Merge "Fix documentation of HistoryPager::lastLink() and make code more readable"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 23 Jul 2014 20:38:32 +0000 (20:38 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 23 Jul 2014 20:38:32 +0000 (20:38 +0000)
714 files changed:
.jscsrc
.travis.yml
CREDITS
RELEASE-NOTES-1.24
StartProfiler.sample
api.php
docs/hooks.txt
docs/scripts.txt
img_auth.php
includes/AutoLoader.php
includes/Block.php
includes/CacheHelper.php [deleted file]
includes/CategoryViewer.php
includes/ChangesFeed.php [deleted file]
includes/Collation.php
includes/DefaultSettings.php
includes/EditPage.php
includes/Export.php
includes/Fallback.php
includes/GitInfo.php
includes/GlobalFunctions.php
includes/Hooks.php
includes/Html.php
includes/HtmlFormatter.php
includes/Import.php
includes/Init.php [deleted file]
includes/Linker.php
includes/MWNamespace.php [new file with mode: 0644]
includes/MediaWiki.php [new file with mode: 0644]
includes/Message.php
includes/MimeMagic.php
includes/Namespace.php [deleted file]
includes/OutputPage.php
includes/PHPVersionError.php
includes/Pager.php
includes/Preferences.php
includes/PrefixSearch.php
includes/ProtectionForm.php
includes/Revision.php
includes/Sanitizer.php
includes/Setup.php
includes/SiteConfiguration.php
includes/Skin.php
includes/SkinTemplate.php
includes/StubObject.php
includes/Title.php
includes/User.php
includes/UserMailer.php
includes/WebStart.php
includes/Wiki.php [deleted file]
includes/actions/Action.php
includes/actions/CachedAction.php
includes/actions/FormAction.php
includes/actions/FormlessAction.php
includes/actions/HistoryAction.php
includes/actions/RawAction.php
includes/actions/RevertAction.php
includes/api/ApiBase.php
includes/api/ApiExpandTemplates.php
includes/api/ApiFormatBase.php
includes/api/ApiImageRotate.php
includes/api/ApiMain.php
includes/api/ApiParse.php
includes/api/ApiPurge.php
includes/api/ApiQuery.php
includes/api/ApiQueryAllUsers.php
includes/api/ApiQueryBase.php
includes/api/ApiQueryDeletedrevs.php
includes/api/ApiQueryFilearchive.php
includes/api/ApiQueryLogEvents.php
includes/api/ApiQueryRecentChanges.php
includes/api/ApiQueryRevisions.php
includes/api/ApiQuerySiteinfo.php
includes/api/ApiQueryUserContributions.php
includes/api/ApiQueryWatchlist.php
includes/api/ApiResult.php
includes/api/ApiSetNotificationTimestamp.php
includes/api/ApiWatch.php
includes/cache/CacheDependency.php
includes/cache/CacheHelper.php [new file with mode: 0644]
includes/cache/LocalisationCache.php
includes/changes/ChangesFeed.php [new file with mode: 0644]
includes/clientpool/RedisConnectionPool.php
includes/config/ConfigException.php
includes/content/ContentHandler.php
includes/context/ContextSource.php
includes/context/DerivativeContext.php
includes/context/RequestContext.php
includes/db/Database.php
includes/db/DatabaseMssql.php
includes/db/DatabasePostgres.php
includes/db/DatabaseSqlite.php
includes/db/LBFactorySingle.php
includes/db/LoadBalancer.php
includes/debug/Debug.php [deleted file]
includes/debug/MWDebug.php [new file with mode: 0644]
includes/deferred/LinksUpdate.php
includes/deferred/ViewCountUpdate.php
includes/diff/DifferenceEngine.php
includes/filebackend/FSFileBackend.php
includes/filebackend/FileBackendStore.php
includes/filebackend/lockmanager/DBLockManager.php
includes/filerepo/FileRepo.php
includes/filerepo/ForeignAPIRepo.php
includes/filerepo/RepoGroup.php
includes/filerepo/file/File.php
includes/filerepo/file/LocalFile.php
includes/gallery/ImageGalleryBase.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormField.php
includes/htmlform/HTMLSelectField.php
includes/installer/CliInstaller.php
includes/installer/DatabaseUpdater.php
includes/installer/Installer.php
includes/installer/LocalSettingsGenerator.php
includes/installer/MssqlInstaller.php
includes/installer/MssqlUpdater.php
includes/installer/MysqlInstaller.php
includes/installer/MysqlUpdater.php
includes/installer/PostgresInstaller.php
includes/installer/PostgresUpdater.php
includes/installer/SqliteUpdater.php
includes/installer/WebInstaller.php
includes/installer/WebInstallerOutput.php
includes/installer/WebInstallerPage.php
includes/installer/i18n/be-tarask.json
includes/installer/i18n/bto.json [new file with mode: 0644]
includes/installer/i18n/ca.json
includes/installer/i18n/ce.json
includes/installer/i18n/cs.json
includes/installer/i18n/de.json
includes/installer/i18n/en.json
includes/installer/i18n/eo.json
includes/installer/i18n/es.json
includes/installer/i18n/fa.json
includes/installer/i18n/fi.json
includes/installer/i18n/fr.json
includes/installer/i18n/gl.json
includes/installer/i18n/haw.json
includes/installer/i18n/he.json
includes/installer/i18n/ia.json
includes/installer/i18n/id.json
includes/installer/i18n/ja.json
includes/installer/i18n/ko.json
includes/installer/i18n/lb.json
includes/installer/i18n/mk.json
includes/installer/i18n/ms.json
includes/installer/i18n/nb.json
includes/installer/i18n/pl.json
includes/installer/i18n/pt-br.json
includes/installer/i18n/pt.json
includes/installer/i18n/qqq.json
includes/installer/i18n/ru.json
includes/installer/i18n/sv.json
includes/installer/i18n/tr.json
includes/installer/i18n/uk.json
includes/installer/i18n/yi.json
includes/installer/i18n/zh-hans.json
includes/installer/i18n/zh-hant.json
includes/jobqueue/Job.php
includes/jobqueue/JobQueueRedis.php
includes/jobqueue/aggregator/JobQueueAggregatorRedis.php
includes/libs/CSSMin.php
includes/libs/HashRing.php
includes/libs/HttpStatus.php
includes/logging/LogEventsList.php
includes/logging/LogPager.php
includes/logging/PatrolLog.php
includes/media/Bitmap.php
includes/media/DjVu.php
includes/media/Exif.php
includes/media/FormatMetadata.php
includes/media/ImageHandler.php
includes/media/Jpeg.php
includes/media/MediaHandler.php
includes/media/PNG.php
includes/media/XCF.php
includes/media/XMP.php
includes/mime.info
includes/mime.types
includes/normal/UtfNormalBench.php
includes/normal/UtfNormalMemStress.php
includes/objectcache/BagOStuff.php
includes/objectcache/MemcachedPeclBagOStuff.php
includes/objectcache/ObjectCache.php
includes/objectcache/SqlBagOStuff.php
includes/page/Article.php
includes/page/ImagePage.php
includes/page/WikiFilePage.php
includes/page/WikiPage.php
includes/parser/CoreParserFunctions.php
includes/parser/LinkHolderArray.php
includes/parser/MWTidy.php [new file with mode: 0644]
includes/parser/Parser.php
includes/parser/ParserOptions.php
includes/parser/Tidy.php [deleted file]
includes/poolcounter/PoolCounterRedis.php
includes/profiler/Profiler.php
includes/resourceloader/DerivativeResourceLoaderContext.php [new file with mode: 0644]
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderContext.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/revisiondelete/RevisionDelete.php
includes/search/SearchMySQL.php
includes/search/SearchResultSet.php
includes/search/SearchSqlite.php
includes/site/MediaWikiSite.php
includes/site/Site.php
includes/site/SiteList.php
includes/site/SiteSQLStore.php
includes/specialpage/ChangesListSpecialPage.php
includes/specialpage/FormSpecialPage.php
includes/specials/SpecialActiveusers.php
includes/specials/SpecialChangePassword.php
includes/specials/SpecialContributions.php
includes/specials/SpecialCreateAccount.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialLinkSearch.php
includes/specials/SpecialListfiles.php
includes/specials/SpecialListusers.php
includes/specials/SpecialMergeHistory.php
includes/specials/SpecialMovepage.php
includes/specials/SpecialPageLanguage.php
includes/specials/SpecialRecentchanges.php
includes/specials/SpecialRevisiondelete.php
includes/specials/SpecialSearch.php
includes/specials/SpecialTrackingCategories.php
includes/specials/SpecialUnblock.php
includes/specials/SpecialUpload.php
includes/specials/SpecialVersion.php
includes/specials/SpecialWantedfiles.php
includes/specials/SpecialWatchlist.php
includes/specials/SpecialWhatlinkshere.php
includes/templates/Userlogin.php
includes/title/MediaWikiTitleCodec.php
includes/upload/UploadBase.php
includes/utils/Cdb.php
includes/utils/CdbPHP.php
includes/utils/IP.php
includes/utils/MWCryptHKDF.php
includes/utils/MWCryptRand.php
includes/utils/MWFunction.php
includes/utils/StringUtils.php
includes/utils/UIDGenerator.php
includes/utils/ZipDirectoryReader.php
index.php
languages/Language.php
languages/Names.php
languages/classes/LanguageRu.php
languages/i18n/ar.json
languages/i18n/arq.json
languages/i18n/arz.json
languages/i18n/ast.json
languages/i18n/az.json
languages/i18n/ba.json
languages/i18n/bar.json
languages/i18n/bcc.json
languages/i18n/bcl.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bho.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/ce.json
languages/i18n/ckb.json
languages/i18n/cs.json
languages/i18n/cy.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/diq.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/fa.json
languages/i18n/fi.json
languages/i18n/fo.json
languages/i18n/fr.json
languages/i18n/frr.json
languages/i18n/gan-hans.json
languages/i18n/gd.json
languages/i18n/gl.json
languages/i18n/gsw.json
languages/i18n/he.json
languages/i18n/hi.json
languages/i18n/hr.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/id.json
languages/i18n/ilo.json
languages/i18n/is.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/kiu.json
languages/i18n/kk-cyrl.json
languages/i18n/ko.json
languages/i18n/ksh.json
languages/i18n/ku-latn.json
languages/i18n/lb.json
languages/i18n/lrc.json
languages/i18n/lv.json
languages/i18n/lzz.json
languages/i18n/mg.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/ms.json
languages/i18n/mt.json
languages/i18n/mzn.json
languages/i18n/nan.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/nds-nl.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/oc.json
languages/i18n/pa.json
languages/i18n/pl.json
languages/i18n/pms.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/qu.json
languages/i18n/ro.json
languages/i18n/ru.json
languages/i18n/scn.json
languages/i18n/sl.json
languages/i18n/sq.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/i18n/th.json
languages/i18n/tr.json
languages/i18n/tt-cyrl.json
languages/i18n/uk.json
languages/i18n/vi.json
languages/i18n/wuu.json
languages/i18n/yi.json
languages/i18n/yo.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/messages/MessagesCrh_cyrl.php
languages/messages/MessagesCrh_latn.php
languages/messages/MessagesCs.php
languages/messages/MessagesDsb.php
languages/messages/MessagesEn.php
languages/messages/MessagesFa.php
languages/messages/MessagesFrp.php
languages/messages/MessagesHsb.php
languages/messages/MessagesKk_arab.php
languages/messages/MessagesKk_cyrl.php
languages/messages/MessagesKk_latn.php
languages/messages/MessagesKsh.php
languages/messages/MessagesLzh.php
languages/messages/MessagesNds_nl.php
languages/messages/MessagesOs.php
languages/messages/MessagesSr_ec.php
languages/messages/MessagesSv.php
languages/messages/MessagesTt_cyrl.php
languages/messages/MessagesTt_latn.php
load.php
maintenance/README
maintenance/archives/patch-il_from_namespace.sql [new file with mode: 0644]
maintenance/archives/patch-pl_from_namespace.sql [new file with mode: 0644]
maintenance/archives/patch-tl_from_namespace.sql [new file with mode: 0644]
maintenance/benchmarks/benchmarkParse.php
maintenance/compareParserCache.php
maintenance/convertLinks.php
maintenance/dictionary/mediawiki.dic
maintenance/doMaintenance.php
maintenance/edit.php
maintenance/eraseArchivedFile.php
maintenance/fixDoubleRedirects.php
maintenance/importDump.php
maintenance/importTextFile.php [deleted file]
maintenance/install.php
maintenance/language/generateCollationData.php
maintenance/mctest.php
maintenance/nextJobDB.php [deleted file]
maintenance/populateBacklinkNamespace.php [new file with mode: 0644]
maintenance/postgres/tables.sql
maintenance/purgeChangedPages.php
maintenance/resources/update-oojs-ui.sh
maintenance/resources/update-oojs.sh
maintenance/runJobs.php
maintenance/tables.sql
maintenance/update.php
mw-config/index.php
resources/Resources.php
resources/lib/es5-shim/es5-shim.js
resources/lib/jquery/jquery.cookie.js
resources/lib/oojs-ui/i18n/ar.json
resources/lib/oojs-ui/i18n/ast.json
resources/lib/oojs-ui/i18n/ca.json
resources/lib/oojs-ui/i18n/cs.json
resources/lib/oojs-ui/i18n/de.json
resources/lib/oojs-ui/i18n/en.json
resources/lib/oojs-ui/i18n/es.json
resources/lib/oojs-ui/i18n/et.json
resources/lib/oojs-ui/i18n/fa.json
resources/lib/oojs-ui/i18n/fi.json
resources/lib/oojs-ui/i18n/fr.json
resources/lib/oojs-ui/i18n/gd.json [new file with mode: 0644]
resources/lib/oojs-ui/i18n/gl.json
resources/lib/oojs-ui/i18n/he.json
resources/lib/oojs-ui/i18n/hu.json
resources/lib/oojs-ui/i18n/ia.json
resources/lib/oojs-ui/i18n/ilo.json
resources/lib/oojs-ui/i18n/it.json
resources/lib/oojs-ui/i18n/lb.json
resources/lib/oojs-ui/i18n/lv.json
resources/lib/oojs-ui/i18n/mk.json
resources/lib/oojs-ui/i18n/om.json
resources/lib/oojs-ui/i18n/pl.json
resources/lib/oojs-ui/i18n/pt.json
resources/lib/oojs-ui/i18n/qqq.json
resources/lib/oojs-ui/i18n/ro.json
resources/lib/oojs-ui/i18n/ru.json
resources/lib/oojs-ui/i18n/sq.json
resources/lib/oojs-ui/i18n/sr-ec.json
resources/lib/oojs-ui/i18n/sv.json
resources/lib/oojs-ui/i18n/uk.json
resources/lib/oojs-ui/i18n/vi.json
resources/lib/oojs-ui/i18n/yi.json
resources/lib/oojs-ui/i18n/zh-hans.json
resources/lib/oojs-ui/i18n/zh-hant.json
resources/lib/oojs-ui/images/anchor.svg [new file with mode: 0644]
resources/lib/oojs-ui/images/icons/accept.svg
resources/lib/oojs-ui/images/icons/add-item.svg
resources/lib/oojs-ui/images/icons/advanced.svg
resources/lib/oojs-ui/images/icons/alert.svg
resources/lib/oojs-ui/images/icons/arched-arrow-ltr.svg
resources/lib/oojs-ui/images/icons/arched-arrow-rtl.svg
resources/lib/oojs-ui/images/icons/check.svg
resources/lib/oojs-ui/images/icons/clear.svg
resources/lib/oojs-ui/images/icons/close.svg
resources/lib/oojs-ui/images/icons/code.svg
resources/lib/oojs-ui/images/icons/collapse.svg
resources/lib/oojs-ui/images/icons/comment.svg
resources/lib/oojs-ui/images/icons/expand.svg
resources/lib/oojs-ui/images/icons/help.svg
resources/lib/oojs-ui/images/icons/history.svg
resources/lib/oojs-ui/images/icons/info.svg
resources/lib/oojs-ui/images/icons/link.svg
resources/lib/oojs-ui/images/icons/menu.svg
resources/lib/oojs-ui/images/icons/move-ltr.svg
resources/lib/oojs-ui/images/icons/move-rtl.svg
resources/lib/oojs-ui/images/icons/picture.svg
resources/lib/oojs-ui/images/icons/remove-item.svg
resources/lib/oojs-ui/images/icons/remove.svg
resources/lib/oojs-ui/images/icons/search.svg
resources/lib/oojs-ui/images/icons/settings.svg
resources/lib/oojs-ui/images/icons/tag.svg
resources/lib/oojs-ui/images/icons/window.svg
resources/lib/oojs-ui/images/indicators/alert.svg
resources/lib/oojs-ui/images/indicators/arrow-down.svg
resources/lib/oojs-ui/images/indicators/arrow-ltr.svg
resources/lib/oojs-ui/images/indicators/arrow-rtl.svg
resources/lib/oojs-ui/images/indicators/arrow-up.svg
resources/lib/oojs-ui/images/indicators/required.svg
resources/lib/oojs-ui/images/tail.svg [deleted file]
resources/lib/oojs-ui/oojs-ui-agora.css
resources/lib/oojs-ui/oojs-ui-agora.rtl.css [new file with mode: 0644]
resources/lib/oojs-ui/oojs-ui-apex.css
resources/lib/oojs-ui/oojs-ui-apex.rtl.css [new file with mode: 0644]
resources/lib/oojs-ui/oojs-ui.js
resources/lib/oojs-ui/oojs-ui.rtl.css [new file with mode: 0644]
resources/lib/oojs-ui/oojs-ui.svg.css
resources/lib/oojs-ui/oojs-ui.svg.rtl.css [new file with mode: 0644]
resources/lib/sinonjs/sinon-1.10.3.js [new file with mode: 0644]
resources/lib/sinonjs/sinon-1.9.0.js [deleted file]
resources/lib/sinonjs/sinon-ie-1.10.3.js [new file with mode: 0644]
resources/lib/sinonjs/sinon-ie-1.9.0.js [deleted file]
resources/src/es5-skip.js
resources/src/jquery.json-deprecate.js
resources/src/jquery.ui-themes/vector/images/ui-bg_flat_15_cd0a0a_40x100.png
resources/src/jquery.ui-themes/vector/images/ui-bg_flat_70_000000_40x100.png
resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png
resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-hard_80_d7ebf9_1x100.png
resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_100_e4f1fb_1x100.png
resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_100_ffffff_1x100.png
resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_25_ffef8f_1x100.png
resources/src/jquery.ui-themes/vector/images/ui-bg_inset-hard_100_f0f0f0_1x100.png
resources/src/jquery.ui-themes/vector/images/ui-icons_2694e8_256x240.png
resources/src/jquery.ui-themes/vector/images/ui-icons_2e83ff_256x240.png
resources/src/jquery.ui-themes/vector/images/ui-icons_3d80b3_256x240.png
resources/src/jquery.ui-themes/vector/images/ui-icons_666666_256x240.png
resources/src/jquery.ui-themes/vector/images/ui-icons_72a7cf_256x240.png
resources/src/jquery.ui-themes/vector/images/ui-icons_ffffff_256x240.png
resources/src/jquery.ui-themes/vector/jquery.ui.accordion.css
resources/src/jquery.ui-themes/vector/jquery.ui.autocomplete.css
resources/src/jquery.ui-themes/vector/jquery.ui.button.css
resources/src/jquery.ui-themes/vector/jquery.ui.core.css
resources/src/jquery.ui-themes/vector/jquery.ui.datepicker.css
resources/src/jquery.ui-themes/vector/jquery.ui.dialog.css
resources/src/jquery.ui-themes/vector/jquery.ui.menu.css [new file with mode: 0644]
resources/src/jquery.ui-themes/vector/jquery.ui.progressbar.css
resources/src/jquery.ui-themes/vector/jquery.ui.resizable.css
resources/src/jquery.ui-themes/vector/jquery.ui.selectable.css
resources/src/jquery.ui-themes/vector/jquery.ui.slider.css
resources/src/jquery.ui-themes/vector/jquery.ui.spinner.css [new file with mode: 0644]
resources/src/jquery.ui-themes/vector/jquery.ui.tabs.css
resources/src/jquery.ui-themes/vector/jquery.ui.theme.css
resources/src/jquery.ui-themes/vector/jquery.ui.tooltip.css [new file with mode: 0644]
resources/src/jquery/jquery.accessKeyLabel.js
resources/src/jquery/jquery.arrowSteps.js
resources/src/jquery/jquery.colorUtil.js
resources/src/jquery/jquery.makeCollapsible.js
resources/src/jquery/jquery.textSelection.js
resources/src/mediawiki.api/mediawiki.api.edit.js
resources/src/mediawiki.hidpi-skip.js [new file with mode: 0644]
resources/src/mediawiki.language/languages/la.js
resources/src/mediawiki.language/languages/ru.js
resources/src/mediawiki.less/mediawiki.mixins.less
resources/src/mediawiki.less/mediawiki.ui/mixins.less [new file with mode: 0644]
resources/src/mediawiki.less/mediawiki.ui/variables.less [new file with mode: 0644]
resources/src/mediawiki.page/mediawiki.page.gallery.js
resources/src/mediawiki.page/mediawiki.page.ready.js
resources/src/mediawiki.page/mediawiki.page.watch.ajax.js
resources/src/mediawiki.skinning/content.parsoid.less
resources/src/mediawiki.special/mediawiki.special.block.css
resources/src/mediawiki.special/mediawiki.special.css
resources/src/mediawiki.special/mediawiki.special.search.css
resources/src/mediawiki.ui/components/buttons.less [new file with mode: 0644]
resources/src/mediawiki.ui/components/default/buttons.less [deleted file]
resources/src/mediawiki.ui/components/default/forms.less [deleted file]
resources/src/mediawiki.ui/components/forms.less [new file with mode: 0644]
resources/src/mediawiki.ui/components/utilities.less
resources/src/mediawiki.ui/components/vector/buttons.less [deleted file]
resources/src/mediawiki.ui/components/vector/containers.less [deleted file]
resources/src/mediawiki.ui/components/vector/forms.less [deleted file]
resources/src/mediawiki.ui/default.less
resources/src/mediawiki.ui/mixins/effects.less [deleted file]
resources/src/mediawiki.ui/mixins/forms.less [deleted file]
resources/src/mediawiki.ui/mixins/type.less [deleted file]
resources/src/mediawiki.ui/mixins/utilities.less [deleted file]
resources/src/mediawiki.ui/settings/colors.less [deleted file]
resources/src/mediawiki.ui/settings/typography.less [deleted file]
resources/src/mediawiki.ui/vector.less [deleted file]
resources/src/mediawiki/mediawiki.feedback.js
resources/src/mediawiki/mediawiki.htmlform.js
resources/src/mediawiki/mediawiki.js
resources/src/mediawiki/mediawiki.user.js
skins/MonoBook/i18n/ast.json
skins/MonoBook/i18n/be.json
skins/MonoBook/i18n/ca.json
skins/MonoBook/i18n/da.json
skins/MonoBook/i18n/es.json
skins/MonoBook/i18n/fa.json
skins/MonoBook/i18n/gl.json
skins/MonoBook/i18n/hi.json
skins/MonoBook/i18n/id.json
skins/MonoBook/i18n/ilo.json [new file with mode: 0644]
skins/MonoBook/i18n/lb.json
skins/MonoBook/i18n/ms.json
skins/MonoBook/i18n/nl.json
skins/MonoBook/i18n/pl.json
skins/MonoBook/i18n/pt.json
skins/MonoBook/i18n/ru.json
skins/MonoBook/i18n/uk.json
skins/MonoBook/i18n/zh-hant.json
skins/Vector/VectorTemplate.php
skins/Vector/components/common.less
skins/Vector/components/notifications.less
skins/Vector/components/tabs.less
skins/Vector/i18n/ase.json
skins/Vector/i18n/ast.json
skins/Vector/i18n/be.json
skins/Vector/i18n/ca.json
skins/Vector/i18n/ce.json
skins/Vector/i18n/cy.json
skins/Vector/i18n/da.json
skins/Vector/i18n/es.json
skins/Vector/i18n/eu.json
skins/Vector/i18n/fa.json
skins/Vector/i18n/frr.json
skins/Vector/i18n/gl.json
skins/Vector/i18n/hi.json
skins/Vector/i18n/id.json
skins/Vector/i18n/ilo.json
skins/Vector/i18n/kk-cyrl.json
skins/Vector/i18n/lb.json
skins/Vector/i18n/lrc.json
skins/Vector/i18n/lv.json
skins/Vector/i18n/ms.json
skins/Vector/i18n/mt.json
skins/Vector/i18n/nb.json
skins/Vector/i18n/nl.json
skins/Vector/i18n/pl.json
skins/Vector/i18n/uk.json
skins/Vector/i18n/zh-hant.json
skins/common/config.css
skins/common/images/icons/fileicon-xcf.png [new file with mode: 0644]
skins/common/images/tipsy-arrow.gif [deleted file]
skins/common/shared.css
skins/common/wikibits.js
tests/browser/Gemfile
tests/browser/Gemfile.lock
tests/browser/features/create_and_follow_wiki_link.feature
tests/browser/features/edit_page.feature
tests/browser/features/file.feature [new file with mode: 0644]
tests/browser/features/login.feature [new file with mode: 0644]
tests/browser/features/step_definitions/edit_page_steps.rb
tests/browser/features/step_definitions/file_steps.rb [new file with mode: 0644]
tests/browser/features/step_definitions/login_steps.rb [new file with mode: 0644]
tests/browser/features/support/env.rb
tests/browser/features/support/pages/edit_page.rb
tests/browser/features/support/pages/file_does_not_exist_page.rb [new file with mode: 0644]
tests/browser/features/support/pages/login_error_page.rb [new file with mode: 0644]
tests/frontend/Gruntfile.js
tests/frontend/package.json
tests/parser/parserTest.inc
tests/parser/parserTests.txt
tests/phpunit/LessFileCompilationTest.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/ResourceLoaderTestCase.php
tests/phpunit/data/media/README
tests/phpunit/data/media/say-test.ogg [new file with mode: 0644]
tests/phpunit/includes/ArrayUtilsTest.php
tests/phpunit/includes/EditPageTest.php
tests/phpunit/includes/GitInfoTest.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php
tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php
tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php
tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php
tests/phpunit/includes/GlobalFunctions/wfBaseConvertTest.php
tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php
tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php
tests/phpunit/includes/GlobalFunctions/wfGetCallerTest.php
tests/phpunit/includes/GlobalFunctions/wfParseUrlTest.php
tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php
tests/phpunit/includes/GlobalFunctions/wfShellExecTest.php [new file with mode: 0644]
tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php
tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
tests/phpunit/includes/HtmlFormatterTest.php
tests/phpunit/includes/HtmlTest.php
tests/phpunit/includes/ImagePage404Test.php [new file with mode: 0644]
tests/phpunit/includes/ImagePageTest.php [new file with mode: 0644]
tests/phpunit/includes/ImportTest.php
tests/phpunit/includes/LinkerTest.php
tests/phpunit/includes/LinksUpdateTest.php
tests/phpunit/includes/MWNamespaceTest.php
tests/phpunit/includes/MimeMagicTest.php [new file with mode: 0644]
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/SampleTest.php
tests/phpunit/includes/SanitizerValidateEmailTest.php
tests/phpunit/includes/StatusTest.php
tests/phpunit/includes/TimeAdjustTest.php
tests/phpunit/includes/TitlePermissionTest.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/UserTest.php
tests/phpunit/includes/WebRequestTest.php
tests/phpunit/includes/WikiPageTest.php
tests/phpunit/includes/actions/ActionTest.php [new file with mode: 0644]
tests/phpunit/includes/api/ApiOptionsTest.php
tests/phpunit/includes/api/query/ApiQueryTest.php
tests/phpunit/includes/config/ConfigFactoryTest.php
tests/phpunit/includes/content/TextContentTest.php
tests/phpunit/includes/db/DatabaseSqliteTest.php
tests/phpunit/includes/debug/MWDebugTest.php
tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
tests/phpunit/includes/filerepo/RepoGroupTest.php [new file with mode: 0644]
tests/phpunit/includes/filerepo/file/FileTest.php [new file with mode: 0644]
tests/phpunit/includes/filerepo/files/FileTest.php [deleted file]
tests/phpunit/includes/libs/MWMessagePackTest.php
tests/phpunit/includes/media/BitmapMetadataHandlerTest.php
tests/phpunit/includes/media/BitmapScalingTest.php
tests/phpunit/includes/media/DjVuTest.php
tests/phpunit/includes/media/ExifBitmapTest.php
tests/phpunit/includes/media/ExifRotationTest.php
tests/phpunit/includes/media/ExifTest.php
tests/phpunit/includes/media/FakeDimensionFile.php
tests/phpunit/includes/media/FormatMetadataTest.php
tests/phpunit/includes/media/GIFMetadataExtractorTest.php
tests/phpunit/includes/media/GIFTest.php
tests/phpunit/includes/media/IPTCTest.php
tests/phpunit/includes/media/JpegMetadataExtractorTest.php
tests/phpunit/includes/media/JpegTest.php
tests/phpunit/includes/media/MediaHandlerTest.php
tests/phpunit/includes/media/MediaWikiMediaTestCase.php
tests/phpunit/includes/media/PNGMetadataExtractorTest.php
tests/phpunit/includes/media/PNGTest.php
tests/phpunit/includes/media/SVGMetadataExtractorTest.php
tests/phpunit/includes/media/SVGTest.php
tests/phpunit/includes/media/TiffTest.php
tests/phpunit/includes/media/XCFTest.php [new file with mode: 0644]
tests/phpunit/includes/media/XMPTest.php
tests/phpunit/includes/media/XMPValidateTest.php
tests/phpunit/includes/normal/CleanUpTest.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/includes/parser/ParserMethodsTest.php
tests/phpunit/includes/poolcounter/PoolCounterTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
tests/phpunit/includes/site/MediaWikiSiteTest.php
tests/phpunit/includes/specials/SpecialSearchTest.php
tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php
tests/phpunit/includes/title/MediaWikiTitleCodecTest.php
tests/phpunit/languages/LanguageRuTest.php
tests/phpunit/languages/LanguageTest.php
tests/phpunit/maintenance/getSlaveServerTest.php [deleted file]
tests/phpunit/phpunit.php
tests/phpunit/structure/AutoLoaderTest.php
tests/phpunit/suites/UploadFromUrlTestSuite.php
tests/qunit/QUnitTestResources.php
tests/qunit/data/testrunner.js
tests/qunit/suites/resources/jquery/jquery.client.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js
tests/testHelpers.inc
thumb.php

diff --git a/.jscsrc b/.jscsrc
index 0da9aa5..b9139b2 100644 (file)
--- a/.jscsrc
+++ b/.jscsrc
@@ -1,94 +1,10 @@
 {
-    "requireCurlyBraces": [
-        "if",
-        "else",
-        "for",
-        "while",
-        "do",
-        "try",
-        "catch"
-    ],
-    "requireSpaceAfterKeywords": [
-        "if",
-        "else",
-        "for",
-        "while",
-        "do",
-        "switch",
-        "return",
-        "try",
-        "catch",
-        "function"
-    ],
-    "requireSpaceBeforeBlockStatements": true,
-    "requireParenthesesAroundIIFE": true,
-    "requireSpacesInConditionalExpression": true,
-    "disallowSpacesInNamedFunctionExpression": {
-        "beforeOpeningRoundBrace": true
-    },
-    "disallowSpacesInFunctionDeclaration": {
-        "beforeOpeningRoundBrace": true
-    },
-    "requireMultipleVarDecl": "onevar",
-    "requireBlocksOnNewline": 1,
-    "disallowEmptyBlocks": true,
-    "requireSpacesInsideObjectBrackets": "all",
-    "disallowSpaceAfterObjectKeys": true,
-    "requireCommaBeforeLineBreak": true,
-    "disallowSpaceAfterPrefixUnaryOperators": [
-        "++",
-        "--",
-        "+",
-        "-",
-        "~",
-        "!"
-    ],
-    "disallowSpaceBeforePostfixUnaryOperators": [
-        "++",
-        "--"
-    ],
-    "disallowSpaceBeforeBinaryOperators": [
-        ","
-    ],
-    "requireSpaceBeforeBinaryOperators": [
-        "=",
-        "+",
-        "-",
-        "/",
-        "*",
-        "==",
-        "===",
-        "!=",
-        "!==",
-        ">",
-        ">=",
-        "<",
-        "<="
-    ],
-    "requireSpaceAfterBinaryOperators": [
-        "=",
-        "+",
-        "-",
-        "/",
-        "*",
-        "==",
-        "===",
-        "!=",
-        "!==",
-        ">",
-        ">=",
-        "<",
-        "<="
-    ],
-    "disallowKeywords": [ "with" ],
-    "disallowMultipleLineBreaks": true,
-    "validateLineBreaks": "LF",
-    "validateQuoteMarks": "'",
-    "disallowMixedSpacesAndTabs": true,
-    "disallowTrailingWhitespace": true,
-    "disallowTrailingComma": true,
-    "requireLineFeedAtFileEnd": true,
-    "requireCapitalizedConstructors": true,
-    "requireDotNotation": true,
-    "disallowYodaConditions": true
+       "preset": "wikimedia",
+
+       "disallowDanglingUnderscores": null,
+       "disallowKeywordsOnNewLine": null,
+       "disallowQuotedKeysInObjects": null,
+       "requireCamelCaseOrUpperCaseIdentifiers": null,
+       "requireSpacesInsideArrayBrackets": null,
+       "validateIndentation": null
 }
index 64075f1..dedb4e1 100644 (file)
@@ -38,6 +38,7 @@ script:
   - php tests/phpunit/phpunit.php
 
 notifications:
+  email: false
   irc:
     channels:
       - "chat.freenode.net#mediawiki-core"
diff --git a/CREDITS b/CREDITS
index cf222a0..fde6b78 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -157,6 +157,7 @@ following names for their contribution to the product.
 * Kim Hyun-Joon
 * Lee Worden
 * Lejonel
+* Leon Liesener
 * liangent
 * Louperivois
 * Lucas Garczewski
index 73ba1c2..6d13c91 100644 (file)
@@ -1,5 +1,5 @@
-Security reminder: MediaWiki does not require PHP's register_globals. If you
-have it on, turn it '''off''' if you can.
+Security reminder: If you have PHP's register_globals option set, you must
+turn it off. MediaWiki will no longer work with it enabled.
 
 == MediaWiki 1.24 ==
 
@@ -9,6 +9,12 @@ MediaWiki 1.24 is an alpha-quality branch and is not recommended for use in
 production.
 
 === Configuration changes in 1.24 ===
+* MediaWiki will no longer run if register_globals is enabled. It has been
+  deprecated for 5 years now, and was removed in PHP 5.4. For more information
+  about why, see <https://www.mediawiki.org/wiki/register_globals>.
+* MediaWiki now requires PHP's iconv extension. openSUSE users may need to
+  install the php5-iconv package. Users of other systems may need to add
+  extension=iconv.so to php.ini or recompile PHP without --without-iconv.
 * The server's canonical hostname is available as $wgServerName, which is
   exposed in both mw.config and ApiQuerySiteInfo.
 * Introduced $wgPagePropsHaveSortkey as a backwards-compatibility switch,
@@ -26,6 +32,14 @@ production.
   prefixes (i.e. turned into interlanguage links when $wgInterwikiMagic is set
   to true).
 * $wgParserTestRemote has been removed.
+* $wgCountTotalSearchHits has been removed. If you're concerned about efficiency
+  of search, you should use something like CirrusSearch instead of built in
+  search.
+* Users in the 'sysop' group have access to Special:MergeHistory by default.
+* $wgFileStore was removed after having been deprecated in 1.17. Alternative
+  configurations are $wgDeletedDirectory and $wgHashedUploadDirectory.
+* The deprecated $wgUseCommaCount variable has been removed.
+* $wgEnableSorbs and $wgSorbsUrl have been removed.
 
 === New features in 1.24 ===
 * Added a new hook, "WhatLinksHereProps", to allow extensions to annotate
@@ -101,6 +115,20 @@ production.
   The feature needs to be enabled with $wgPageLanguageUseDB=true and
   permission needs to be set for 'pagelang'.
 * Upgrade Moment.js to v2.7.0.
+* (bug 67042) Added support for the HTML5 <rtc> tag for East Asian typography.
+* Upgrade Sinon.JS to 1.10.3.
+* Added the es5-shim polyfill for older or non-compliant javascript engines.
+* Upgrade jQuery Cookie to v1.2.0.
+* (bug 20476) Add a "viewsuppressed" user right to be able to view
+  suppressed content but not suppress it ("suppressrevision" right).
+* Added a new hook, "OutputPageScriptsForBottomQueue", to add modules to the
+  bottom queue that should be requested in a dedicated <script> request.
+* (bug 66440) The MediaWiki web installer will now allow you to choose the skins
+  to enable (from the ones included in download tarball) and decide which one
+  should be the default.
+* (bug 68085) Links of the form [[localInterwikiPrefix:languageCode:pageTitle]],
+  where localInterwikiPrefix is a member of the $wgLocalInterwikis array, will
+  no longer be displayed in the sidebar when $wgInterwikiMagic is true.
 
 === Bug fixes in 1.24 ===
 * (bug 49116) Footer copyright notice is now always displayed in user language
@@ -127,6 +155,7 @@ production.
 * (bug 65757) MSSQL: Update script drops unnamed constraints to be prepared
   for future updates. Because it's doing so heuristically, it may fail or drop
   wrong constraints.
+* (bug 67870) wfShellExec() cuts off stdout at multiples of 8192 bytes.
 
 === Web API changes in 1.24 ===
 * action=parse API now supports prop=modules, which provides the list of
@@ -148,6 +177,11 @@ production.
 * meta=userinfo can now return the count of unread pages on the watchlist.
 * list=watchlist can now filter by unread status.
 * The deprecated action=parse&prop=languageshtml has been removed.
+* (bug 48071) action=setnotificationtimestamp no longer throws PHP or database
+  errors when no pages are given.
+* (bug 60734) Actions that use ApiPageSet (e.g. purge, watch,
+  setnotificationtimestamp) will now include continuation information when
+  using a generator.
 
 === Languages updated in 1.24 ===
 
@@ -205,6 +239,36 @@ changes to languages because of Bugzilla reports.
   set of hooks has been removed and replaced by a single new hook
   SpecialPageBeforeFormDisplay.
 * (bug 65781) Removed block warning on included {{Special:Contributions}}
+* Removed Skin::makeGlobalVariablesScript. (deprecated since 1.19)
+* Removed MWNamespace::isMain(). (deprecated since 1.19)
+* Removed Preferences::loadOldSearchNs(). (deprecated since 1.19)
+* Removed OutputPage::getStatusMessage(). (deprecated since 1.18)
+* Removed OutputPage::isUserJsAllowed(). (deprecated since 1.18)
+* Removed Title::updateTitleProtection(). (deprecated since 1.19)
+* Removed ParserOptions::setSkin(). (deprecated since 1.19)
+* Removed Title::escapeCanonicalURL(). (deprecated since 1.19)
+* Removed Title::escapeLocalURL(). (deprecated since 1.19)
+* Removed Title::escapeFullURL(). (deprecated since 1.19)
+* Removed User::isValidEmailAddr(). (deprecated since 1.18)
+* Removed Title::getEscapedText(). (deprecated since 1.19)
+* Removed Language::getFallbackLanguageCode(). (deprecated since 1.19)
+* Removed WikiPage::isBigDeletion(). (deprecated since 1.19)
+* Removed MWInit class which contained functions related to a now discontinued
+  PHP compiler called hphpc. (deprecated since 1.22)
+* ApiResult::enableSizeCheck() and disableSizeCheck() are now obsolete.
+* Removed ResourceLoaderGetStartupModules hook. (deprecated since 1.23)
+* Removed getFormFields(), onSubmit() and onSuccess() from FormlessAction, as
+  these were meant specifically for FormAction instead.
+* Removed Action::execute().
+* Removed AjaxAddScript which has been obsolete since ResourceLoader and
+  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 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,
+  and filelinks tables. Run update.php to apply this change to the schema.
 
 ==== Renamed classes ====
 * CLDRPluralRuleConverter_Expression to CLDRPluralRuleConverterExpression
@@ -247,6 +311,11 @@ changes to languages because of Bugzilla reports.
 ==== Removed classes ====
 * IPBlockForm - Use SpecialBlock directly
 * WatchlistEditor - Use SpecialEditWatchlist directly
+* FormatExif - Use FormatMetadata directly
+* RevertFileAction - Use RevertAction directly
+* HistoryPage - Use HistoryAction directly
+* RawPage - Use RawAction directly
+* StubContLang - Use Language::factory() instead
 
 == Compatibility ==
 
index db5e0ff..d9b5288 100644 (file)
@@ -2,13 +2,22 @@
 
 /**
  * To use a profiler, copy this file to StartProfiler.php,
- * and add something like this:
+ * and add either:
  *
- *   $wgProfiler['class'] = 'Profiler';
+ *   // Does not support the debugging toolbar
+ *   // Stores profiling information in the database
+ *   // Requires running maintenance/archives/patch-profiling.sql
+ *   $wgProfiler['class'] = 'ProfilerSimpleDB'
+ *
+ * or:
+ *
+ *   // Supports the debugging toolbar
+ *   // Does not store profiling information in the database
+ *   $wgProfiler['class'] = 'ProfilerStandard';
  *
  * Or for a sampling profiler:
  *   if ( !mt_rand( 0, 100 ) ) {
- *       $wgProfiler['class'] = 'Profiler';
+ *       $wgProfiler['class'] = 'ProfilerSimpleDB';
  *   } else {
  *       $wgProfiler['class'] = 'ProfilerStub';
  *   }
diff --git a/api.php b/api.php
index e55ec75..80abc35 100644 (file)
--- a/api.php
+++ b/api.php
@@ -34,7 +34,7 @@
 define( 'MW_API', true );
 
 // Bail if PHP is too low
-if ( !function_exists( 'version_compare' ) || version_compare( phpversion(), '5.3.2' ) < 0 ) {
+if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.3.2' ) < 0 ) {
        // We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+
        require dirname( __FILE__ ) . '/includes/PHPVersionError.php';
        wfPHPVersionError( 'api.php' );
@@ -104,7 +104,7 @@ if ( $wgAPIRequestLog ) {
                wfTimestamp( TS_MW ),
                $endtime - $starttime,
                $wgRequest->getIP(),
-               $_SERVER['HTTP_USER_AGENT']
+               $wgRequest->getHeader( 'User-agent' )
        );
        $items[] = $wgRequest->wasPosted() ? 'POST' : 'GET';
        if ( $processor ) {
index 1673f06..3ee1221 100644 (file)
@@ -326,10 +326,12 @@ $revCount: Number of revisions in the XML file
 $sRevCount: Number of successfully imported revisions
 $pageInfo: associative array of page information
 
-'AjaxAddScript': Called in output page just before the initialisation
-of the javascript ajax engine. The hook is only called when ajax
-is enabled ( $wgUseAjax = true; ).
-&$output: OutputPage object
+'AfterParserFetchFileAndTitle': After an image gallery is formed by Parser,
+just before adding its HTML to parser output.
+$parser: Parser object that called the hook
+$ig: Gallery, an object of one of the gallery classes (inheriting from
+ImageGalleryBase)
+$html: HTML generated by the gallery
 
 'AlternateEdit': Before checking if a user can edit a page and before showing
 the edit form ( EditPage::edit() ). This is triggered on &action=edit.
@@ -1705,8 +1707,8 @@ $refreshLinks: RefreshLinks object
 'MagicWordwgVariableIDs': When defining new magic words IDs.
 $variableIDs: array of strings
 
-'MakeGlobalVariablesScript': Called right before Skin::makeVariablesScript is
-executed. Ideally, this hook should only be used to add variables that depend on
+'MakeGlobalVariablesScript': Called at end of OutputPage::getJSVars.
+Ideally, this hook should only be used to add variables that depend on
 the current page/request; static configuration should be added through
 ResourceLoaderGetConfigVars instead.
 &$vars: variable (or multiple variables) to be added into the output of
@@ -1750,6 +1752,30 @@ caches.
 $title: name of the page changed.
 $text: new contents of the page.
 
+'MimeMagicInit': Before processing the list mapping MIME types to media types
+and the list mapping MIME types to file extensions.
+As an extension author, you are encouraged to submit patches to MediaWiki's
+core to add new MIME types to mime.types.
+$mimeMagic: Instance of MimeMagic.
+  Use $mimeMagic->addExtraInfo( $stringOfInfo );
+  for adding new MIME info to the list.
+  Use $mimeMagic->addExtraTypes( $stringOfTypes );
+  for adding new MIME types to the list.
+
+'MimeMagicImproveFromExtension': Allows MW extensions to further improve the
+MIME type detected by considering the file extension.
+$mimeMagic: Instance of MimeMagic.
+$ext: File extension.
+&$mime: MIME type (in/out).
+
+'MimeMagicGuessFromContent': Allows MW extensions guess the MIME by content.
+$mimeMagic: Instance of MimeMagic.
+&$head: First 1024 bytes of the file in a string (in - Do not alter!).
+&$tail: More or equal than last 65558 bytes of the file in a string
+  (in - Do not alter!).
+$file: File path.
+&$mime: MIME type (out).
+
 'ModifyExportQuery': Modify the query used by the exporter.
 $db: The database object to be queried.
 &$tables: Tables in the query.
@@ -1845,6 +1871,14 @@ $categories: associative array, keys are category names, values are category
 $links: array, intended to hold the result. Must be an associative array with
   category types as keys and arrays of HTML links as values.
 
+'OutputPageScriptsForBottomQueue': Allows adding modules to the bottom queue
+that should be requested in a dedicated <script> request. In most cases you'll
+want to use OutputPage::addModules instead (from another hook) which allows
+ResourceLoader to better combine requests and allows the module load requests
+to be cached better. Typically you'd only use this for user-specific modules.
+$out: OutputPage instance
+&$modules: Array of modules names to add to the bottom queue
+
 'PageContentInsertComplete': After a new article is created.
 $wikiPage: WikiPage created
 $user: User creating the article
@@ -2127,12 +2161,6 @@ configuration variables to JavaScript. Things that depend on the current page
 or request state must be added through MakeGlobalVariablesScript instead.
 &$vars: array( variable name => value )
 
-'ResourceLoaderGetStartupModules': DEPRECATED. Run once the startup module is being
-generated. This allows you to add modules to the startup module. This hook
-should be used sparingly since any module added here will be loaded on all
-pages. This hook is useful if you want to make code available to module loader
-scripts.
-
 'ResourceLoaderRegisterModules': Right before modules information is required,
 such as when responding to a resource
 loader request or generating HTML output.
@@ -2889,6 +2917,15 @@ to be switched to HTTPS.
 $user: User in question.
 &$https: Boolean whether $user should be switched to HTTPS.
 
+'UserResetAllOptions': Called in User::resetOptions() when user preferences
+have been requested to be reset. This hook can be used to exclude certain
+options from being reset even when the user has requested all prefs to be reset,
+because certain options might be stored in the user_properties database table
+despite not being visible and editable via Special:Preferences.
+$user: the User (object) whose preferences are being reset
+&$newOptions: array of new (site default) preferences
+$options: array of the user's old preferences
+$resetKinds: array containing the kinds of preferences to reset
 
 'UserRetrieveNewTalks': Called when retrieving "You have new messages!"
 message(s).
@@ -2929,6 +2966,11 @@ invalidated and GetExtendedMetadata hook called again).
 $timestamp: The timestamp metadata was generated
 $file: The file the metadata is for
 
+'UserMailerChangeReturnPath': Called to generate a VERP return address
+when UserMailer sends an email, with a bounce handling extension.
+$to: Array of MailAddress objects for the recipients
+&$returnPath: The return address string
+
 'WantedPages::getQueryInfo': Called in WantedPagesPage::getQueryInfo(), can be
 used to alter the SQL query which gets the list of wanted pages.
 &$wantedPages: WantedPagesPage object
index 4f16709..c6fa674 100644 (file)
@@ -40,7 +40,7 @@ Primary scripts:
 
     To enable the profileinfo.php itself, you'll need to set $wgDBadminuser
     and $wgDBadminpassword in your LocalSettings.php, as well as $wgEnableProfileInfo 
-    See also https://www.mediawiki.org/wiki/How_to_debug#Profiling.
+    See also https://www.mediawiki.org/wiki/Manual:Profiling .
 
   thumb.php
     Script used to resize images if it is configured to be done when the web
index 6f449c6..55f17ac 100644 (file)
@@ -114,7 +114,7 @@ function wfImageAuthMain() {
        // be under a folder that has the source file name.
        if ( $zone === 'thumb' || $zone === 'transcoded' ) {
                $name = wfBaseName( dirname( $path ) );
-               $filename = $repo->getZonePath( $zone ) . substr( $path, strlen( "/".$zone ) );
+               $filename = $repo->getZonePath( $zone ) . substr( $path, strlen( "/" . $zone ) );
                // Check to see if the file exists
                if ( !$repo->fileExists( $filename ) ) {
                        wfForbidden( 'img-auth-accessdenied', 'img-auth-nofile', $filename );
index 1417db0..1393685 100644 (file)
@@ -38,15 +38,14 @@ $wgAutoloadLocalClasses = array(
        'Autopromote' => 'includes/Autopromote.php',
        'BaseTemplate' => 'includes/SkinTemplate.php',
        'Block' => 'includes/Block.php',
-       'CacheHelper' => 'includes/CacheHelper.php',
        'Category' => 'includes/Category.php',
        'Categoryfinder' => 'includes/Categoryfinder.php',
        'CategoryViewer' => 'includes/CategoryViewer.php',
-       'ChangesFeed' => 'includes/ChangesFeed.php',
        'ChangeTags' => 'includes/ChangeTags.php',
        'ChannelFeed' => 'includes/Feed.php',
        'Collation' => 'includes/Collation.php',
        'CollationCkb' => 'includes/Collation.php',
+       'CollationEt' => 'includes/Collation.php',
        'ConcatenatedGzipHistoryBlob' => 'includes/HistoryBlob.php',
        'Cookie' => 'includes/Cookie.php',
        'CookieJar' => 'includes/Cookie.php',
@@ -107,28 +106,20 @@ $wgAutoloadLocalClasses = array(
        'HTMLTextAreaField' => 'includes/htmlform/HTMLTextAreaField.php',
        'HTMLTextField' => 'includes/htmlform/HTMLTextField.php',
        'Http' => 'includes/HttpFunctions.php',
-       'ICacheHelper' => 'includes/CacheHelper.php',
        'IcuCollation' => 'includes/Collation.php',
        'IdentityCollation' => 'includes/Collation.php',
        'ImportStreamSource' => 'includes/Import.php',
        'ImportStringSource' => 'includes/Import.php',
        'IndexPager' => 'includes/Pager.php',
        'Interwiki' => 'includes/interwiki/Interwiki.php',
-       'LCStore' => 'includes/cache/LocalisationCache.php',
-       'LCStoreAccel' => 'includes/cache/LocalisationCache.php',
-       'LCStoreCDB' => 'includes/cache/LocalisationCache.php',
-       'LCStoreDB' => 'includes/cache/LocalisationCache.php',
-       'LCStoreNull' => 'includes/cache/LocalisationCache.php',
        'License' => 'includes/Licenses.php',
        'Licenses' => 'includes/Licenses.php',
        'Linker' => 'includes/Linker.php',
        'LinkFilter' => 'includes/LinkFilter.php',
-       'LocalisationCache' => 'includes/cache/LocalisationCache.php',
-       'LocalisationCacheBulkLoad' => 'includes/cache/LocalisationCache.php',
        'MagicWord' => 'includes/MagicWord.php',
        'MagicWordArray' => 'includes/MagicWord.php',
        'MailAddress' => 'includes/UserMailer.php',
-       'MediaWiki' => 'includes/Wiki.php',
+       'MediaWiki' => 'includes/MediaWiki.php',
        'MediaWikiI18N' => 'includes/SkinTemplate.php',
        'MediaWikiVersionFetcher' => 'includes/MediaWikiVersionFetcher.php',
        'Message' => 'includes/Message.php',
@@ -136,8 +127,7 @@ $wgAutoloadLocalClasses = array(
        'MimeMagic' => 'includes/MimeMagic.php',
        'MWHookException' => 'includes/Hooks.php',
        'MWHttpRequest' => 'includes/HttpFunctions.php',
-       'MWInit' => 'includes/Init.php',
-       'MWNamespace' => 'includes/Namespace.php',
+       'MWNamespace' => 'includes/MWNamespace.php',
        'OutputPage' => 'includes/OutputPage.php',
        'Pager' => 'includes/Pager.php',
        'PasswordError' => 'includes/User.php',
@@ -175,7 +165,6 @@ $wgAutoloadLocalClasses = array(
        'Status' => 'includes/Status.php',
        'StreamFile' => 'includes/StreamFile.php',
        'StringPrefixSearch' => 'includes/PrefixSearch.php',
-       'StubContLang' => 'includes/StubObject.php',
        'StubObject' => 'includes/StubObject.php',
        'StubUserLang' => 'includes/StubObject.php',
        'TablePager' => 'includes/Pager.php',
@@ -190,7 +179,6 @@ $wgAutoloadLocalClasses = array(
        'User' => 'includes/User.php',
        'UserArray' => 'includes/UserArray.php',
        'UserArrayFromResult' => 'includes/UserArrayFromResult.php',
-       'UserCache' => 'includes/cache/UserCache.php',
        'UserMailer' => 'includes/UserMailer.php',
        'UserRightsProxy' => 'includes/UserRightsProxy.php',
        'WatchedItem' => 'includes/WatchedItem.php',
@@ -217,17 +205,14 @@ $wgAutoloadLocalClasses = array(
        'FormlessAction' => 'includes/actions/FormlessAction.php',
        'FormAction' => 'includes/actions/FormAction.php',
        'HistoryAction' => 'includes/actions/HistoryAction.php',
-       'HistoryPage' => 'includes/actions/HistoryAction.php',
        'HistoryPager' => 'includes/actions/HistoryAction.php',
        'InfoAction' => 'includes/actions/InfoAction.php',
        'MarkpatrolledAction' => 'includes/actions/MarkpatrolledAction.php',
        'ProtectAction' => 'includes/actions/ProtectAction.php',
        'PurgeAction' => 'includes/actions/PurgeAction.php',
        'RawAction' => 'includes/actions/RawAction.php',
-       'RawPage' => 'includes/actions/RawAction.php',
        'RenderAction' => 'includes/actions/RenderAction.php',
        'RevertAction' => 'includes/actions/RevertAction.php',
-       'RevertFileAction' => 'includes/actions/RevertAction.php',
        'RevisiondeleteAction' => 'includes/actions/RevisiondeleteAction.php',
        'RollbackAction' => 'includes/actions/RollbackAction.php',
        'SubmitAction' => 'includes/actions/EditAction.php',
@@ -347,6 +332,7 @@ $wgAutoloadLocalClasses = array(
        # includes/cache
        'BacklinkCache' => 'includes/cache/BacklinkCache.php',
        'CacheDependency' => 'includes/cache/CacheDependency.php',
+       'CacheHelper' => 'includes/cache/CacheHelper.php',
        'ConstantDependency' => 'includes/cache/CacheDependency.php',
        'DependencyWrapper' => 'includes/cache/CacheDependency.php',
        'FileCacheBase' => 'includes/cache/FileCacheBase.php',
@@ -354,14 +340,24 @@ $wgAutoloadLocalClasses = array(
        'GenderCache' => 'includes/cache/GenderCache.php',
        'GlobalDependency' => 'includes/cache/CacheDependency.php',
        'HTMLFileCache' => 'includes/cache/HTMLFileCache.php',
+       'ICacheHelper' => 'includes/cache/CacheHelper.php',
+       'LCStore' => 'includes/cache/LocalisationCache.php',
+       'LCStoreAccel' => 'includes/cache/LocalisationCache.php',
+       'LCStoreCDB' => 'includes/cache/LocalisationCache.php',
+       'LCStoreDB' => 'includes/cache/LocalisationCache.php',
+       'LCStoreNull' => 'includes/cache/LocalisationCache.php',
        'LinkBatch' => 'includes/cache/LinkBatch.php',
        'LinkCache' => 'includes/cache/LinkCache.php',
+       'LocalisationCache' => 'includes/cache/LocalisationCache.php',
+       'LocalisationCacheBulkLoad' => 'includes/cache/LocalisationCache.php',
        'MapCacheLRU' => 'includes/cache/MapCacheLRU.php',
        'MessageCache' => 'includes/cache/MessageCache.php',
        'ObjectFileCache' => 'includes/cache/ObjectFileCache.php',
        'ResourceFileCache' => 'includes/cache/ResourceFileCache.php',
+       'UserCache' => 'includes/cache/UserCache.php',
 
        # includes/changes
+       'ChangesFeed' => 'includes/changes/ChangesFeed.php',
        'ChangesList' => 'includes/changes/ChangesList.php',
        'EnhancedChangesList' => 'includes/changes/EnhancedChangesList.php',
        'OldChangesList' => 'includes/changes/OldChangesList.php',
@@ -465,7 +461,7 @@ $wgAutoloadLocalClasses = array(
        'SQLiteField' => 'includes/db/DatabaseSqlite.php',
 
        # includes/debug
-       'MWDebug' => 'includes/debug/Debug.php',
+       'MWDebug' => 'includes/debug/MWDebug.php',
 
        # includes/deferred
        'DataUpdate' => 'includes/deferred/DataUpdate.php',
@@ -738,7 +734,6 @@ $wgAutoloadLocalClasses = array(
        'DjVuImage' => 'includes/media/DjVuImage.php',
        'Exif' => 'includes/media/Exif.php',
        'ExifBitmapHandler' => 'includes/media/ExifBitmap.php',
-       'FormatExif' => 'includes/media/FormatMetadata.php',
        'FormatMetadata' => 'includes/media/FormatMetadata.php',
        'GIFHandler' => 'includes/media/GIF.php',
        'GIFMetadataExtractor' => 'includes/media/GIFMetadataExtractor.php',
@@ -801,8 +796,8 @@ $wgAutoloadLocalClasses = array(
        'CoreTagHooks' => 'includes/parser/CoreTagHooks.php',
        'DateFormatter' => 'includes/parser/DateFormatter.php',
        'LinkHolderArray' => 'includes/parser/LinkHolderArray.php',
-       'MWTidy' => 'includes/parser/Tidy.php',
-       'MWTidyWrapper' => 'includes/parser/Tidy.php',
+       'MWTidy' => 'includes/parser/MWTidy.php',
+       'MWTidyWrapper' => 'includes/parser/MWTidy.php',
        'PPCustomFrame_DOM' => 'includes/parser/Preprocessor_DOM.php',
        'PPCustomFrame_Hash' => 'includes/parser/Preprocessor_Hash.php',
        'PPDAccum_Hash' => 'includes/parser/Preprocessor_Hash.php',
@@ -856,6 +851,8 @@ $wgAutoloadLocalClasses = array(
        'MachineReadableRCFeedFormatter' => 'includes/rcfeed/MachineReadableRCFeedFormatter.php',
 
        # includes/resourceloader
+       'DerivativeResourceLoaderContext' =>
+               'includes/resourceloader/DerivativeResourceLoaderContext.php',
        'ResourceLoader' => 'includes/resourceloader/ResourceLoader.php',
        'ResourceLoaderContext' => 'includes/resourceloader/ResourceLoaderContext.php',
        'ResourceLoaderFileModule' => 'includes/resourceloader/ResourceLoaderFileModule.php',
@@ -1151,6 +1148,7 @@ $wgAutoloadLocalClasses = array(
        'FixExtLinksProtocolRelative' => 'maintenance/fixExtLinksProtocolRelative.php',
        'LoggedUpdateMaintenance' => 'maintenance/Maintenance.php',
        'Maintenance' => 'maintenance/Maintenance.php',
+       'PopulateBacklinkNamespace' => 'maintenance/populateBacklinkNamespace.php',
        'PopulateCategory' => 'maintenance/populateCategory.php',
        'PopulateImageSha1' => 'maintenance/populateImageSha1.php',
        'PopulateFilearchiveSha1' => 'maintenance/populateFilearchiveSha1.php',
index 3896369..aaabec9 100644 (file)
@@ -347,7 +347,7 @@ class Block {
        /**
         * Given a database row from the ipblocks table, initialize
         * member variables
-        * @param ResultWrapper $row A row from the ipblocks table
+        * @param stdClass $row A row from the ipblocks table
         */
        protected function initFromRow( $row ) {
                $this->setTarget( $row->ipb_address );
@@ -382,7 +382,7 @@ class Block {
 
        /**
         * Create a new Block object from a database row
-        * @param ResultWrapper $row Row from the ipblocks table
+        * @param stdClass $row Row from the ipblocks table
         * @return Block
         */
        public static function newFromRow( $row ) {
@@ -967,7 +967,7 @@ class Block {
 
                $method = __METHOD__;
                $dbw = wfGetDB( DB_MASTER );
-               $dbw->onTransactionIdle( function() use ( $dbw, $method ) {
+               $dbw->onTransactionIdle( function () use ( $dbw, $method ) {
                        $dbw->delete( 'ipblocks',
                                array( 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ), $method );
                } );
@@ -1123,7 +1123,7 @@ class Block {
 
                // Sort hard blocks before soft ones and secondarily sort blocks
                // that disable account creation before those that don't.
-               usort( $blocks, function( Block $a, Block $b ) {
+               usort( $blocks, function ( Block $a, Block $b ) {
                        $aWeight = (int)$a->isHardblock() . (int)$a->prevents( 'createaccount' );
                        $bWeight = (int)$b->isHardblock() . (int)$b->prevents( 'createaccount' );
                        return strcmp( $bWeight, $aWeight ); // highest weight first
@@ -1368,7 +1368,7 @@ class Block {
                        $this->getId(),
                        $lang->formatExpiry( $this->mExpiry ),
                        (string)$intended,
-                       $lang->timeanddate( wfTimestamp( TS_MW, $this->mTimestamp ), true ),
+                       $lang->userTimeAndDate( $this->mTimestamp, $context->getUser() ),
                );
        }
 }
diff --git a/includes/CacheHelper.php b/includes/CacheHelper.php
deleted file mode 100644 (file)
index 695eac3..0000000
+++ /dev/null
@@ -1,386 +0,0 @@
-<?php
-/**
- * Cache of various elements in a single cache entry.
- *
- * 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
- * @license GNU GPL v2 or later
- * @author Jeroen De Dauw < jeroendedauw@gmail.com >
- */
-
-/**
- * Interface for all classes implementing CacheHelper functionality.
- *
- * @since 1.20
- */
-interface ICacheHelper {
-       /**
-        * Sets if the cache should be enabled or not.
-        *
-        * @since 1.20
-        * @param bool $cacheEnabled
-        */
-       function setCacheEnabled( $cacheEnabled );
-
-       /**
-        * Initializes the caching.
-        * Should be called before the first time anything is added via addCachedHTML.
-        *
-        * @since 1.20
-        *
-        * @param int|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
-        * @param bool|null $cacheEnabled Sets if the cache should be enabled or not.
-        */
-       function startCache( $cacheExpiry = null, $cacheEnabled = null );
-
-       /**
-        * Get a cached value if available or compute it if not and then cache it if possible.
-        * The provided $computeFunction is only called when the computation needs to happen
-        * and should return a result value. $args are arguments that will be passed to the
-        * compute function when called.
-        *
-        * @since 1.20
-        *
-        * @param {function} $computeFunction
-        * @param array|mixed $args
-        * @param string|null $key
-        *
-        * @return mixed
-        */
-       function getCachedValue( $computeFunction, $args = array(), $key = null );
-
-       /**
-        * Saves the HTML to the cache in case it got recomputed.
-        * Should be called after the last time anything is added via addCachedHTML.
-        *
-        * @since 1.20
-        */
-       function saveCache();
-
-       /**
-        * Sets the time to live for the cache, in seconds or a unix timestamp
-        * indicating the point of expiry...
-        *
-        * @since 1.20
-        *
-        * @param int $cacheExpiry
-        */
-       function setExpiry( $cacheExpiry );
-}
-
-/**
- * Helper class for caching various elements in a single cache entry.
- *
- * To get a cached value or compute it, use getCachedValue like this:
- * $this->getCachedValue( $callback );
- *
- * To add HTML that should be cached, use addCachedHTML like this:
- * $this->addCachedHTML( $callback );
- *
- * The callback function is only called when needed, so do all your expensive
- * computations here. This function should returns the HTML to be cached.
- * It should not add anything to the PageOutput object!
- *
- * Before the first addCachedHTML call, you should call $this->startCache();
- * After adding the last HTML that should be cached, call $this->saveCache();
- *
- * @since 1.20
- */
-class CacheHelper implements ICacheHelper {
-       /**
-        * The time to live for the cache, in seconds or a unix timestamp indicating the point of expiry.
-        *
-        * @since 1.20
-        * @var int
-        */
-       protected $cacheExpiry = 3600;
-
-       /**
-        * List of HTML chunks to be cached (if !hasCached) or that where cached (of hasCached).
-        * If not cached already, then the newly computed chunks are added here,
-        * if it as cached already, chunks are removed from this list as they are needed.
-        *
-        * @since 1.20
-        * @var array
-        */
-       protected $cachedChunks;
-
-       /**
-        * Indicates if the to be cached content was already cached.
-        * Null if this information is not available yet.
-        *
-        * @since 1.20
-        * @var bool|null
-        */
-       protected $hasCached = null;
-
-       /**
-        * If the cache is enabled or not.
-        *
-        * @since 1.20
-        * @var bool
-        */
-       protected $cacheEnabled = true;
-
-       /**
-        * Function that gets called when initialization is done.
-        *
-        * @since 1.20
-        * @var callable
-        */
-       protected $onInitHandler = false;
-
-       /**
-        * Elements to build a cache key with.
-        *
-        * @since 1.20
-        * @var array
-        */
-       protected $cacheKey = array();
-
-       /**
-        * Sets if the cache should be enabled or not.
-        *
-        * @since 1.20
-        * @param bool $cacheEnabled
-        */
-       public function setCacheEnabled( $cacheEnabled ) {
-               $this->cacheEnabled = $cacheEnabled;
-       }
-
-       /**
-        * Initializes the caching.
-        * Should be called before the first time anything is added via addCachedHTML.
-        *
-        * @since 1.20
-        *
-        * @param int|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
-        * @param bool|null $cacheEnabled Sets if the cache should be enabled or not.
-        */
-       public function startCache( $cacheExpiry = null, $cacheEnabled = null ) {
-               if ( is_null( $this->hasCached ) ) {
-                       if ( !is_null( $cacheExpiry ) ) {
-                               $this->cacheExpiry = $cacheExpiry;
-                       }
-
-                       if ( !is_null( $cacheEnabled ) ) {
-                               $this->setCacheEnabled( $cacheEnabled );
-                       }
-
-                       $this->initCaching();
-               }
-       }
-
-       /**
-        * Returns a message that notifies the user he/she is looking at
-        * a cached version of the page, including a refresh link.
-        *
-        * @since 1.20
-        *
-        * @param IContextSource $context
-        * @param bool $includePurgeLink
-        *
-        * @return string
-        */
-       public function getCachedNotice( IContextSource $context, $includePurgeLink = true ) {
-               if ( $this->cacheExpiry < 86400 * 3650 ) {
-                       $message = $context->msg(
-                               'cachedspecial-viewing-cached-ttl',
-                               $context->getLanguage()->formatDuration( $this->cacheExpiry )
-                       )->escaped();
-               } else {
-                       $message = $context->msg(
-                               'cachedspecial-viewing-cached-ts'
-                       )->escaped();
-               }
-
-               if ( $includePurgeLink ) {
-                       $refreshArgs = $context->getRequest()->getQueryValues();
-                       unset( $refreshArgs['title'] );
-                       $refreshArgs['action'] = 'purge';
-
-                       $subPage = $context->getTitle()->getFullText();
-                       $subPage = explode( '/', $subPage, 2 );
-                       $subPage = count( $subPage ) > 1 ? $subPage[1] : false;
-
-                       $message .= ' ' . Linker::link(
-                               $context->getTitle( $subPage ),
-                               $context->msg( 'cachedspecial-refresh-now' )->escaped(),
-                               array(),
-                               $refreshArgs
-                       );
-               }
-
-               return $message;
-       }
-
-       /**
-        * Initializes the caching if not already done so.
-        * Should be called before any of the caching functionality is used.
-        *
-        * @since 1.20
-        */
-       protected function initCaching() {
-               if ( $this->cacheEnabled && is_null( $this->hasCached ) ) {
-                       $cachedChunks = wfGetCache( CACHE_ANYTHING )->get( $this->getCacheKeyString() );
-
-                       $this->hasCached = is_array( $cachedChunks );
-                       $this->cachedChunks = $this->hasCached ? $cachedChunks : array();
-
-                       if ( $this->onInitHandler !== false ) {
-                               call_user_func( $this->onInitHandler, $this->hasCached );
-                       }
-               }
-       }
-
-       /**
-        * Get a cached value if available or compute it if not and then cache it if possible.
-        * The provided $computeFunction is only called when the computation needs to happen
-        * and should return a result value. $args are arguments that will be passed to the
-        * compute function when called.
-        *
-        * @since 1.20
-        *
-        * @param {function} $computeFunction
-        * @param array|mixed $args
-        * @param string|null $key
-        *
-        * @return mixed
-        */
-       public function getCachedValue( $computeFunction, $args = array(), $key = null ) {
-               $this->initCaching();
-
-               if ( $this->cacheEnabled && $this->hasCached ) {
-                       $value = null;
-
-                       if ( is_null( $key ) ) {
-                               $itemKey = array_keys( array_slice( $this->cachedChunks, 0, 1 ) );
-                               $itemKey = array_shift( $itemKey );
-
-                               if ( !is_integer( $itemKey ) ) {
-                                       wfWarn( "Attempted to get item with non-numeric key while " .
-                                               "the next item in the queue has a key ($itemKey) in " . __METHOD__ );
-                               } elseif ( is_null( $itemKey ) ) {
-                                       wfWarn( "Attempted to get an item while the queue is empty in " . __METHOD__ );
-                               } else {
-                                       $value = array_shift( $this->cachedChunks );
-                               }
-                       } 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__ );
-                               }
-                       }
-               } else {
-                       if ( !is_array( $args ) ) {
-                               $args = array( $args );
-                       }
-
-                       $value = call_user_func_array( $computeFunction, $args );
-
-                       if ( $this->cacheEnabled ) {
-                               if ( is_null( $key ) ) {
-                                       $this->cachedChunks[] = $value;
-                               } else {
-                                       $this->cachedChunks[$key] = $value;
-                               }
-                       }
-               }
-
-               return $value;
-       }
-
-       /**
-        * Saves the HTML to the cache in case it got recomputed.
-        * Should be called after the last time anything is added via addCachedHTML.
-        *
-        * @since 1.20
-        */
-       public function saveCache() {
-               if ( $this->cacheEnabled && $this->hasCached === false && !empty( $this->cachedChunks ) ) {
-                       wfGetCache( CACHE_ANYTHING )->set(
-                               $this->getCacheKeyString(),
-                               $this->cachedChunks,
-                               $this->cacheExpiry
-                       );
-               }
-       }
-
-       /**
-        * Sets the time to live for the cache, in seconds or a unix timestamp
-        * indicating the point of expiry...
-        *
-        * @since 1.20
-        *
-        * @param int $cacheExpiry
-        */
-       public function setExpiry( $cacheExpiry ) {
-               $this->cacheExpiry = $cacheExpiry;
-       }
-
-       /**
-        * Returns the cache key to use to cache this page's HTML output.
-        * Is constructed from the special page name and language code.
-        *
-        * @since 1.20
-        *
-        * @return string
-        * @throws MWException
-        */
-       protected function getCacheKeyString() {
-               if ( $this->cacheKey === array() ) {
-                       throw new MWException( 'No cache key set, so cannot obtain or save the CacheHelper values.' );
-               }
-
-               return call_user_func_array( 'wfMemcKey', $this->cacheKey );
-       }
-
-       /**
-        * Sets the cache key that should be used.
-        *
-        * @since 1.20
-        *
-        * @param array $cacheKey
-        */
-       public function setCacheKey( array $cacheKey ) {
-               $this->cacheKey = $cacheKey;
-       }
-
-       /**
-        * Rebuild the content, even if it's already cached.
-        * This effectively has the same effect as purging the cache,
-        * since it will be overridden with the new value on the next request.
-        *
-        * @since 1.20
-        */
-       public function rebuildOnDemand() {
-               $this->hasCached = false;
-       }
-
-       /**
-        * Sets a function that gets called when initialization of the cache is done.
-        *
-        * @since 1.20
-        *
-        * @param callable $handlerFunction
-        */
-       public function setOnInitializedHandler( $handlerFunction ) {
-               $this->onInitHandler = $handlerFunction;
-       }
-}
index cd9eaa9..d6755c2 100644 (file)
@@ -708,7 +708,7 @@ class CategoryViewer extends ContextSource {
                        // quick due to the small number of entries.
                        $totalcnt = $rescnt;
                        $category = $this->cat;
-                       wfGetDB( DB_MASTER )->onTransactionIdle( function() use ( $category ) {
+                       wfGetDB( DB_MASTER )->onTransactionIdle( function () use ( $category ) {
                                $category->refreshCounts();
                        } );
                } else {
diff --git a/includes/ChangesFeed.php b/includes/ChangesFeed.php
deleted file mode 100644 (file)
index fb491e5..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-<?php
-/**
- * Feed for list of changes.
- *
- * 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
- */
-
-/**
- * Feed to Special:RecentChanges and Special:RecentChangesLiked
- *
- * @ingroup Feed
- */
-class ChangesFeed {
-       public $format, $type, $titleMsg, $descMsg;
-
-       /**
-        * Constructor
-        *
-        * @param string $format Feed's format (either 'rss' or 'atom')
-        * @param string $type Type of feed (for cache keys)
-        */
-       public function __construct( $format, $type ) {
-               $this->format = $format;
-               $this->type = $type;
-       }
-
-       /**
-        * Get a ChannelFeed subclass object to use
-        *
-        * @param string $title Feed's title
-        * @param string $description Feed's description
-        * @param string $url Url of origin page
-        * @return ChannelFeed|bool ChannelFeed subclass or false on failure
-        */
-       public function getFeedObject( $title, $description, $url ) {
-               global $wgSitename, $wgLanguageCode, $wgFeedClasses;
-
-               if ( !isset( $wgFeedClasses[$this->format] ) ) {
-                       return false;
-               }
-
-               if ( !array_key_exists( $this->format, $wgFeedClasses ) ) {
-                       // falling back to atom
-                       $this->format = 'atom';
-               }
-
-               $feedTitle = "$wgSitename  - {$title} [$wgLanguageCode]";
-               return new $wgFeedClasses[$this->format](
-                       $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;
-               }
-
-               $optionsHash = md5( serialize( $opts->getAllValues() ) ) . $wgRenderHashAppend;
-               $timekey = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash, 'timestamp' );
-               $key = wfMemcKey( $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 $messageMemc
-        *
-        * @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 ) {
-               global $messageMemc;
-               $expire = 3600 * 24; # One day
-               $messageMemc->set( $key, $feed, $expire );
-               $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire );
-       }
-
-       /**
-        * Try to load the feed result from $messageMemc
-        *
-        * @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, $messageMemc;
-
-               $feedLastmod = $messageMemc->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 ); // bug 21916
-                               }
-                               return $messageMemc->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 DatabaseBase resource with recentchanges rows
-        * @param Feed $feed
-        */
-       public static function generateFeed( $rows, &$feed ) {
-               wfProfileIn( __METHOD__ );
-               $items = self::buildItems( $rows );
-               $feed->outHeader();
-               foreach ( $items as $item ) {
-                       $feed->outItem( $item );
-               }
-               $feed->outFooter();
-               wfProfileOut( __METHOD__ );
-       }
-
-       /**
-        * Generate the feed items given a row from the database.
-        * @param object $rows DatabaseBase resource with recentchanges rows
-        */
-       public static function buildItems( $rows ) {
-               wfProfileIn( __METHOD__ );
-               $items = array();
-
-               # Merge adjacent edits by one user
-               $sorted = array();
-               $n = 0;
-               foreach ( $rows as $obj ) {
-                       if ( $n > 0 &&
-                               $obj->rc_type == RC_EDIT &&
-                               $obj->rc_namespace >= 0 &&
-                               $obj->rc_cur_id == $sorted[$n - 1]->rc_cur_id &&
-                               $obj->rc_user_text == $sorted[$n - 1]->rc_user_text ) {
-                               $sorted[$n - 1]->rc_last_oldid = $obj->rc_last_oldid;
-                       } else {
-                               $sorted[$n] = $obj;
-                               $n++;
-                       }
-               }
-
-               foreach ( $sorted as $obj ) {
-                       $title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title );
-                       $talkpage = MWNamespace::canTalk( $obj->rc_namespace )
-                               ? $title->getTalkPage()->getFullURL()
-                               : '';
-
-                       // Skip items with deleted content (avoids partially complete/inconsistent output)
-                       if ( $obj->rc_deleted ) {
-                               continue;
-                       }
-
-                       if ( $obj->rc_this_oldid ) {
-                               $url = $title->getFullURL( array(
-                                       'diff' => $obj->rc_this_oldid,
-                                       'oldid' => $obj->rc_last_oldid,
-                               ) );
-                       } else {
-                               // log entry or something like that.
-                               $url = $title->getFullURL();
-                       }
-
-                       $items[] = new FeedItem(
-                               $title->getPrefixedText(),
-                               FeedUtils::formatDiff( $obj ),
-                               $url,
-                               $obj->rc_timestamp,
-                               ( $obj->rc_deleted & Revision::DELETED_USER )
-                                       ? wfMessage( 'rev-deleted-user' )->escaped() : $obj->rc_user_text,
-                               $talkpage
-                       );
-               }
-
-               wfProfileOut( __METHOD__ );
-               return $items;
-       }
-}
index 71adb09..bcb0a56 100644 (file)
@@ -49,6 +49,8 @@ abstract class Collation {
                                return new IcuCollation( 'root' );
                        case 'xx-uca-ckb':
                                return new CollationCkb;
+                       case 'xx-uca-et':
+                               return new CollationEt;
                        default:
                                $match = array();
                                if ( preg_match( '/^uca-([a-z@=-]+)$/', $collationName, $match ) ) {
@@ -253,7 +255,7 @@ class IcuCollation extends Collation {
                'el' => array(),
                'eo' => array( "Ĉ", "Ĝ", "Ĥ", "Ĵ", "Ŝ", "Ŭ" ),
                'es' => array( "Ñ" ),
-               'et' => array( "Š", "Ž", "Õ", "Ä", "Ö", "Ü" ),
+               'et' => array( "Š", "Ž", "Õ", "Ä", "Ö", "Ü", "W" ), // added W for CollationEt (xx-uca-et)
                'eu' => array( "Ñ" ),
                'fo' => array( "Á", "Ð", "Í", "Ó", "Ú", "Ý", "Æ", "Ø", "Å" ),
                'fur' => array( "À", "Á", "Â", "È", "Ì", "Ò", "Ù" ),
@@ -597,3 +599,42 @@ class CollationCkb extends IcuCollation {
                $this->digitTransformLanguage = Language::factory( 'ckb' );
        }
 }
+
+/**
+ * Workaround for incorrect collation of Estonian language ('et') in ICU (bug 54168).
+ *
+ * 'W' and 'V' should not be considered the same letter for the purposes of collation in modern
+ * Estonian. We work around this by replacing 'W' and 'w' with 'ᴡ' U+1D21 'LATIN LETTER SMALL
+ * CAPITAL W' for sortkey generation, which is collated like 'W' and is not tailored to have the
+ * same primary weight as 'V' in Estonian.
+ */
+class CollationEt extends IcuCollation {
+       function __construct() {
+               parent::__construct( 'et' );
+       }
+
+       private static function mangle( $string ) {
+               return str_replace(
+                       array( 'w', 'W' ),
+                       'ᴡ', // U+1D21 'LATIN LETTER SMALL CAPITAL W'
+                       $string
+               );
+       }
+
+       private static function unmangle( $string ) {
+               // Casing data is lost…
+               return str_replace(
+                       'ᴡ', // U+1D21 'LATIN LETTER SMALL CAPITAL W'
+                       'W',
+                       $string
+               );
+       }
+
+       function getSortKey( $string ) {
+               return parent::getSortKey( self::mangle( $string ) );
+       }
+
+       function getFirstLetter( $string ) {
+               return self::unmangle( parent::getFirstLetter( self::mangle( $string ) ) );
+       }
+}
index 0990708..86b7533 100644 (file)
@@ -355,11 +355,6 @@ $wgEnableAsyncUploads = false;
  */
 $wgIllegalFileChars = ":";
 
-/**
- * @deprecated since 1.17 use $wgDeletedDirectory
- */
-$wgFileStore = array();
-
 /**
  * What directory to place deleted uploads in.
  * Defaults to "{$wgUploadDirectory}/deleted".
@@ -1217,6 +1212,34 @@ $wgThumbLimits = array(
        300
 );
 
+/**
+ * When defined, is an array of image widths used as buckets for thumbnail generation.
+ * The goal is to save resources by generating thumbnails based on reference buckets instead of
+ * always using the original. This will incur a speed gain but cause a quality loss.
+ *
+ * The buckets generation is chained, with each bucket generated based on the above bucket
+ * when possible. File handlers have to opt into using that feature. For now only BitmapHandler
+ * supports it.
+ */
+$wgThumbnailBuckets = null;
+
+/**
+ * When using thumbnail buckets as defined above, this sets the minimum distance to the bucket
+ * above the requested size. The distance represents how many extra pixels of width the bucket
+ * needs in order to be used as the reference for a given thumbnail. For example, with the
+ * following buckets:
+ *
+ * $wgThumbnailBuckets = array ( 128, 256, 512 );
+ *
+ * and a distance of 50:
+ *
+ * $wgThumbnailMinimumBucketDistance = 50;
+ *
+ * If we want to render a thumbnail of width 220px, the 512px bucket will be used,
+ * because 220 + 50 = 270 and the closest bucket bigger than 270px is 512.
+ */
+$wgThumbnailMinimumBucketDistance = 50;
+
 /**
  * Default parameters for the "<gallery>" tag
  */
@@ -2163,6 +2186,12 @@ $wgCachePages = true;
  */
 $wgCacheEpoch = '20030516000000';
 
+/**
+ * Directory where GitInfo will look for pre-computed cache files. If false,
+ * $wgCacheDirectory/gitinfo will be used.
+ */
+$wgGitInfoCacheDirectory = false;
+
 /**
  * Bump this number when changing the global style sheets and JavaScript.
  *
@@ -3951,9 +3980,6 @@ $wgTranscludeCacheExpiry = 3600;
  * - 'any': all pages as considered as valid articles
  * - 'comma': the page must contain a comma to be considered valid
  * - 'link': the page must contain a [[wiki link]] to be considered valid
- * - null: the value will be set at run time depending on $wgUseCommaCount:
- *         if $wgUseCommaCount is false, it will be 'link', if it is true
- *         it will be 'comma'
  *
  * See also See https://www.mediawiki.org/wiki/Manual:Article_count
  *
@@ -3961,13 +3987,7 @@ $wgTranscludeCacheExpiry = 3600;
  * to update it, you will need to run the maintenance/updateArticleCount.php
  * script.
  */
-$wgArticleCountMethod = null;
-
-/**
- * Backward compatibility setting, will set $wgArticleCountMethod if it is null.
- * @deprecated since 1.18; use $wgArticleCountMethod instead
- */
-$wgUseCommaCount = false;
+$wgArticleCountMethod = 'link';
 
 /**
  * wgHitcounterUpdateFreq sets how often page counters should be updated, higher
@@ -4364,7 +4384,7 @@ $wgGroupPermissions['sysop']['unblockself'] = true;
 $wgGroupPermissions['sysop']['suppressredirect'] = true;
 #$wgGroupPermissions['sysop']['pagelang'] = true;
 #$wgGroupPermissions['sysop']['upload_by_url'] = true;
-#$wgGroupPermissions['sysop']['mergehistory'] = true;
+$wgGroupPermissions['sysop']['mergehistory'] = true;
 
 // Permission to change users' group assignments
 $wgGroupPermissions['bureaucrat']['userrights'] = true;
@@ -4380,6 +4400,8 @@ $wgGroupPermissions['bureaucrat']['noratelimit'] = true;
 #$wgGroupPermissions['suppress']['hideuser'] = true;
 // To hide revisions/log items from users and Sysops
 #$wgGroupPermissions['suppress']['suppressrevision'] = true;
+// To view revisions/log items hidden from users and Sysops
+#$wgGroupPermissions['suppress']['viewsuppressed'] = true;
 // For private suppression log access
 #$wgGroupPermissions['suppress']['suppressionlog'] = true;
 
@@ -4679,12 +4701,6 @@ $wgSummarySpamRegex = array();
  */
 $wgEnableDnsBlacklist = false;
 
-/**
- * @deprecated since 1.17 Use $wgEnableDnsBlacklist instead, only kept for
- * backward compatibility.
- */
-$wgEnableSorbs = false;
-
 /**
  * List of DNS blacklists to use, if $wgEnableDnsBlacklist is true.
  *
@@ -4710,12 +4726,6 @@ $wgEnableSorbs = false;
  */
 $wgDnsBlacklistUrls = array( 'http.dnsbl.sorbs.net.' );
 
-/**
- * @deprecated since 1.17 Use $wgDnsBlacklistUrls instead, only kept for
- * backward compatibility.
- */
-$wgSorbsUrl = array();
-
 /**
  * Proxy whitelist, list of addresses that are assumed to be non-proxy despite
  * what the other methods might say.
@@ -5278,18 +5288,6 @@ $wgAdvancedSearchHighlighting = false;
  */
 $wgSearchHighlightBoundaries = '[\p{Z}\p{P}\p{C}]';
 
-/**
- * Set to true to have the search engine count total
- * search matches to present in the Special:Search UI.
- * Not supported by every search engine shipped with MW.
- *
- * This could however be slow on larger wikis, and is pretty flaky
- * with the current title vs content split. Recommend avoiding until
- * that's been worked out cleanly; but this may aid in testing the
- * search UI and API to confirm that the result count works.
- */
-$wgCountTotalSearchHits = false;
-
 /**
  * Template for OpenSearch suggestions, defaults to API action=opensearch
  *
@@ -5601,9 +5599,11 @@ $wgRC2UDPOmitBots = false;
  * Destinations to which notifications about recent changes
  * should be sent.
  *
- * As of MediaWiki 1.22, the only supported 'engine' parameter option in core
- * is 'UDPRCFeedEngine', which is used to send recent changes over UDP to the
- * specified server.
+ * As of MediaWiki 1.22, there are 2 supported 'engine' parameter option in core:
+ *   * 'UDPRCFeedEngine', which is used to send recent changes over UDP to the
+ *      specified server.
+ *   * 'RedisPubSubFeedEngine', which is used to send recent changes to Redis.
+ *
  * The common options are:
  *   * 'uri' -- the address to which the notices are to be sent.
  *   * 'formatter' -- the class name (implementing RCFeedFormatter) which will
@@ -5613,10 +5613,12 @@ $wgRC2UDPOmitBots = false;
  *   * 'omit_user' -- whether edits by registered users should be in the feed
  *   * 'omit_minor' -- whether minor edits should be in the feed
  *   * 'omit_patrolled' -- whether patrolled edits should be in the feed
+ *
  *  The IRC-specific options are:
  *   * 'add_interwiki_prefix' -- whether the titles should be prefixed with
  *     the first entry in the $wgLocalInterwikis array (or the value of
  *     $wgLocalInterwiki, if set)
+ *
  *  The JSON-specific options are:
  *   * 'channel' -- if set, the 'channel' parameter is also set in JSON values.
  *
@@ -7122,6 +7124,14 @@ $wgHKDFAlgorithm = 'sha256';
  */
 $wgPageLanguageUseDB = false;
 
+/**
+ * Enable use of the *_namespace fields of the pagelinks, redirect, and templatelinks tables.
+ * Set this only if the fields are fully populated. This may be removed in 1.25.
+ * @var bool
+ * @since 1.24
+ */
+$wgUseLinkNamespaceDBFields = false;
+
 /**
  * For really cool vim folding this needs to be at the end:
  * vim: foldmarker=@{,@} foldmethod=marker
index 3d57e95..9d512ab 100644 (file)
@@ -66,11 +66,6 @@ class EditPage {
         */
        const AS_CONTENT_TOO_BIG = 216;
 
-       /**
-        * Status: User cannot edit? (not used)
-        */
-       const AS_USER_CANNOT_EDIT = 217;
-
        /**
         * Status: this anonymous user is not allowed to edit this page
         */
@@ -129,11 +124,6 @@ class EditPage {
         */
        const AS_MAX_ARTICLE_SIZE_EXCEEDED = 229;
 
-       /**
-        * not used
-        */
-       const AS_OK = 230;
-
        /**
         * Status: WikiPage::doEdit() was unsuccessful
         */
@@ -1523,6 +1513,37 @@ class EditPage {
                return true;
        }
 
+       /**
+        * Return the summary to be used for a new section.
+        *
+        * @param string $sectionanchor Set to the section anchor text
+        * @return string
+        */
+       private function newSectionSummary( &$sectionanchor = null ) {
+               global $wgParser;
+
+               if ( $this->sectiontitle !== '' ) {
+                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $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 );
+                               return wfMessage( 'newsectionsummary' )
+                                       ->rawParams( $cleanSectionTitle )->inContentLanguage()->text();
+                       }
+               } elseif ( $this->summary !== '' ) {
+                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
+                       # This is a new section, so create a link to the new section
+                       # in the revision summary.
+                       $cleanSummary = $wgParser->stripSectionName( $this->summary );
+                       return wfMessage( 'newsectionsummary' )
+                               ->rawParams( $cleanSummary )->inContentLanguage()->text();
+               } else {
+                       return $this->summary;
+               }
+       }
+
        /**
         * Attempt submission (no UI)
         *
@@ -1764,31 +1785,11 @@ class EditPage {
                                if ( $this->sectiontitle !== '' ) {
                                        // Insert the section title above the content.
                                        $content = $content->addSectionHeader( $this->sectiontitle );
-
-                                       // Jump to the new section
-                                       $result['sectionanchor'] =
-                                               $wgParser->guessLegacySectionNameFromWikiText( $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 );
-                                               $this->summary = wfMessage( 'newsectionsummary' )
-                                                       ->rawParams( $cleanSectionTitle )->inContentLanguage()->text();
-                                       }
                                } elseif ( $this->summary !== '' ) {
                                        // Insert the section title above the content.
                                        $content = $content->addSectionHeader( $this->summary );
-
-                                       // Jump to the new section
-                                       $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
-
-                                       // Create a link to the new section from the edit summary.
-                                       $cleanSummary = $wgParser->stripSectionName( $this->summary );
-                                       $this->summary = wfMessage( 'newsectionsummary' )
-                                               ->rawParams( $cleanSummary )->inContentLanguage()->text();
                                }
+                               $this->summary = $this->newSectionSummary( $result['sectionanchor'] );
                        }
 
                        $status->value = self::AS_SUCCESS_NEW_ARTICLE;
@@ -1806,7 +1807,8 @@ class EditPage {
                                $this->isConflict = true;
                                if ( $this->section == 'new' ) {
                                        if ( $this->mArticle->getUserText() == $wgUser->getName() &&
-                                               $this->mArticle->getComment() == $this->summary ) {
+                                               $this->mArticle->getComment() == $this->newSectionSummary()
+                                       ) {
                                                // Probably a duplicate submission of a new comment.
                                                // This can happen when squid resends a request after
                                                // a timeout but the first one actually went through.
@@ -1920,24 +1922,7 @@ class EditPage {
                        wfProfileIn( __METHOD__ . '-sectionanchor' );
                        $sectionanchor = '';
                        if ( $this->section == 'new' ) {
-                               if ( $this->sectiontitle !== '' ) {
-                                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $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 );
-                                               $this->summary = wfMessage( 'newsectionsummary' )
-                                                       ->rawParams( $cleanSectionTitle )->inContentLanguage()->text();
-                                       }
-                               } elseif ( $this->summary !== '' ) {
-                                       $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
-                                       # This is a new section, so create a link to the new section
-                                       # in the revision summary.
-                                       $cleanSummary = $wgParser->stripSectionName( $this->summary );
-                                       $this->summary = wfMessage( 'newsectionsummary' )
-                                               ->rawParams( $cleanSummary )->inContentLanguage()->text();
-                               }
+                               $this->summary = $this->newSectionSummary( $sectionanchor );
                        } elseif ( $this->section != '' ) {
                                # Try to get a section anchor from the section source, redirect
                                # to edited section if header found.
@@ -2022,7 +2007,7 @@ class EditPage {
 
                        // Do this in its own transaction to reduce contention...
                        $dbw = wfGetDB( DB_MASTER );
-                       $dbw->onTransactionIdle( function() use ( $dbw, $title, $watch, $wgUser, $fname ) {
+                       $dbw->onTransactionIdle( function () use ( $dbw, $title, $watch, $wgUser, $fname ) {
                                $dbw->begin( $fname );
                                WatchAction::doWatchOrUnwatch( $watch, $title, $wgUser );
                                $dbw->commit( $fname );
index 21fcd5a..e57fe7f 100644 (file)
@@ -1552,23 +1552,3 @@ class DumpMultiWriter {
                return $filenames;
        }
 }
-
-/**
- * @param string $string
- * @return string
- * @todo FIXME: Only used in OAI extension. Move over there.
- */
-function xmlsafe( $string ) {
-       wfProfileIn( __FUNCTION__ );
-
-       /**
-        * The page may contain old data which has not been properly normalized.
-        * Invalid UTF-8 sequences or forbidden control characters will make our
-        * XML output invalid, so be sure to strip them out.
-        */
-       $string = UtfNormal::cleanUp( $string );
-
-       $string = htmlspecialchars( $string );
-       wfProfileOut( __FUNCTION__ );
-       return $string;
-}
index e38bdf1..c4b22f5 100644 (file)
  */
 class Fallback {
 
-       /**
-        * @param string $from
-        * @param string $to
-        * @param string $string
-        * @return string
-        */
-       public static function iconv( $from, $to, $string ) {
-               if ( substr( $to, -8 ) == '//IGNORE' ) {
-                       $to = substr( $to, 0, strlen( $to ) - 8 );
-               }
-               if ( strcasecmp( $from, $to ) == 0 ) {
-                       return $string;
-               }
-               if ( strcasecmp( $from, 'utf-8' ) == 0 ) {
-                       return utf8_decode( $string );
-               }
-               if ( strcasecmp( $to, 'utf-8' ) == 0 ) {
-                       return utf8_encode( $string );
-               }
-               return $string;
-       }
-
        /**
         * Fallback implementation for mb_substr, hardcoded to UTF-8.
         * Attempts to be at least _moderately_ efficient; best optimized
index 304c1bc..acf1bf6 100644 (file)
@@ -57,6 +57,9 @@ class GitInfo {
         */
        public function __construct( $repoDir, $usePrecomputed = true ) {
                $this->cacheFile = self::getCacheFilePath( $repoDir );
+               wfDebugLog( 'gitinfo',
+                       "Computed cacheFile={$this->cacheFile} for {$repoDir}"
+               );
                if ( $usePrecomputed &&
                        $this->cacheFile !== null &&
                        is_readable( $this->cacheFile )
@@ -65,9 +68,11 @@ class GitInfo {
                                file_get_contents( $this->cacheFile ),
                                true
                        );
+                       wfDebugLog( 'gitinfo', "Loaded git data from cache for {$repoDir}" );
                }
 
                if ( !$this->cacheIsComplete() ) {
+                       wfDebugLog( 'gitinfo', "Cache incomplete for {$repoDir}" );
                        $this->basedir = $repoDir . DIRECTORY_SEPARATOR . '.git';
                        if ( is_readable( $this->basedir ) && !is_dir( $this->basedir ) ) {
                                $GITfile = file_get_contents( $this->basedir );
@@ -90,24 +95,31 @@ class GitInfo {
         * Compute the path to the cache file for a given directory.
         *
         * @param string $repoDir The root directory of the repo where .git can be found
-        * @return string Path to GitInfo cache file in $wgCacheDirectory or null if
-        * $wgCacheDirectory is false (cache disabled).
+        * @return string Path to GitInfo cache file in $wgGitInfoCacheDirectory or
+        * null if $wgGitInfoCacheDirectory is false (cache disabled).
+        * @since 1.24
         */
        protected static function getCacheFilePath( $repoDir ) {
-               global $IP, $wgCacheDirectory;
-               if ( $wgCacheDirectory ) {
-                       // Transform path to git repo to something we can safely embed in a filename
-                       $repoName = $repoDir;
-                       if ( strpos( $repoName, $IP ) === 0 ) {
+               global $IP, $wgGitInfoCacheDirectory;
+
+               if ( $wgGitInfoCacheDirectory ) {
+                       // Convert both $IP and $repoDir to canonical paths to protect against
+                       // $IP having changed between the settings files and runtime.
+                       $realIP = realpath( $IP );
+                       $repoName = realpath( $repoDir );
+                       if ( $repoName === false ) {
+                               // Unit tests use fake path names
+                               $repoName = $repoDir;
+                       }
+                       if ( strpos( $repoName, $realIP ) === 0 ) {
                                // Strip $IP from path
-                               $repoName = substr( $repoName, strlen( $IP ) );
+                               $repoName = substr( $repoName, strlen( $realIP ) );
                        }
+                       // Transform path to git repo to something we can safely embed in
+                       // a filename
                        $repoName = strtr( $repoName, DIRECTORY_SEPARATOR, '-' );
                        $fileName = 'info' . $repoName . '.json';
-                       return implode(
-                               DIRECTORY_SEPARATOR,
-                               array( $wgCacheDirectory, 'gitinfo', $fileName )
-                       );
+                       return "{$wgGitInfoCacheDirectory}/{$fileName}";
                }
                return null;
        }
@@ -330,7 +342,9 @@ class GitInfo {
                        $this->getRemoteUrl();
 
                        if ( !$this->cacheIsComplete() ) {
-                               wfDebugLog( "Failed to compute GitInfo for \"{$this->basedir}\"" );
+                               wfDebugLog( 'gitinfo',
+                                       "Failed to compute GitInfo for \"{$this->basedir}\""
+                               );
                                return;
                        }
 
index c1908af..fe12a07 100644 (file)
@@ -35,16 +35,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
  * PHP extensions may be included here.
  */
 
-if ( !function_exists( 'iconv' ) ) {
-       /**
-        * @codeCoverageIgnore
-        * @return string
-        */
-       function iconv( $from, $to, $string ) {
-               return Fallback::iconv( $from, $to, $string );
-       }
-}
-
 if ( !function_exists( 'mb_substr' ) ) {
        /**
         * @codeCoverageIgnore
@@ -2028,36 +2018,6 @@ function wfShowingResults( $offset, $limit ) {
        return wfMessage( 'showingresults' )->numParams( $limit, $offset + 1 )->parse();
 }
 
-/**
- * Generate (prev x| next x) (20|50|100...) type links for paging
- *
- * @param string $offset
- * @param int $limit
- * @param string $link
- * @param string $query Optional URL query parameter string
- * @param bool $atend Optional param for specified if this is the last page
- * @return string
- * @deprecated since 1.19; use Language::viewPrevNext() instead
- */
-function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) {
-       wfDeprecated( __METHOD__, '1.19' );
-
-       global $wgLang;
-
-       $query = wfCgiToArray( $query );
-
-       if ( is_object( $link ) ) {
-               $title = $link;
-       } else {
-               $title = Title::newFromText( $link );
-               if ( is_null( $title ) ) {
-                       return false;
-               }
-       }
-
-       return $wgLang->viewPrevNext( $title, $offset, $limit, $query, $atend );
-}
-
 /**
  * @todo document
  * @todo FIXME: We may want to blacklist some broken browsers
@@ -2580,10 +2540,12 @@ function wfIsHHVM() {
 /**
  * Swap two variables
  *
+ * @deprecated since 1.24
  * @param mixed $x
  * @param mixed $y
  */
 function swap( &$x, &$y ) {
+       wfDeprecated( __FUNCTION__, '1.24' );
        $z = $x;
        $x = $y;
        $y = $z;
@@ -2948,19 +2910,28 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(),
                $fds[(int)$pipe] = $fd;
        }
 
-       while ( true ) {
-               $status = proc_get_status( $proc );
-               if ( !$status['running'] ) {
-                       break;
+       $running = true;
+       $timeout = null;
+       $numReadyPipes = 0;
+
+       while ( $running === true || $numReadyPipes !== 0 ) {
+               if ( $running ) {
+                       $status = proc_get_status( $proc );
+                       // If the process has terminated, switch to nonblocking selects
+                       // for getting any data still waiting to be read.
+                       if ( !$status['running'] ) {
+                               $running = false;
+                               $timeout = 0;
+                       }
                }
-               $status = false;
 
                $readyPipes = $pipes;
 
                // Clear last error
                // @codingStandardsIgnoreStart Generic.PHP.NoSilencedErrors.Discouraged
                @trigger_error( '' );
-               if ( @stream_select( $readyPipes, $emptyArray, $emptyArray, null ) === false ) {
+               $numReadyPipes = @stream_select( $readyPipes, $emptyArray, $emptyArray, $timeout );
+               if ( $numReadyPipes === false ) {
                        // @codingStandardsIgnoreEnd
                        $error = error_get_last();
                        if ( strncmp( $error['message'], $eintrMessage, strlen( $eintrMessage ) ) == 0 ) {
@@ -3008,7 +2979,7 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(),
 
        // Use the status previously collected if possible, since proc_get_status()
        // just calls waitpid() which will not return anything useful the second time.
-       if ( $status === false ) {
+       if ( $running ) {
                $status = proc_get_status( $proc );
        }
 
@@ -3826,11 +3797,14 @@ function wfGetNull() {
  * in maintenance scripts, to avoid causing too much lag.  Of course, this is
  * a no-op if there are no slaves.
  *
- * @param int|bool $maxLag (deprecated)
+ * @param float|null $ifWritesSince Only wait if writes were done since this UNIX timestamp
  * @param string|bool $wiki Wiki identifier accepted by wfGetLB
  * @param string|bool $cluster Cluster name accepted by LBFactory. Default: false.
  */
-function wfWaitForSlaves( $maxLag = false, $wiki = false, $cluster = false ) {
+function wfWaitForSlaves( $ifWritesSince = false, $wiki = false, $cluster = false ) {
+       // B/C: first argument used to be "max seconds of lag"; ignore such values
+       $ifWritesSince = ( $ifWritesSince > 1e9 ) ? $ifWritesSince : false;
+
        if ( $cluster !== false ) {
                $lb = wfGetLBFactory()->getExternalLB( $cluster );
        } else {
@@ -3840,7 +3814,13 @@ function wfWaitForSlaves( $maxLag = false, $wiki = false, $cluster = false ) {
        // bug 27975 - Don't try to wait for slaves if there are none
        // Prevents permission error when getting master position
        if ( $lb->getServerCount() > 1 ) {
+               if ( $ifWritesSince && !$lb->hasMasterConnection() ) {
+                       return; // assume no writes done
+               }
                $dbw = $lb->getConnection( DB_MASTER, array(), $wiki );
+               if ( $ifWritesSince && $dbw->lastDoneWrites() < $ifWritesSince ) {
+                       return; // no writes since the last wait
+               }
                $pos = $dbw->getMasterPos();
                // The DBMS may not support getMasterPos() or the whole
                // load balancer might be fake (e.g. $wgAllDBsAreLocalhost).
index 89457e8..77486b2 100644 (file)
@@ -48,7 +48,7 @@ class Hooks {
         * Attach an event handler to a given hook.
         *
         * @param string $name Name of hook
-        * @param mixed $callback Callback function to attach
+        * @param callable $callback Callback function to attach
         *
         * @since 1.18
         */
index 5262ffe..dbabbae 100644 (file)
@@ -386,7 +386,7 @@ class Html {
         * For instance, it will omit quotation marks if $wgWellFormedXml is false,
         * and will treat boolean attributes specially.
         *
-        * Attributes that should contain space-separated lists (such as 'class') array
+        * Attributes that can contain space-separated lists ('class', 'accesskey' and 'rel') array
         * values are allowed as well, which will automagically be normalized
         * and converted to a space-separated string. In addition to a numerical
         * array, the attribute value may also be an associative array. See the
@@ -413,6 +413,8 @@ class Html {
         *   A value of false means to omit the attribute.  For boolean attributes,
         *   you can omit the key, e.g., array( 'checked' ) instead of
         *   array( 'checked' => 'checked' ) or such.
+        *
+        * @throws MWException if an attribute that doesn't allow lists is set to an array
         * @return string HTML fragment that goes between element name and '>'
         *   (starting with a space if at least one attribute is output)
         */
@@ -500,6 +502,8 @@ class Html {
 
                                // Remove duplicates and create the string
                                $value = implode( ' ', array_unique( $value ) );
+                       } elseif ( is_array( $value ) ) {
+                               throw new MWException( "HTML attribute $key can not contain a list of values" );
                        }
 
                        // See the "Attributes" section in the HTML syntax part of HTML5,
index 38aa392..ebced70 100644 (file)
@@ -138,7 +138,7 @@ class HtmlFormatter {
 
                // Bail out early if nothing to do
                if ( array_reduce( $removals,
-                       function( $carry, $item ) {
+                       function ( $carry, $item ) {
                                return $carry && !$item;
                        },
                        true
index 177d023..6aab157 100644 (file)
@@ -45,7 +45,7 @@ class WikiImporter {
        function __construct( ImportStreamSource $source ) {
                $this->reader = new XMLReader();
 
-               if ( !in_array(  'uploadsource', stream_get_wrappers() ) ) {
+               if ( !in_array( 'uploadsource', stream_get_wrappers() ) ) {
                        stream_wrapper_register( 'uploadsource', 'UploadSourceAdapter' );
                }
                $id = UploadSourceAdapter::registerSource( $source );
diff --git a/includes/Init.php b/includes/Init.php
deleted file mode 100644 (file)
index d9aeb7b..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-<?php
-/**
- * Some functions that are useful during startup.
- *
- * This class previously contained some functionality related to a PHP compiler
- * called hphpc. That compiler has now been discontinued.
- *
- * 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
- */
-
-/**
- * Some functions that are useful during startup.
- *
- * This class previously contained some functionality related to a PHP compiler
- * called hphpc. That compiler has now been discontinued. All methods are now
- * deprecated.
- */
-class MWInit {
-       private static $compilerVersion;
-
-       /**
-        * @deprecated since 1.22
-        */
-       static function getCompilerVersion() {
-               return false;
-       }
-
-       /**
-        * Returns true if we are running under HipHop, whether in compiled or
-        * interpreted mode.
-        *
-        * @deprecated since 1.22
-        * @return bool
-        */
-       static function isHipHop() {
-               return wfIsHHVM();
-       }
-
-       /**
-        * Get a fully-qualified path for a source file relative to $IP.
-        * @deprecated since 1.22
-        *
-        * @param string $file
-        *
-        * @return string
-        */
-       static function interpretedPath( $file ) {
-               global $IP;
-               return "$IP/$file";
-       }
-
-       /**
-        * @deprecated since 1.22
-        * @param string $file
-        * @return string
-        */
-       static function compiledPath( $file ) {
-               global $IP;
-               return "$IP/$file";
-       }
-
-       /**
-        * @deprecated since 1.22
-        * @param string $file
-        * @return string
-        */
-       static function extCompiledPath( $file ) {
-               return false;
-       }
-
-       /**
-        * Deprecated wrapper for class_exists()
-        * @deprecated since 1.22
-        *
-        * @param string $class
-        *
-        * @return bool
-        */
-       static function classExists( $class ) {
-               return class_exists( $class );
-       }
-
-       /**
-        * Deprecated wrapper for method_exists()
-        * @deprecated since 1.22
-        *
-        * @param string $class
-        * @param string $method
-        *
-        * @return bool
-        */
-       static function methodExists( $class, $method ) {
-               return method_exists( $class, $method );
-       }
-
-       /**
-        * Deprecated wrapper for function_exists()
-        * @deprecated since 1.22
-        *
-        * @param string $function
-        *
-        * @return bool
-        */
-       static function functionExists( $function ) {
-               return function_exists( $function );
-       }
-
-       /**
-        * Deprecated wrapper for call_user_func_array()
-        * @deprecated since 1.22
-        *
-        * @param string $className
-        * @param string $methodName
-        * @param array $args
-        *
-        * @return mixed
-        */
-       static function callStaticMethod( $className, $methodName, $args ) {
-               return call_user_func_array( array( $className, $methodName ), $args );
-       }
-}
index 7d88f25..1991694 100644 (file)
@@ -1379,7 +1379,7 @@ class Linker {
                                                . '<span dir="auto">' . $auto . $post . '</span>';
                                }
                                return $comment;
-               },
+                       },
                        $comment
                );
        }
@@ -1418,7 +1418,11 @@ class Linker {
 
                                # fix up urlencoded title texts (copied from Parser::replaceInternalLinks)
                                if ( strpos( $match[1], '%' ) !== false ) {
-                                       $match[1] = str_replace( array( '<', '>' ), array( '&lt;', '&gt;' ), rawurldecode( $match[1] ) );
+                                       $match[1] = str_replace(
+                                               array( '<', '>' ),
+                                               array( '&lt;', '&gt;' ),
+                                               rawurldecode( $match[1] )
+                                       );
                                }
 
                                # Handle link renaming [[foo|text]] will show link as "text"
diff --git a/includes/MWNamespace.php b/includes/MWNamespace.php
new file mode 100644 (file)
index 0000000..392f558
--- /dev/null
@@ -0,0 +1,496 @@
+<?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
+ */
+
+/**
+ * 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
+ *
+ */
+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 = array( NS_SPECIAL, NS_USER, NS_MEDIAWIKI );
+
+       /**
+        * 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;
+       }
+
+       /**
+        * Can pages in the given namespace be moved?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public static function isMovable( $index ) {
+               global $wgAllowImageMoving;
+
+               $result = !( $index < NS_MAIN || ( $index == NS_FILE && !$wgAllowImageMoving ) );
+
+               /**
+                * @since 1.20
+                */
+               wfRunHooks( 'NamespaceIsMovable', array( $index, &$result ) );
+
+               return $result;
+       }
+
+       /**
+        * Is the given namespace is a subject (non-talk) namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        * @since 1.19
+        */
+       public static function isSubject( $index ) {
+               return !self::isTalk( $index );
+       }
+
+       /**
+        * Is the given namespace a talk namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public static 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 static function getTalk( $index ) {
+               self::isMethodValidFor( $index, __METHOD__ );
+               return self::isTalk( $index )
+                       ? $index
+                       : $index + 1;
+       }
+
+       /**
+        * 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 static function getSubject( $index ) {
+               # Handle special namespaces
+               if ( $index < NS_MAIN ) {
+                       return $index;
+               }
+
+               return self::isTalk( $index )
+                       ? $index - 1
+                       : $index;
+       }
+
+       /**
+        * 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|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;
+               }
+       }
+
+       /**
+        * Returns whether the specified namespace exists
+        *
+        * @param int $index
+        *
+        * @return bool
+        * @since 1.19
+        */
+       public static function exists( $index ) {
+               $nslist = self::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
+        * @since 1.19
+        */
+       public static 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
+        * @since 1.19
+        */
+       public static function subjectEquals( $ns1, $ns2 ) {
+               return self::getSubject( $ns1 ) == self::getSubject( $ns2 );
+       }
+
+       /**
+        * Returns array of all defined namespaces with their canonical
+        * (English) names.
+        *
+        * @param bool $rebuild Rebuild namespace list (default = false). Used for testing.
+        *
+        * @return array
+        * @since 1.17
+        */
+       public static function getCanonicalNamespaces( $rebuild = false ) {
+               static $namespaces = null;
+               if ( $namespaces === null || $rebuild ) {
+                       global $wgExtraNamespaces, $wgCanonicalNamespaceNames;
+                       $namespaces = array( NS_MAIN => '' ) + $wgCanonicalNamespaceNames;
+                       if ( is_array( $wgExtraNamespaces ) ) {
+                               $namespaces += $wgExtraNamespaces;
+                       }
+                       wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) );
+               }
+               return $namespaces;
+       }
+
+       /**
+        * Returns the canonical (English) name for a given index
+        *
+        * @param int $index Namespace index
+        * @return string|bool If no canonical definition.
+        */
+       public static function getCanonicalName( $index ) {
+               $nslist = self::getCanonicalNamespaces();
+               if ( isset( $nslist[$index] ) ) {
+                       return $nslist[$index];
+               } else {
+                       return 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
+        */
+       public static function getCanonicalIndex( $name ) {
+               static $xNamespaces = false;
+               if ( $xNamespaces === false ) {
+                       $xNamespaces = array();
+                       foreach ( self::getCanonicalNamespaces() as $i => $text ) {
+                               $xNamespaces[strtolower( $text )] = $i;
+                       }
+               }
+               if ( array_key_exists( $name, $xNamespaces ) ) {
+                       return $xNamespaces[$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.
+        * @return array
+        */
+       public static function getValidNamespaces() {
+               static $mValidNamespaces = null;
+
+               if ( is_null( $mValidNamespaces ) ) {
+                       foreach ( array_keys( self::getCanonicalNamespaces() ) as $ns ) {
+                               if ( $ns >= 0 ) {
+                                       $mValidNamespaces[] = $ns;
+                               }
+                       }
+               }
+
+               return $mValidNamespaces;
+       }
+
+       /**
+        * Can this namespace ever have a talk namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public static function canTalk( $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 static function isContent( $index ) {
+               global $wgContentNamespaces;
+               return $index == NS_MAIN || in_array( $index, $wgContentNamespaces );
+       }
+
+       /**
+        * Can pages in a namespace be watched?
+        *
+        * @param int $index
+        * @return bool
+        */
+       public static function isWatchable( $index ) {
+               return $index >= NS_MAIN;
+       }
+
+       /**
+        * Does the namespace allow subpages?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function hasSubpages( $index ) {
+               global $wgNamespacesWithSubpages;
+               return !empty( $wgNamespacesWithSubpages[$index] );
+       }
+
+       /**
+        * Get a list of all namespace indices which are considered to contain content
+        * @return array Array of namespace indices
+        */
+       public static function getContentNamespaces() {
+               global $wgContentNamespaces;
+               if ( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === array() ) {
+                       return array( 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( array( NS_MAIN ), $wgContentNamespaces );
+               } else {
+                       return $wgContentNamespaces;
+               }
+       }
+
+       /**
+        * List all namespace indices which are considered subject, aka not a talk
+        * or special namespace. See also MWNamespace::isSubject
+        *
+        * @return array Array of namespace indices
+        */
+       public static function getSubjectNamespaces() {
+               return array_filter(
+                       MWNamespace::getValidNamespaces(),
+                       'MWNamespace::isSubject'
+               );
+       }
+
+       /**
+        * List all namespace indices which are considered talks, aka not a subject
+        * or special namespace. See also MWNamespace::isTalk
+        *
+        * @return array Array of namespace indices
+        */
+       public static function getTalkNamespaces() {
+               return array_filter(
+                       MWNamespace::getValidNamespaces(),
+                       'MWNamespace::isTalk'
+               );
+       }
+
+       /**
+        * Is the namespace first-letter capitalized?
+        *
+        * @param int $index Index to check
+        * @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;
+       }
+
+       /**
+        * Does the namespace (potentially) have different aliases for different
+        * genders. Not all languages make a distinction here.
+        *
+        * @since 1.18
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function hasGenderDistinction( $index ) {
+               return $index == NS_USER || $index == NS_USER_TALK;
+       }
+
+       /**
+        * It is not possible to use pages from this namespace as template?
+        *
+        * @since 1.20
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function isNonincludable( $index ) {
+               global $wgNonincludableNamespaces;
+               return $wgNonincludableNamespaces && in_array( $index, $wgNonincludableNamespaces );
+       }
+
+       /**
+        * Get the default content model for a namespace
+        * This does not mean that all pages in that namespace have the model
+        *
+        * @since 1.21
+        * @param int $index Index to check
+        * @return null|string Default model name for the given namespace, if set
+        */
+       public static function getNamespaceContentModel( $index ) {
+               global $wgNamespaceContentModels;
+               return isset( $wgNamespaceContentModels[$index] )
+                       ? $wgNamespaceContentModels[$index]
+                       : null;
+       }
+
+       /**
+        * Determine which restriction levels it makes sense to use in a namespace,
+        * optionally filtered by a user's rights.
+        *
+        * @since 1.23
+        * @param int $index Index to check
+        * @param User $user User to check
+        * @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 = array();
+               $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 = array( '' );
+               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;
+       }
+}
diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php
new file mode 100644 (file)
index 0000000..1c245c1
--- /dev/null
@@ -0,0 +1,722 @@
+<?php
+/**
+ * Helper class for the index.php entry point.
+ *
+ * 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
+ */
+
+/**
+ * The MediaWiki class is the helper class for the index.php entry point.
+ *
+ * @internal documentation reviewed 15 Mar 2010
+ */
+class MediaWiki {
+       /**
+        * @todo Fold $output, etc, into this
+        * @var IContextSource
+        */
+       private $context;
+
+       /**
+        * @param null|WebRequest $x
+        * @return WebRequest
+        */
+       public function request( WebRequest $x = null ) {
+               $old = $this->context->getRequest();
+               $this->context->setRequest( $x );
+               return $old;
+       }
+
+       /**
+        * @param null|OutputPage $x
+        * @return OutputPage
+        */
+       public function output( OutputPage $x = null ) {
+               $old = $this->context->getOutput();
+               $this->context->setOutput( $x );
+               return $old;
+       }
+
+       /**
+        * @param IContextSource|null $context
+        */
+       public function __construct( IContextSource $context = null ) {
+               if ( !$context ) {
+                       $context = RequestContext::getMain();
+               }
+
+               $this->context = $context;
+       }
+
+       /**
+        * Parse the request to get the Title object
+        *
+        * @return Title Title object to be $wgTitle
+        */
+       private function parseTitle() {
+               global $wgContLang;
+
+               $request = $this->context->getRequest();
+               $curid = $request->getInt( 'curid' );
+               $title = $request->getVal( 'title' );
+               $action = $request->getVal( 'action', 'view' );
+
+               if ( $request->getCheck( 'search' ) ) {
+                       // Compatibility with old search URLs which didn't use Special:Search
+                       // Just check for presence here, so blank requests still
+                       // show the search page when using ugly URLs (bug 8054).
+                       $ret = SpecialPage::getTitleFor( 'Search' );
+               } elseif ( $curid ) {
+                       // URLs like this are generated by RC, because rc_title isn't always accurate
+                       $ret = Title::newFromID( $curid );
+               } else {
+                       $ret = Title::newFromURL( $title );
+                       // Alias NS_MEDIA page URLs to NS_FILE...we only use NS_MEDIA
+                       // in wikitext links to tell Parser to make a direct file link
+                       if ( !is_null( $ret ) && $ret->getNamespace() == NS_MEDIA ) {
+                               $ret = Title::makeTitle( NS_FILE, $ret->getDBkey() );
+                       }
+                       // Check variant links so that interwiki links don't have to worry
+                       // about the possible different language variants
+                       if ( count( $wgContLang->getVariants() ) > 1
+                               && !is_null( $ret ) && $ret->getArticleID() == 0
+                       ) {
+                               $wgContLang->findVariantLink( $title, $ret );
+                       }
+               }
+
+               // If title is not provided, always allow oldid and diff to set the title.
+               // If title is provided, allow oldid and diff to override the title, unless
+               // we are talking about a special page which might use these parameters for
+               // other purposes.
+               if ( $ret === null || !$ret->isSpecialPage() ) {
+                       // We can have urls with just ?diff=,?oldid= or even just ?diff=
+                       $oldid = $request->getInt( 'oldid' );
+                       $oldid = $oldid ? $oldid : $request->getInt( 'diff' );
+                       // Allow oldid to override a changed or missing title
+                       if ( $oldid ) {
+                               $rev = Revision::newFromId( $oldid );
+                               $ret = $rev ? $rev->getTitle() : $ret;
+                       }
+               }
+
+               // Use the main page as default title if nothing else has been provided
+               if ( $ret === null
+                       && strval( $title ) === ''
+                       && !$request->getCheck( 'curid' )
+                       && $action !== 'delete'
+               ) {
+                       $ret = Title::newMainPage();
+               }
+
+               if ( $ret === null || ( $ret->getDBkey() == '' && !$ret->isExternal() ) ) {
+                       $ret = SpecialPage::getTitleFor( 'Badtitle' );
+               }
+
+               return $ret;
+       }
+
+       /**
+        * Get the Title object that we'll be acting on, as specified in the WebRequest
+        * @return Title
+        */
+       public function getTitle() {
+               if ( $this->context->getTitle() === null ) {
+                       $this->context->setTitle( $this->parseTitle() );
+               }
+               return $this->context->getTitle();
+       }
+
+       /**
+        * Returns the name of the action that will be executed.
+        *
+        * @return string Action
+        */
+       public function getAction() {
+               static $action = null;
+
+               if ( $action === null ) {
+                       $action = Action::getActionName( $this->context );
+               }
+
+               return $action;
+       }
+
+       /**
+        * Performs the request.
+        * - bad titles
+        * - read restriction
+        * - local interwiki redirects
+        * - redirect loop
+        * - special pages
+        * - normal pages
+        *
+        * @throws MWException|PermissionsError|BadTitleError|HttpError
+        * @return void
+        */
+       private function performRequest() {
+               global $wgServer, $wgUsePathInfo, $wgTitle;
+
+               wfProfileIn( __METHOD__ );
+
+               $request = $this->context->getRequest();
+               $requestTitle = $title = $this->context->getTitle();
+               $output = $this->context->getOutput();
+               $user = $this->context->getUser();
+
+               if ( $request->getVal( 'printable' ) === 'yes' ) {
+                       $output->setPrintable();
+               }
+
+               $unused = null; // To pass it by reference
+               wfRunHooks( 'BeforeInitialize', array( &$title, &$unused, &$output, &$user, $request, $this ) );
+
+               // Invalid titles. Bug 21776: The interwikis must redirect even if the page name is empty.
+               if ( is_null( $title ) || ( $title->getDBkey() == '' && !$title->isExternal() )
+                       || $title->isSpecial( 'Badtitle' )
+               ) {
+                       $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) );
+                       wfProfileOut( __METHOD__ );
+                       throw new BadTitleError();
+               }
+
+               // Check user's permissions to read this page.
+               // We have to check here to catch special pages etc.
+               // We will check again in Article::view().
+               $permErrors = $title->getUserPermissionsErrors( 'read', $user );
+               if ( count( $permErrors ) ) {
+                       // Bug 32276: allowing the skin to generate output with $wgTitle or
+                       // $this->context->title set to the input title would allow anonymous users to
+                       // determine whether a page exists, potentially leaking private data. In fact, the
+                       // curid and oldid request  parameters would allow page titles to be enumerated even
+                       // when they are not guessable. So we reset the title to Special:Badtitle before the
+                       // permissions error is displayed.
+                       //
+                       // The skin mostly uses $this->context->getTitle() these days, but some extensions
+                       // still use $wgTitle.
+
+                       $badTitle = SpecialPage::getTitleFor( 'Badtitle' );
+                       $this->context->setTitle( $badTitle );
+                       $wgTitle = $badTitle;
+
+                       wfProfileOut( __METHOD__ );
+                       throw new PermissionsError( 'read', $permErrors );
+               }
+
+               $pageView = false; // was an article or special page viewed?
+
+               // Interwiki redirects
+               if ( $title->isExternal() ) {
+                       $rdfrom = $request->getVal( 'rdfrom' );
+                       if ( $rdfrom ) {
+                               $url = $title->getFullURL( array( 'rdfrom' => $rdfrom ) );
+                       } else {
+                               $query = $request->getValues();
+                               unset( $query['title'] );
+                               $url = $title->getFullURL( $query );
+                       }
+                       // Check for a redirect loop
+                       if ( !preg_match( '/^' . preg_quote( $wgServer, '/' ) . '/', $url )
+                               && $title->isLocal()
+                       ) {
+                               // 301 so google et al report the target as the actual url.
+                               $output->redirect( $url, 301 );
+                       } else {
+                               $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) );
+                               wfProfileOut( __METHOD__ );
+                               throw new BadTitleError();
+                       }
+               // Redirect loops, no title in URL, $wgUsePathInfo URLs, and URLs with a variant
+               } elseif ( $request->getVal( 'action', 'view' ) == 'view' && !$request->wasPosted()
+                       && ( $request->getVal( 'title' ) === null
+                               || $title->getPrefixedDBkey() != $request->getVal( 'title' ) )
+                       && !count( $request->getValueNames( array( 'action', 'title' ) ) )
+                       && wfRunHooks( 'TestCanonicalRedirect', array( $request, $title, $output ) )
+               ) {
+                       if ( $title->isSpecialPage() ) {
+                               list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
+                               if ( $name ) {
+                                       $title = SpecialPage::getTitleFor( $name, $subpage );
+                               }
+                       }
+                       $targetUrl = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
+                       // Redirect to canonical url, make it a 301 to allow caching
+                       if ( $targetUrl == $request->getFullRequestURL() ) {
+                               $message = "Redirect loop detected!\n\n" .
+                                       "This means the wiki got confused about what page was " .
+                                       "requested; this sometimes happens when moving a wiki " .
+                                       "to a new server or changing the server configuration.\n\n";
+
+                               if ( $wgUsePathInfo ) {
+                                       $message .= "The wiki is trying to interpret the page " .
+                                               "title from the URL path portion (PATH_INFO), which " .
+                                               "sometimes fails depending on the web server. Try " .
+                                               "setting \"\$wgUsePathInfo = false;\" in your " .
+                                               "LocalSettings.php, or check that \$wgArticlePath " .
+                                               "is correct.";
+                               } else {
+                                       $message .= "Your web server was detected as possibly not " .
+                                               "supporting URL path components (PATH_INFO) correctly; " .
+                                               "check your LocalSettings.php for a customized " .
+                                               "\$wgArticlePath setting and/or toggle \$wgUsePathInfo " .
+                                               "to true.";
+                               }
+                               throw new HttpError( 500, $message );
+                       } else {
+                               $output->setSquidMaxage( 1200 );
+                               $output->redirect( $targetUrl, '301' );
+                       }
+               // Special pages
+               } elseif ( NS_SPECIAL == $title->getNamespace() ) {
+                       $pageView = true;
+                       // Actions that need to be made when we have a special pages
+                       SpecialPageFactory::executePath( $title, $this->context );
+               } else {
+                       // ...otherwise treat it as an article view. The article
+                       // may be a redirect to another article or URL.
+                       $article = $this->initializeArticle();
+                       if ( is_object( $article ) ) {
+                               $pageView = true;
+                               $this->performAction( $article, $requestTitle );
+                       } elseif ( is_string( $article ) ) {
+                               $output->redirect( $article );
+                       } else {
+                               wfProfileOut( __METHOD__ );
+                               throw new MWException( "Shouldn't happen: MediaWiki::initializeArticle()"
+                                       . " returned neither an object nor a URL" );
+                       }
+               }
+
+               if ( $pageView ) {
+                       // Promote user to any groups they meet the criteria for
+                       $user->addAutopromoteOnceGroups( 'onView' );
+               }
+
+               wfProfileOut( __METHOD__ );
+       }
+
+       /**
+        * Initialize the main Article object for "standard" actions (view, etc)
+        * Create an Article object for the page, following redirects if needed.
+        *
+        * @return mixed An Article, or a string to redirect to another URL
+        */
+       private function initializeArticle() {
+               global $wgDisableHardRedirects;
+
+               wfProfileIn( __METHOD__ );
+
+               $title = $this->context->getTitle();
+               if ( $this->context->canUseWikiPage() ) {
+                       // Try to use request context wiki page, as there
+                       // is already data from db saved in per process
+                       // cache there from this->getAction() call.
+                       $page = $this->context->getWikiPage();
+                       $article = Article::newFromWikiPage( $page, $this->context );
+               } else {
+                       // This case should not happen, but just in case.
+                       $article = Article::newFromTitle( $title, $this->context );
+                       $this->context->setWikiPage( $article->getPage() );
+               }
+
+               // NS_MEDIAWIKI has no redirects.
+               // It is also used for CSS/JS, so performance matters here...
+               if ( $title->getNamespace() == NS_MEDIAWIKI ) {
+                       wfProfileOut( __METHOD__ );
+                       return $article;
+               }
+
+               $request = $this->context->getRequest();
+
+               // Namespace might change when using redirects
+               // Check for redirects ...
+               $action = $request->getVal( 'action', 'view' );
+               $file = ( $title->getNamespace() == NS_FILE ) ? $article->getFile() : null;
+               if ( ( $action == 'view' || $action == 'render' ) // ... for actions that show content
+                       && !$request->getVal( 'oldid' ) // ... and are not old revisions
+                       && !$request->getVal( 'diff' ) // ... and not when showing diff
+                       && $request->getVal( 'redirect' ) != 'no' // ... unless explicitly told not to
+                       // ... and the article is not a non-redirect image page with associated file
+                       && !( is_object( $file ) && $file->exists() && !$file->getRedirected() )
+               ) {
+                       // Give extensions a change to ignore/handle redirects as needed
+                       $ignoreRedirect = $target = false;
+
+                       wfRunHooks( 'InitializeArticleMaybeRedirect',
+                               array( &$title, &$request, &$ignoreRedirect, &$target, &$article ) );
+
+                       // Follow redirects only for... redirects.
+                       // If $target is set, then a hook wanted to redirect.
+                       if ( !$ignoreRedirect && ( $target || $article->isRedirect() ) ) {
+                               // Is the target already set by an extension?
+                               $target = $target ? $target : $article->followRedirect();
+                               if ( is_string( $target ) ) {
+                                       if ( !$wgDisableHardRedirects ) {
+                                               // we'll need to redirect
+                                               wfProfileOut( __METHOD__ );
+                                               return $target;
+                                       }
+                               }
+                               if ( is_object( $target ) ) {
+                                       // Rewrite environment to redirected article
+                                       $rarticle = Article::newFromTitle( $target, $this->context );
+                                       $rarticle->loadPageData();
+                                       if ( $rarticle->exists() || ( is_object( $file ) && !$file->isLocal() ) ) {
+                                               $rarticle->setRedirectedFrom( $title );
+                                               $article = $rarticle;
+                                               $this->context->setTitle( $target );
+                                               $this->context->setWikiPage( $article->getPage() );
+                                       }
+                               }
+                       } else {
+                               $this->context->setTitle( $article->getTitle() );
+                               $this->context->setWikiPage( $article->getPage() );
+                       }
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $article;
+       }
+
+       /**
+        * Perform one of the "standard" actions
+        *
+        * @param Page $page
+        * @param Title $requestTitle The original title, before any redirects were applied
+        */
+       private function performAction( Page $page, Title $requestTitle ) {
+               global $wgUseSquid, $wgSquidMaxage;
+
+               wfProfileIn( __METHOD__ );
+
+               $request = $this->context->getRequest();
+               $output = $this->context->getOutput();
+               $title = $this->context->getTitle();
+               $user = $this->context->getUser();
+
+               if ( !wfRunHooks( 'MediaWikiPerformAction',
+                               array( $output, $page, $title, $user, $request, $this ) )
+               ) {
+                       wfProfileOut( __METHOD__ );
+                       return;
+               }
+
+               $act = $this->getAction();
+
+               $action = Action::factory( $act, $page, $this->context );
+
+               if ( $action instanceof Action ) {
+                       # Let Squid cache things if we can purge them.
+                       if ( $wgUseSquid &&
+                               in_array( $request->getFullRequestURL(), $requestTitle->getSquidURLs() )
+                       ) {
+                               $output->setSquidMaxage( $wgSquidMaxage );
+                       }
+
+                       $action->show();
+                       wfProfileOut( __METHOD__ );
+                       return;
+               }
+
+               if ( wfRunHooks( 'UnknownAction', array( $request->getVal( 'action', 'view' ), $page ) ) ) {
+                       $output->setStatusCode( 404 );
+                       $output->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
+               }
+
+               wfProfileOut( __METHOD__ );
+       }
+
+       /**
+        * Run the current MediaWiki instance
+        * index.php just calls this
+        */
+       public function run() {
+               try {
+                       $this->checkMaxLag();
+                       try {
+                               $this->main();
+                       } catch ( ErrorPageError $e ) {
+                               // Bug 62091: while exceptions are convenient to bubble up GUI errors,
+                               // they are not internal application faults. As with normal requests, this
+                               // should commit, print the output, do deferred updates, jobs, and profiling.
+                               wfGetLBFactory()->commitMasterChanges();
+                               $e->report(); // display the GUI error
+                       }
+                       if ( function_exists( 'fastcgi_finish_request' ) ) {
+                               fastcgi_finish_request();
+                       }
+                       $this->triggerJobs();
+                       $this->restInPeace();
+               } catch ( Exception $e ) {
+                       MWExceptionHandler::handle( $e );
+               }
+       }
+
+       /**
+        * Checks if the request should abort due to a lagged server,
+        * for given maxlag parameter.
+        * @return bool
+        */
+       private function checkMaxLag() {
+               global $wgShowHostnames;
+
+               wfProfileIn( __METHOD__ );
+               $maxLag = $this->context->getRequest()->getVal( 'maxlag' );
+               if ( !is_null( $maxLag ) ) {
+                       list( $host, $lag ) = wfGetLB()->getMaxLag();
+                       if ( $lag > $maxLag ) {
+                               $resp = $this->context->getRequest()->response();
+                               $resp->header( 'HTTP/1.1 503 Service Unavailable' );
+                               $resp->header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
+                               $resp->header( 'X-Database-Lag: ' . intval( $lag ) );
+                               $resp->header( 'Content-Type: text/plain' );
+                               if ( $wgShowHostnames ) {
+                                       echo "Waiting for $host: $lag seconds lagged\n";
+                               } else {
+                                       echo "Waiting for a database server: $lag seconds lagged\n";
+                               }
+
+                               wfProfileOut( __METHOD__ );
+
+                               exit;
+                       }
+               }
+               wfProfileOut( __METHOD__ );
+               return true;
+       }
+
+       private function main() {
+               global $wgUseFileCache, $wgTitle, $wgUseAjax;
+
+               wfProfileIn( __METHOD__ );
+
+               $request = $this->context->getRequest();
+
+               // Send Ajax requests to the Ajax dispatcher.
+               if ( $wgUseAjax && $request->getVal( 'action', 'view' ) == 'ajax' ) {
+
+                       // Set a dummy title, because $wgTitle == null might break things
+                       $title = Title::makeTitle( NS_MAIN, 'AJAX' );
+                       $this->context->setTitle( $title );
+                       $wgTitle = $title;
+
+                       $dispatcher = new AjaxDispatcher();
+                       $dispatcher->performAction();
+                       wfProfileOut( __METHOD__ );
+                       return;
+               }
+
+               // Get title from request parameters,
+               // is set on the fly by parseTitle the first time.
+               $title = $this->getTitle();
+               $action = $this->getAction();
+               $wgTitle = $title;
+
+               // If the user has forceHTTPS set to true, or if the user
+               // is in a group requiring HTTPS, or if they have the HTTPS
+               // preference set, redirect them to HTTPS.
+               // Note: Do this after $wgTitle is setup, otherwise the hooks run from
+               // isLoggedIn() will do all sorts of weird stuff.
+               if (
+                       $request->getProtocol() == 'http' &&
+                       (
+                               $request->getCookie( 'forceHTTPS', '' ) ||
+                               // check for prefixed version for currently logged in users
+                               $request->getCookie( 'forceHTTPS' ) ||
+                               // Avoid checking the user and groups unless it's enabled.
+                               (
+                                       $this->context->getUser()->isLoggedIn()
+                                       && $this->context->getUser()->requiresHTTPS()
+                               )
+                       )
+               ) {
+                       $oldUrl = $request->getFullRequestURL();
+                       $redirUrl = preg_replace( '#^http://#', 'https://', $oldUrl );
+
+                       // ATTENTION: This hook is likely to be removed soon due to overall design of the system.
+                       if ( wfRunHooks( 'BeforeHttpsRedirect', array( $this->context, &$redirUrl ) ) ) {
+
+                               if ( $request->wasPosted() ) {
+                                       // This is weird and we'd hope it almost never happens. This
+                                       // means that a POST came in via HTTP and policy requires us
+                                       // redirecting to HTTPS. It's likely such a request is going
+                                       // to fail due to post data being lost, but let's try anyway
+                                       // and just log the instance.
+                                       //
+                                       // @todo FIXME: See if we could issue a 307 or 308 here, need
+                                       // to see how clients (automated & browser) behave when we do
+                                       wfDebugLog( 'RedirectedPosts', "Redirected from HTTP to HTTPS: $oldUrl" );
+                               }
+                               // Setup dummy Title, otherwise OutputPage::redirect will fail
+                               $title = Title::newFromText( NS_MAIN, 'REDIR' );
+                               $this->context->setTitle( $title );
+                               $output = $this->context->getOutput();
+                               // Since we only do this redir to change proto, always send a vary header
+                               $output->addVaryHeader( 'X-Forwarded-Proto' );
+                               $output->redirect( $redirUrl );
+                               $output->output();
+                               wfProfileOut( __METHOD__ );
+                               return;
+                       }
+               }
+
+               if ( $wgUseFileCache && $title->getNamespace() >= 0 ) {
+                       wfProfileIn( 'main-try-filecache' );
+                       if ( HTMLFileCache::useFileCache( $this->context ) ) {
+                               // Try low-level file cache hit
+                               $cache = HTMLFileCache::newFromTitle( $title, $action );
+                               if ( $cache->isCacheGood( /* Assume up to date */ ) ) {
+                                       // Check incoming headers to see if client has this cached
+                                       $timestamp = $cache->cacheTimestamp();
+                                       if ( !$this->context->getOutput()->checkLastModified( $timestamp ) ) {
+                                               $cache->loadFromFileCache( $this->context );
+                                       }
+                                       // Do any stats increment/watchlist stuff
+                                       // Assume we're viewing the latest revision (this should always be the case with file cache)
+                                       $this->context->getWikiPage()->doViewUpdates( $this->context->getUser() );
+                                       // Tell OutputPage that output is taken care of
+                                       $this->context->getOutput()->disable();
+                                       wfProfileOut( 'main-try-filecache' );
+                                       wfProfileOut( __METHOD__ );
+                                       return;
+                               }
+                       }
+                       wfProfileOut( 'main-try-filecache' );
+               }
+
+               // Actually do the work of the request and build up any output
+               $this->performRequest();
+
+               // Either all DB and deferred updates should happen or none.
+               // The later should not be cancelled due to client disconnect.
+               ignore_user_abort( true );
+               // Now commit any transactions, so that unreported errors after
+               // output() don't roll back the whole DB transaction
+               wfGetLBFactory()->commitMasterChanges();
+
+               // Output everything!
+               $this->context->getOutput()->output();
+
+               wfProfileOut( __METHOD__ );
+       }
+
+       /**
+        * Ends this task peacefully
+        */
+       public function restInPeace() {
+               // Do any deferred jobs
+               DeferredUpdates::doUpdates( 'commit' );
+
+               // Log profiling data, e.g. in the database or UDP
+               wfLogProfilingData();
+
+               // Commit and close up!
+               $factory = wfGetLBFactory();
+               $factory->commitMasterChanges();
+               $factory->shutdown();
+
+               wfDebug( "Request ended normally\n" );
+       }
+
+       /**
+        * Potentially open a socket and sent an HTTP request back to the server
+        * to run a specified number of jobs. This registers a callback to cleanup
+        * the socket once it's done.
+        */
+       protected function triggerJobs() {
+               global $wgJobRunRate, $wgServer, $wgRunJobsAsync;
+
+               if ( $wgJobRunRate <= 0 || wfReadOnly() ) {
+                       return;
+               } elseif ( $this->getTitle()->isSpecial( 'RunJobs' ) ) {
+                       return; // recursion guard
+               }
+
+               $section = new ProfileSection( __METHOD__ );
+
+               if ( $wgJobRunRate < 1 ) {
+                       $max = mt_getrandmax();
+                       if ( mt_rand( 0, $max ) > $max * $wgJobRunRate ) {
+                               return; // the higher $wgJobRunRate, the less likely we return here
+                       }
+                       $n = 1;
+               } else {
+                       $n = intval( $wgJobRunRate );
+               }
+
+               if ( !$wgRunJobsAsync ) {
+                       // If running jobs asynchronously has been disabled, run the job here
+                       // while the user waits
+                       SpecialRunJobs::executeJobs( $n );
+                       return;
+               }
+
+               try {
+                       if ( !JobQueueGroup::singleton()->queuesHaveJobs( JobQueueGroup::TYPE_DEFAULT ) ) {
+                               return; // do not send request if there are probably no jobs
+                       }
+               } catch ( JobQueueError $e ) {
+                       MWExceptionHandler::logException( $e );
+                       return; // do not make the site unavailable
+               }
+
+               $query = array( 'title' => 'Special:RunJobs',
+                       'tasks' => 'jobs', 'maxjobs' => $n, 'sigexpiry' => time() + 5 );
+               $query['signature'] = SpecialRunJobs::getQuerySignature( $query );
+
+               $errno = $errstr = null;
+               $info = wfParseUrl( $wgServer );
+               wfSuppressWarnings();
+               $sock = fsockopen(
+                       $info['host'],
+                       isset( $info['port'] ) ? $info['port'] : 80,
+                       $errno,
+                       $errstr,
+                       // If it takes more than 100ms to connect to ourselves there
+                       // is a problem elsewhere.
+                       0.1
+               );
+               wfRestoreWarnings();
+               if ( !$sock ) {
+                       wfDebugLog( 'runJobs', "Failed to start cron API (socket error $errno): $errstr\n" );
+                       // Fall back to running the job here while the user waits
+                       SpecialRunJobs::executeJobs( $n );
+                       return;
+               }
+
+               $url = wfAppendQuery( wfScript( 'index' ), $query );
+               $req = "POST $url HTTP/1.1\r\nHost: {$info['host']}\r\nConnection: Close\r\n\r\n";
+
+               wfDebugLog( 'runJobs', "Running $n job(s) via '$url'\n" );
+               // Send a cron API request to be performed in the background.
+               // Give up if this takes too long to send (which should be rare).
+               stream_set_timeout( $sock, 1 );
+               $bytes = fwrite( $sock, $req );
+               if ( $bytes !== strlen( $req ) ) {
+                       wfDebugLog( 'runJobs', "Failed to start cron API (socket write error)\n" );
+               } else {
+                       // Do not wait for the response (the script should handle client aborts).
+                       // Make sure that we don't close before that script reaches ignore_user_abort().
+                       $status = fgets( $sock );
+                       if ( !preg_match( '#^HTTP/\d\.\d 202 #', $status ) ) {
+                               wfDebugLog( 'runJobs', "Failed to start cron API: received '$status'\n" );
+                       }
+               }
+               fclose( $sock );
+       }
+}
index 826d55b..950bcd5 100644 (file)
@@ -995,7 +995,7 @@ class Message {
         * @throws MWException If message key array is empty.
         */
        protected function fetchMessage() {
-               if ( !isset( $this->message ) ) {
+               if ( $this->message === null ) {
                        $cache = MessageCache::singleton();
                        if ( is_array( $this->key ) ) {
                                if ( !count( $this->key ) ) {
@@ -1054,7 +1054,7 @@ class RawMessage extends Message {
         */
        public function fetchMessage() {
                // Just in case the message is unset somewhere.
-               if ( !isset( $this->message ) ) {
+               if ( $this->message === null ) {
                        $this->message = $this->key;
                }
                return $this->message;
index c2ac186..b4d3ab1 100644 (file)
@@ -164,6 +164,14 @@ class MimeMagic {
         */
        protected $mIEAnalyzer;
 
+       /** @var string Extra MIME types, set for example by media handling extensions
+        */
+       private $mExtraTypes = '';
+
+       /** @var string Extra MIME info, set for example by media handling extensions
+        */
+       private $mExtraInfo = '';
+
        /** @var MimeMagic The singleton instance
         */
        private static $instance = null;
@@ -179,6 +187,9 @@ class MimeMagic {
 
                global $wgMimeTypeFile, $IP;
 
+               # Allow media handling extensions adding MIME-types and MIME-info
+               wfRunHooks( 'MimeMagicInit', array( $this ) );
+
                $types = MM_WELL_KNOWN_MIME_TYPES;
 
                if ( $wgMimeTypeFile == 'includes/mime.types' ) {
@@ -197,11 +208,13 @@ class MimeMagic {
                        wfDebug( __METHOD__ . ": no mime types file defined, using build-ins only.\n" );
                }
 
+               $types .= "\n" . $this->mExtraTypes;
+
                $types = str_replace( array( "\r\n", "\n\r", "\n\n", "\r\r", "\r" ), "\n", $types );
                $types = str_replace( "\t", " ", $types );
 
                $this->mMimeToExt = array();
-               $this->mToMime = array();
+               $this->mExtToMime = array();
 
                $lines = explode( "\n", $types );
                foreach ( $lines as $s ) {
@@ -272,6 +285,8 @@ class MimeMagic {
                        wfDebug( __METHOD__ . ": no mime info file defined, using build-ins only.\n" );
                }
 
+               $info .= "\n" . $this->mExtraInfo;
+
                $info = str_replace( array( "\r\n", "\n\r", "\n\n", "\r\r", "\r" ), "\n", $info );
                $info = str_replace( "\t", " ", $info );
 
@@ -342,6 +357,26 @@ class MimeMagic {
                return self::$instance;
        }
 
+       /**
+        * Adds to the list mapping MIME to file extensions.
+        * As an extension author, you are encouraged to submit patches to
+        * MediaWiki's core to add new MIME types to mime.types.
+        * @param string $types
+        */
+       public function addExtraTypes( $types ) {
+               $this->mExtraTypes .= "\n" . $types;
+       }
+
+       /**
+        * Adds to the list mapping MIME to media type.
+        * As an extension author, you are encouraged to submit patches to
+        * MediaWiki's core to add new MIME info to mime.info.
+        * @param string $info
+        */
+       public function addExtraInfo( $info ) {
+               $this->mExtraInfo .= "\n" . $info;
+       }
+
        /**
         * Returns a list of file extensions for a given mime type as a space
         * separated string or null if the mime type was unrecognized. Resolves
@@ -485,14 +520,6 @@ class MimeMagic {
         * by looking at the file extension. Typically, this method would be called on the
         * result of guessMimeType().
         *
-        * Currently, this method does the following:
-        *
-        * If $mime is "unknown/unknown" and isRecognizableExtension( $ext ) returns false,
-        * return the result of guessTypesForExtension($ext).
-        *
-        * If $mime is "application/x-opc+zip" and isMatchingExtension( $ext, $mime )
-        * gives true, return the result of guessTypesForExtension($ext).
-        *
         * @param string $mime The mime type, typically guessed from a file's content.
         * @param string $ext The file extension, as taken from the file name
         *
@@ -518,8 +545,17 @@ class MimeMagic {
                                        ".$ext is not a known OPC extension.\n" );
                                $mime = 'application/zip';
                        }
+               } elseif ( $mime === 'text/plain' && $this->findMediaType( ".$ext" ) === MEDIATYPE_TEXT ) {
+                       // Textual types are sometimes not recognized properly.
+                       // If detected as text/plain, and has an extension which is textual
+                       // improve to the extension's type. For example, csv and json are often
+                       // misdetected as text/plain.
+                       $mime = $this->guessTypesForExtension( $ext );
                }
 
+               # Media handling extensions can improve the MIME detected
+               wfRunHooks( 'MimeMagicImproveFromExtension', array( $this, $ext, &$mime ) );
+
                if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
                        $mime = $this->mMimeTypeAliases[$mime];
                }
@@ -746,7 +782,17 @@ class MimeMagic {
                        return 'image/vnd.djvu';
                }
 
-               return false;
+               # Media handling extensions can guess the MIME by content
+               # It's intentionally here so that if core is wrong about a type (false positive),
+               # people will hopefully nag and submit patches :)
+               $mime = false;
+               # Some strings by reference for performance - assuming well-behaved hooks
+               wfRunHooks(
+                       'MimeMagicGuessFromContent',
+                       array( $this, &$head, &$tail, $file, &$mime )
+               );
+
+               return $mime;
        }
 
        /**
diff --git a/includes/Namespace.php b/includes/Namespace.php
deleted file mode 100644 (file)
index 4edddbc..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-<?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
- */
-
-/**
- * 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
- *
- */
-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 = array( NS_SPECIAL, NS_USER, NS_MEDIAWIKI );
-
-       /**
-        * 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;
-       }
-
-       /**
-        * Can pages in the given namespace be moved?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        */
-       public static function isMovable( $index ) {
-               global $wgAllowImageMoving;
-
-               $result = !( $index < NS_MAIN || ( $index == NS_FILE && !$wgAllowImageMoving ) );
-
-               /**
-                * @since 1.20
-                */
-               wfRunHooks( 'NamespaceIsMovable', array( $index, &$result ) );
-
-               return $result;
-       }
-
-       /**
-        * Is the given namespace is a subject (non-talk) namespace?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        * @since 1.19
-        */
-       public static function isSubject( $index ) {
-               return !self::isTalk( $index );
-       }
-
-       /**
-        * @see self::isSubject
-        * @deprecated since 1.19 Please use the more consistently named isSubject
-        * @return bool
-        */
-       public static function isMain( $index ) {
-               wfDeprecated( __METHOD__, '1.19' );
-               return self::isSubject( $index );
-       }
-
-       /**
-        * Is the given namespace a talk namespace?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        */
-       public static 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 static function getTalk( $index ) {
-               self::isMethodValidFor( $index, __METHOD__ );
-               return self::isTalk( $index )
-                       ? $index
-                       : $index + 1;
-       }
-
-       /**
-        * 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 static function getSubject( $index ) {
-               # Handle special namespaces
-               if ( $index < NS_MAIN ) {
-                       return $index;
-               }
-
-               return self::isTalk( $index )
-                       ? $index - 1
-                       : $index;
-       }
-
-       /**
-        * 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|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;
-               }
-       }
-
-       /**
-        * Returns whether the specified namespace exists
-        *
-        * @param int $index
-        *
-        * @return bool
-        * @since 1.19
-        */
-       public static function exists( $index ) {
-               $nslist = self::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
-        * @since 1.19
-        */
-       public static 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
-        * @since 1.19
-        */
-       public static function subjectEquals( $ns1, $ns2 ) {
-               return self::getSubject( $ns1 ) == self::getSubject( $ns2 );
-       }
-
-       /**
-        * Returns array of all defined namespaces with their canonical
-        * (English) names.
-        *
-        * @param bool $rebuild Rebuild namespace list (default = false). Used for testing.
-        *
-        * @return array
-        * @since 1.17
-        */
-       public static function getCanonicalNamespaces( $rebuild = false ) {
-               static $namespaces = null;
-               if ( $namespaces === null || $rebuild ) {
-                       global $wgExtraNamespaces, $wgCanonicalNamespaceNames;
-                       $namespaces = array( NS_MAIN => '' ) + $wgCanonicalNamespaceNames;
-                       if ( is_array( $wgExtraNamespaces ) ) {
-                               $namespaces += $wgExtraNamespaces;
-                       }
-                       wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) );
-               }
-               return $namespaces;
-       }
-
-       /**
-        * Returns the canonical (English) name for a given index
-        *
-        * @param int $index Namespace index
-        * @return string|bool If no canonical definition.
-        */
-       public static function getCanonicalName( $index ) {
-               $nslist = self::getCanonicalNamespaces();
-               if ( isset( $nslist[$index] ) ) {
-                       return $nslist[$index];
-               } else {
-                       return 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
-        */
-       public static function getCanonicalIndex( $name ) {
-               static $xNamespaces = false;
-               if ( $xNamespaces === false ) {
-                       $xNamespaces = array();
-                       foreach ( self::getCanonicalNamespaces() as $i => $text ) {
-                               $xNamespaces[strtolower( $text )] = $i;
-                       }
-               }
-               if ( array_key_exists( $name, $xNamespaces ) ) {
-                       return $xNamespaces[$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.
-        * @return array
-        */
-       public static function getValidNamespaces() {
-               static $mValidNamespaces = null;
-
-               if ( is_null( $mValidNamespaces ) ) {
-                       foreach ( array_keys( self::getCanonicalNamespaces() ) as $ns ) {
-                               if ( $ns >= 0 ) {
-                                       $mValidNamespaces[] = $ns;
-                               }
-                       }
-               }
-
-               return $mValidNamespaces;
-       }
-
-       /**
-        * Can this namespace ever have a talk namespace?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        */
-       public static function canTalk( $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 static function isContent( $index ) {
-               global $wgContentNamespaces;
-               return $index == NS_MAIN || in_array( $index, $wgContentNamespaces );
-       }
-
-       /**
-        * Can pages in a namespace be watched?
-        *
-        * @param int $index
-        * @return bool
-        */
-       public static function isWatchable( $index ) {
-               return $index >= NS_MAIN;
-       }
-
-       /**
-        * Does the namespace allow subpages?
-        *
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function hasSubpages( $index ) {
-               global $wgNamespacesWithSubpages;
-               return !empty( $wgNamespacesWithSubpages[$index] );
-       }
-
-       /**
-        * Get a list of all namespace indices which are considered to contain content
-        * @return array Array of namespace indices
-        */
-       public static function getContentNamespaces() {
-               global $wgContentNamespaces;
-               if ( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === array() ) {
-                       return array( 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( array( NS_MAIN ), $wgContentNamespaces );
-               } else {
-                       return $wgContentNamespaces;
-               }
-       }
-
-       /**
-        * List all namespace indices which are considered subject, aka not a talk
-        * or special namespace. See also MWNamespace::isSubject
-        *
-        * @return array Array of namespace indices
-        */
-       public static function getSubjectNamespaces() {
-               return array_filter(
-                       MWNamespace::getValidNamespaces(),
-                       'MWNamespace::isSubject'
-               );
-       }
-
-       /**
-        * List all namespace indices which are considered talks, aka not a subject
-        * or special namespace. See also MWNamespace::isTalk
-        *
-        * @return array Array of namespace indices
-        */
-       public static function getTalkNamespaces() {
-               return array_filter(
-                       MWNamespace::getValidNamespaces(),
-                       'MWNamespace::isTalk'
-               );
-       }
-
-       /**
-        * Is the namespace first-letter capitalized?
-        *
-        * @param int $index Index to check
-        * @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;
-       }
-
-       /**
-        * Does the namespace (potentially) have different aliases for different
-        * genders. Not all languages make a distinction here.
-        *
-        * @since 1.18
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function hasGenderDistinction( $index ) {
-               return $index == NS_USER || $index == NS_USER_TALK;
-       }
-
-       /**
-        * It is not possible to use pages from this namespace as template?
-        *
-        * @since 1.20
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function isNonincludable( $index ) {
-               global $wgNonincludableNamespaces;
-               return $wgNonincludableNamespaces && in_array( $index, $wgNonincludableNamespaces );
-       }
-
-       /**
-        * Get the default content model for a namespace
-        * This does not mean that all pages in that namespace have the model
-        *
-        * @since 1.21
-        * @param int $index Index to check
-        * @return null|string Default model name for the given namespace, if set
-        */
-       public static function getNamespaceContentModel( $index ) {
-               global $wgNamespaceContentModels;
-               return isset( $wgNamespaceContentModels[$index] )
-                       ? $wgNamespaceContentModels[$index]
-                       : null;
-       }
-
-       /**
-        * Determine which restriction levels it makes sense to use in a namespace,
-        * optionally filtered by a user's rights.
-        *
-        * @since 1.23
-        * @param int $index Index to check
-        * @param User $user User to check
-        * @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 = array();
-               $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 = array( '' );
-               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;
-       }
-}
index 2a96891..fbdde64 100644 (file)
@@ -885,10 +885,7 @@ class OutputPage extends ContextSource {
         * @return string
         */
        public function getPageTitleActionText() {
-               if ( isset( $this->mPageTitleActionText ) ) {
-                       return $this->mPageTitleActionText;
-               }
-               return '';
+               return $this->mPageTitleActionText;
        }
 
        /**
@@ -1290,6 +1287,9 @@ class OutputPage extends ContextSource {
                        foreach ( $categories as $category => $type ) {
                                $origcategory = $category;
                                $title = Title::makeTitleSafe( NS_CATEGORY, $category );
+                               if ( !$title ) {
+                                       continue;
+                               }
                                $wgContLang->findVariantLink( $category, $title, true );
                                if ( $category != $origcategory ) {
                                        if ( array_key_exists( $category, $categories ) ) {
@@ -1345,18 +1345,6 @@ class OutputPage extends ContextSource {
                );
        }
 
-       /**
-        * Return whether user JavaScript is allowed for this page
-        * @deprecated since 1.18 Load modules with ResourceLoader, and origin and
-        *     trustworthiness is identified and enforced automagically.
-        * @return bool
-        */
-       public function isUserJsAllowed() {
-               wfDeprecated( __METHOD__, '1.18' );
-               return $this->getAllowedModules( ResourceLoaderModule::TYPE_SCRIPTS ) >=
-                       ResourceLoaderModule::ORIGIN_USER_INDIVIDUAL;
-       }
-
        /**
         * Show what level of JavaScript / CSS untrustworthiness is allowed on this page
         * @see ResourceLoaderModule::$origin
@@ -2069,26 +2057,13 @@ class OutputPage extends ContextSource {
                }
        }
 
-       /**
-        * Get the message associated with the HTTP response code $code
-        *
-        * @param int $code Status code
-        * @return string|null Message or null if $code is not in the list of messages
-        *
-        * @deprecated since 1.18 Use HttpStatus::getMessage() instead.
-        */
-       public static function getStatusMessage( $code ) {
-               wfDeprecated( __METHOD__, '1.18' );
-               return HttpStatus::getMessage( $code );
-       }
-
        /**
         * Finally, all the text has been munged and accumulated into
         * the object, let's actually output it:
         */
        public function output() {
                global $wgLanguageCode, $wgDebugRedirects, $wgMimeType, $wgVaryOnXFP,
-                       $wgUseAjax, $wgResponsiveImages;
+                       $wgResponsiveImages;
 
                if ( $this->mDoNothing ) {
                        return;
@@ -2179,10 +2154,6 @@ class OutputPage extends ContextSource {
                                $this->addModules( $group );
                        }
                        MWDebug::addModules( $this );
-                       if ( $wgUseAjax ) {
-                               // FIXME: deprecate? - not clear why this is useful
-                               wfRunHooks( 'AjaxAddScript', array( &$this ) );
-                       }
 
                        // Hook that allows last minute changes to the output page, e.g.
                        // adding of CSS or Javascript by extensions.
@@ -2746,8 +2717,8 @@ $templates
                        $extraQuery['target'] = $this->mTarget;
                }
 
-               // Create keyed-by-group list of module objects from modules list
-               $groups = array();
+               // Create keyed-by-source and then keyed-by-group list of module objects from modules list
+               $sortedModules = array();
                $resourceLoader = $this->getResourceLoader();
                foreach ( $modules as $name ) {
                        $module = $resourceLoader->getModule( $name );
@@ -2762,136 +2733,126 @@ $templates
                                continue;
                        }
 
-                       $group = $module->getGroup();
-                       if ( !isset( $groups[$group] ) ) {
-                               $groups[$group] = array();
-                       }
-                       $groups[$group][$name] = $module;
+                       $sortedModules[$module->getSource()][$module->getGroup()][$name] = $module;
                }
 
-               foreach ( $groups as $group => $grpModules ) {
-                       // Special handling for user-specific groups
-                       $user = null;
-                       if ( ( $group === 'user' || $group === 'private' ) && $this->getUser()->isLoggedIn() ) {
-                               $user = $this->getUser()->getName();
-                       }
+               foreach ( $sortedModules as $source => $groups ) {
+                       foreach ( $groups as $group => $grpModules ) {
+                               // Special handling for user-specific groups
+                               $user = null;
+                               if ( ( $group === 'user' || $group === 'private' ) && $this->getUser()->isLoggedIn() ) {
+                                       $user = $this->getUser()->getName();
+                               }
 
-                       // Create a fake request based on the one we are about to make so modules return
-                       // correct timestamp and emptiness data
-                       $query = ResourceLoader::makeLoaderQuery(
-                               array(), // modules; not determined yet
-                               $this->getLanguage()->getCode(),
-                               $this->getSkin()->getSkinName(),
-                               $user,
-                               null, // version; not determined yet
-                               ResourceLoader::inDebugMode(),
-                               $only === ResourceLoaderModule::TYPE_COMBINED ? null : $only,
-                               $this->isPrintable(),
-                               $this->getRequest()->getBool( 'handheld' ),
-                               $extraQuery
-                       );
-                       $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
-
-                       // Extract modules that know they're empty
-                       foreach ( $grpModules as $key => $module ) {
-                               // Inline empty modules: since they're empty, just mark them as 'ready' (bug 46857)
-                               // If we're only getting the styles, we don't need to do anything for empty modules.
-                               if ( $module->isKnownEmpty( $context ) ) {
-                                       unset( $grpModules[$key] );
-                                       if ( $only !== ResourceLoaderModule::TYPE_STYLES ) {
-                                               $links['states'][$key] = 'ready';
+                               // Create a fake request based on the one we are about to make so modules return
+                               // correct timestamp and emptiness data
+                               $query = ResourceLoader::makeLoaderQuery(
+                                       array(), // modules; not determined yet
+                                       $this->getLanguage()->getCode(),
+                                       $this->getSkin()->getSkinName(),
+                                       $user,
+                                       null, // version; not determined yet
+                                       ResourceLoader::inDebugMode(),
+                                       $only === ResourceLoaderModule::TYPE_COMBINED ? null : $only,
+                                       $this->isPrintable(),
+                                       $this->getRequest()->getBool( 'handheld' ),
+                                       $extraQuery
+                               );
+                               $context = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
+
+                               // Extract modules that know they're empty
+                               foreach ( $grpModules as $key => $module ) {
+                                       // Inline empty modules: since they're empty, just mark them as 'ready' (bug 46857)
+                                       // If we're only getting the styles, we don't need to do anything for empty modules.
+                                       if ( $module->isKnownEmpty( $context ) ) {
+                                               unset( $grpModules[$key] );
+                                               if ( $only !== ResourceLoaderModule::TYPE_STYLES ) {
+                                                       $links['states'][$key] = 'ready';
+                                               }
                                        }
                                }
-                       }
 
-                       // If there are no non-empty modules, skip this group
-                       if ( count( $grpModules ) === 0 ) {
-                               continue;
-                       }
+                               // If there are no non-empty modules, skip this group
+                               if ( count( $grpModules ) === 0 ) {
+                                       continue;
+                               }
 
-                       // Inline private modules. These can't be loaded through load.php for security
-                       // reasons, see bug 34907. Note that these modules should be loaded from
-                       // getHeadScripts() before the first loader call. Otherwise other modules can't
-                       // properly use them as dependencies (bug 30914)
-                       if ( $group === 'private' ) {
-                               if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
-                                       $links['html'] .= Html::inlineStyle(
-                                               $resourceLoader->makeModuleResponse( $context, $grpModules )
-                                       );
-                               } else {
-                                       $links['html'] .= Html::inlineScript(
-                                               ResourceLoader::makeLoaderConditionalScript(
+                               // Inline private modules. These can't be loaded through load.php for security
+                               // reasons, see bug 34907. Note that these modules should be loaded from
+                               // getHeadScripts() before the first loader call. Otherwise other modules can't
+                               // properly use them as dependencies (bug 30914)
+                               if ( $group === 'private' ) {
+                                       if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
+                                               $links['html'] .= Html::inlineStyle(
                                                        $resourceLoader->makeModuleResponse( $context, $grpModules )
-                                               )
-                                       );
+                                               );
+                                       } else {
+                                               $links['html'] .= Html::inlineScript(
+                                                       ResourceLoader::makeLoaderConditionalScript(
+                                                               $resourceLoader->makeModuleResponse( $context, $grpModules )
+                                                       )
+                                               );
+                                       }
+                                       $links['html'] .= "\n";
+                                       continue;
                                }
-                               $links['html'] .= "\n";
-                               continue;
-                       }
 
-                       // Special handling for the user group; because users might change their stuff
-                       // on-wiki like user pages, or user preferences; we need to find the highest
-                       // timestamp of these user-changeable modules so we can ensure cache misses on change
-                       // This should NOT be done for the site group (bug 27564) because anons get that too
-                       // and we shouldn't be putting timestamps in Squid-cached HTML
-                       $version = null;
-                       if ( $group === 'user' ) {
-                               // Get the maximum timestamp
-                               $timestamp = 1;
-                               foreach ( $grpModules as $module ) {
-                                       $timestamp = max( $timestamp, $module->getModifiedTime( $context ) );
+                               // Special handling for the user group; because users might change their stuff
+                               // on-wiki like user pages, or user preferences; we need to find the highest
+                               // timestamp of these user-changeable modules so we can ensure cache misses on change
+                               // This should NOT be done for the site group (bug 27564) because anons get that too
+                               // and we shouldn't be putting timestamps in Squid-cached HTML
+                               $version = null;
+                               if ( $group === 'user' ) {
+                                       // Get the maximum timestamp
+                                       $timestamp = 1;
+                                       foreach ( $grpModules as $module ) {
+                                               $timestamp = max( $timestamp, $module->getModifiedTime( $context ) );
+                                       }
+                                       // Add a version parameter so cache will break when things change
+                                       $query['version'] = wfTimestamp( TS_ISO_8601_BASIC, $timestamp );
                                }
-                               // Add a version parameter so cache will break when things change
-                               $version = wfTimestamp( TS_ISO_8601_BASIC, $timestamp );
-                       }
 
-                       $url = ResourceLoader::makeLoaderURL(
-                               array_keys( $grpModules ),
-                               $this->getLanguage()->getCode(),
-                               $this->getSkin()->getSkinName(),
-                               $user,
-                               $version,
-                               ResourceLoader::inDebugMode(),
-                               $only === ResourceLoaderModule::TYPE_COMBINED ? null : $only,
-                               $this->isPrintable(),
-                               $this->getRequest()->getBool( 'handheld' ),
-                               $extraQuery
-                       );
-                       if ( $useESI && $wgResourceLoaderUseESI ) {
-                               $esi = Xml::element( 'esi:include', array( 'src' => $url ) );
-                               if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
-                                       $link = Html::inlineStyle( $esi );
-                               } else {
-                                       $link = Html::inlineScript( $esi );
-                               }
-                       } else {
-                               // Automatically select style/script elements
-                               if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
-                                       $link = Html::linkedStyle( $url );
-                               } elseif ( $loadCall ) {
-                                       $link = Html::inlineScript(
-                                               ResourceLoader::makeLoaderConditionalScript(
-                                                       Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) )
-                                               )
-                                       );
+                               $query['modules'] = ResourceLoader::makePackedModulesString( array_keys( $grpModules ) );
+                               $moduleContext = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
+                               $url = $resourceLoader->createLoaderURL( $source, $moduleContext, $extraQuery );
+
+                               if ( $useESI && $wgResourceLoaderUseESI ) {
+                                       $esi = Xml::element( 'esi:include', array( 'src' => $url ) );
+                                       if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
+                                               $link = Html::inlineStyle( $esi );
+                                       } else {
+                                               $link = Html::inlineScript( $esi );
+                                       }
                                } else {
-                                       $link = Html::linkedScript( $url );
-
-                                       // For modules requested directly in the html via <link> or <script>,
-                                       // tell mw.loader they are being loading to prevent duplicate requests.
-                                       foreach ( $grpModules as $key => $module ) {
-                                               // Don't output state=loading for the startup module..
-                                               if ( $key !== 'startup' ) {
-                                                       $links['states'][$key] = 'loading';
+                                       // Automatically select style/script elements
+                                       if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
+                                               $link = Html::linkedStyle( $url );
+                                       } elseif ( $loadCall ) {
+                                               $link = Html::inlineScript(
+                                                       ResourceLoader::makeLoaderConditionalScript(
+                                                               Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) )
+                                                       )
+                                               );
+                                       } else {
+                                               $link = Html::linkedScript( $url );
+
+                                               // For modules requested directly in the html via <link> or <script>,
+                                               // tell mw.loader they are being loading to prevent duplicate requests.
+                                               foreach ( $grpModules as $key => $module ) {
+                                                       // Don't output state=loading for the startup module..
+                                                       if ( $key !== 'startup' ) {
+                                                               $links['states'][$key] = 'loading';
+                                                       }
                                                }
                                        }
                                }
-                       }
 
-                       if ( $group == 'noscript' ) {
-                               $links['html'] .= Html::rawElement( 'noscript', array(), $link ) . "\n";
-                       } else {
-                               $links['html'] .= $link . "\n";
+                               if ( $group == 'noscript' ) {
+                                       $links['html'] .= Html::rawElement( 'noscript', array(), $link ) . "\n";
+                               } else {
+                                       $links['html'] .= $link . "\n";
+                               }
                        }
                }
 
@@ -2937,7 +2898,7 @@ $templates
 
                // Startup - this will immediately load jquery and mediawiki modules
                $links = array();
-               $links[] = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS, true );
+               $links[] = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS, /* $useESI =  */ true );
 
                // Load config before anything else
                $links[] = Html::inlineScript(
@@ -2993,7 +2954,7 @@ $templates
         * @return string
         */
        function getScriptsForBottomQueue( $inHead ) {
-               global $wgUseSiteJs, $wgAllowUserJs;
+               global $wgAllowUserJs;
 
                // Scripts and messages "only" requests marked for bottom inclusion
                // If we're in the <head>, use load() calls rather than <script src="..."> tags
@@ -3059,6 +3020,14 @@ $templates
                        /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
                );
 
+               $modules = array();
+               wfRunHooks( 'OutputPageScriptsForBottomQueue', array( $this, &$modules ) );
+               if ( $modules ) {
+                       $links[] = $this->makeResourceLoaderLink( $modules, ResourceLoaderModule::TYPE_COMBINED,
+                               /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
+                       );
+               }
+
                return self::getHtmlFromLoaderLinks( $links );
        }
 
@@ -3112,16 +3081,13 @@ $templates
        /**
         * Get an array containing the variables to be set in mw.config in JavaScript.
         *
-        * DO NOT CALL THIS FROM OUTSIDE OF THIS CLASS OR Skin::makeGlobalVariablesScript().
-        * This is only public until that function is removed. You have been warned.
-        *
         * Do not add things here which can be evaluated in ResourceLoaderStartUpModule
         * - in other words, page-independent/site-wide variables (without state).
         * You will only be adding bloat to the html page and causing page caches to
         * have to be purged on configuration changes.
         * @return array
         */
-       public function getJSVars() {
+       private function getJSVars() {
                global $wgContLang;
 
                $curRevisionId = 0;
@@ -3559,7 +3525,7 @@ $templates
         * @return string
         */
        public function buildCssLinks() {
-               global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs, $wgContLang;
+               global $wgAllowUserCss, $wgContLang;
 
                $this->getSkin()->setupSkinUserCss( $this );
 
index 0fb3952..0f5a6fc 100644 (file)
@@ -32,6 +32,7 @@
  *   - index.php
  *   - load.php
  *   - api.php
+ *   - mw-config/index.php
  *   - cli
  *
  * @note Since we can't rely on anything, the minimum PHP versions and MW current
@@ -41,7 +42,7 @@ function wfPHPVersionError( $type ) {
        $mwVersion = '1.24';
        $minimumVersionPHP = '5.3.2';
 
-       $phpVersion = phpversion();
+       $phpVersion = PHP_VERSION;
        $protocol = isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
        $message = "MediaWiki $mwVersion requires at least "
                . "PHP version $minimumVersionPHP, you are using PHP $phpVersion.";
@@ -50,10 +51,15 @@ function wfPHPVersionError( $type ) {
                $finalOutput = "You are using PHP version $phpVersion "
                        . "but MediaWiki $mwVersion needs PHP $minimumVersionPHP or higher. ABORTING.\n"
                        . "Check if you have a newer php executable with a different name, such as php5.\n";
-       } elseif ( $type == 'index.php' ) {
+       } elseif ( $type == 'index.php' || $type == 'mw-config/index.php' ) {
                $pathinfo = pathinfo( $_SERVER['SCRIPT_NAME'] );
+               if ( $type == 'mw-config/index.php' ) {
+                       $dirname = dirname( $pathinfo['dirname'] );
+               } else {
+                       $dirname = $pathinfo['dirname'];
+               }
                $encLogo = htmlspecialchars(
-                       str_replace( '//', '/', $pathinfo['dirname'] . '/' ) .
+                       str_replace( '//', '/', $dirname . '/' ) .
                        'skins/common/images/mediawiki.png'
                );
 
index 5f05460..c7de8c1 100644 (file)
@@ -69,7 +69,7 @@ interface Pager {
  *      last page depending on the dir parameter.
  *
  *  Subclassing the pager to implement concrete functionality should be fairly
- *  simple, please see the examples in HistoryPage.php and
+ *  simple, please see the examples in HistoryAction.php and
  *  SpecialBlockList.php. You just need to override formatRow(),
  *  getQueryInfo() and getIndexField(). Don't forget to call the parent
  *  constructor if you override it.
index 081315e..b4bb6de 100644 (file)
@@ -98,6 +98,20 @@ class Preferences {
 
                wfRunHooks( 'GetPreferences', array( $user, &$defaultPreferences ) );
 
+               self::loadPreferenceValues( $user, $context, $defaultPreferences );
+               self::$defaultPreferences = $defaultPreferences;
+               return $defaultPreferences;
+       }
+
+       /**
+        * Loads existing values for a given array of preferences
+        * @throws MWException
+        * @param User $user
+        * @param IContextSource $context
+        * @param array defaultPreferences to load values for
+        * @return array|null
+        */
+       static function loadPreferenceValues( $user, $context, &$defaultPreferences ) {
                ## Remove preferences that wikis don't want to use
                global $wgHiddenPrefs;
                foreach ( $wgHiddenPrefs as $pref ) {
@@ -138,8 +152,6 @@ class Preferences {
                        }
                }
 
-               self::$defaultPreferences = $defaultPreferences;
-
                return $defaultPreferences;
        }
 
@@ -195,7 +207,7 @@ class Preferences {
         * @return void
         */
        static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
-               global $wgAuth, $wgContLang, $wgParser, $wgCookieExpiration, $wgLanguageCode,
+               global $wgAuth, $wgContLang, $wgParser, $wgLanguageCode,
                        $wgDisableLangConversion, $wgMaxSigChars,
                        $wgEnableEmail, $wgEmailConfirmToEdit, $wgEnableUserEmail, $wgEmailAuthentication,
                        $wgEnotifWatchlist, $wgEnotifUserTalk, $wgEnotifRevealEditorAddress,
@@ -738,7 +750,6 @@ class Preferences {
                        'type' => 'select',
                        'section' => 'rendering/advancedrendering',
                        'options' => $stubThresholdOptions,
-                       'size' => 20,
                        'label-raw' => $context->msg( 'stub-threshold' )->text(), // Raw HTML message. Yay?
                );
 
@@ -1463,27 +1474,6 @@ class Preferences {
                        return array( $result, 'mailerror' );
                }
        }
-
-       /**
-        * @deprecated since 1.19
-        * @param User $user
-        * @return array
-        */
-       public static function loadOldSearchNs( $user ) {
-               wfDeprecated( __METHOD__, '1.19' );
-
-               $searchableNamespaces = SearchEngine::searchableNamespaces();
-               // Back compat with old format
-               $arr = array();
-
-               foreach ( $searchableNamespaces as $ns => $name ) {
-                       if ( $user->getOption( 'searchNs' . $ns ) ) {
-                               $arr[] = $ns;
-                       }
-               }
-
-               return $arr;
-       }
 }
 
 /** Some tweaks to allow js prefs to work */
index 13696ad..f794b2a 100644 (file)
@@ -166,7 +166,9 @@ abstract class PrefixSearch {
        protected function specialSearch( $search, $limit ) {
                global $wgContLang;
 
-               list( $searchKey, $subpageSearch ) = explode( '/', $search, 2 );
+               $searchParts = explode( '/', $search, 2 );
+               $searchKey = $searchParts[0];
+               $subpageSearch = isset( $searchParts[1] ) ? $searchParts[1] : null;
 
                // Handle subpage search separately.
                if ( $subpageSearch !== null ) {
index 456e4e6..853e2cc 100644 (file)
@@ -338,20 +338,12 @@ class ProtectionForm {
         * @return string HTML form
         */
        function buildForm() {
-               global $wgUser, $wgLang, $wgOut;
-
-               $mProtectreasonother = Xml::label(
-                       wfMessage( 'protectcomment' )->text(),
-                       'wpProtectReasonSelection'
-               );
-               $mProtectreason = Xml::label(
-                       wfMessage( 'protect-otherreason' )->text(),
-                       'mwProtect-reason'
-               );
+               global $wgUser, $wgLang, $wgOut, $wgCascadingRestrictionLevels;
 
                $out = '';
                if ( !$this->disabled ) {
                        $wgOut->addModules( 'mediawiki.legacy.protect' );
+                       $wgOut->addJsConfigVars( 'wgCascadeableLevels', $wgCascadingRestrictionLevels );
                        $out .= Xml::openElement( 'form', array( 'method' => 'post',
                                'action' => $this->mTitle->getLocalURL( 'action=protect' ),
                                'id' => 'mw-Protect-Form', 'onsubmit' => 'ProtectionForm.enableUnchainedInputs(true)' ) );
@@ -362,6 +354,9 @@ class ProtectionForm {
                        Xml::openElement( 'table', array( 'id' => 'mwProtectSet' ) ) .
                        Xml::openElement( 'tbody' );
 
+               $scExpiryOptions = wfMessage( 'protect-expiry-options' )->inContentLanguage()->text();
+               $showProtectOptions = $scExpiryOptions !== '-' && !$this->disabled;
+
                // Not all languages have V_x <-> N_x relation
                foreach ( $this->mRestrictions as $action => $selected ) {
                        // Messages:
@@ -373,15 +368,6 @@ class ProtectionForm {
                        Xml::openElement( 'table', array( 'id' => "mw-protect-table-$action" ) ) .
                                "<tr><td>" . $this->buildSelector( $action, $selected ) . "</td></tr><tr><td>";
 
-                       $reasonDropDown = Xml::listDropDown( 'wpProtectReasonSelection',
-                               wfMessage( 'protect-dropdown' )->inContentLanguage()->text(),
-                               wfMessage( 'protect-otherreason-op' )->inContentLanguage()->text(),
-                               $this->mReasonSelection,
-                               'mwProtect-reason', 4 );
-                       $scExpiryOptions = wfMessage( 'protect-expiry-options' )->inContentLanguage()->text();
-
-                       $showProtectOptions = $scExpiryOptions !== '-' && !$this->disabled;
-
                        $mProtectexpiry = Xml::label(
                                wfMessage( 'protectexpiry' )->text(),
                                "mwProtectExpirySelection-$action"
@@ -482,6 +468,22 @@ class ProtectionForm {
 
                # Add manual and custom reason field/selects as well as submit
                if ( !$this->disabled ) {
+                       $mProtectreasonother = Xml::label(
+                               wfMessage( 'protectcomment' )->text(),
+                               'wpProtectReasonSelection'
+                       );
+
+                       $mProtectreason = Xml::label(
+                               wfMessage( 'protect-otherreason' )->text(),
+                               'mwProtect-reason'
+                       );
+
+                       $reasonDropDown = Xml::listDropDown( 'wpProtectReasonSelection',
+                               wfMessage( 'protect-dropdown' )->inContentLanguage()->text(),
+                               wfMessage( 'protect-otherreason-op' )->inContentLanguage()->text(),
+                               $this->mReasonSelection,
+                               'mwProtect-reason', 4 );
+
                        $out .= Xml::openElement( 'table', array( 'id' => 'mw-protect-table3' ) ) .
                                Xml::openElement( 'tbody' );
                        $out .= "
@@ -606,9 +608,6 @@ class ProtectionForm {
        }
 
        function buildCleanupScript() {
-               global $wgCascadingRestrictionLevels, $wgOut;
-
-               $cascadeableLevels = $wgCascadingRestrictionLevels;
                $options = array(
                        'tableId' => 'mwProtectSet',
                        'labelText' => wfMessage( 'protect-unchain-permissions' )->plain(),
@@ -616,8 +615,8 @@ class ProtectionForm {
                        'existingMatch' => count( array_unique( $this->mExistingExpiry ) ) === 1,
                );
 
-               $wgOut->addJsConfigVars( 'wgCascadeableLevels', $cascadeableLevels );
                $script = Xml::encodeJsCall( 'ProtectionForm.init', array( $options ) );
+
                return Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( $script ) );
        }
 
index 06f5bd0..bcd3fd8 100644 (file)
@@ -41,6 +41,11 @@ class Revision implements IDBAccessObject {
        protected $mParentId;
        protected $mComment;
        protected $mText;
+       protected $mTextId;
+
+       /**
+        * @var stdClass|null
+        */
        protected $mTextRow;
 
        /**
@@ -299,7 +304,7 @@ class Revision implements IDBAccessObject {
        private static function newFromConds( $conditions, $flags = 0 ) {
                $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
                $rev = self::loadFromConds( $db, $conditions, $flags );
-               if ( is_null( $rev ) && wfGetLB()->getServerCount() > 1 ) {
+               if ( $rev === null && wfGetLB()->getServerCount() > 1 ) {
                        if ( !( $flags & self::READ_LATEST ) ) {
                                $dbw = wfGetDB( DB_MASTER );
                                $rev = self::loadFromConds( $dbw, $conditions, $flags );
@@ -566,13 +571,13 @@ class Revision implements IDBAccessObject {
                                $this->mTitle = null;
                        }
 
-                       if ( !isset( $row->rev_content_model ) || is_null( $row->rev_content_model ) ) {
+                       if ( !isset( $row->rev_content_model ) ) {
                                $this->mContentModel = null; # determine on demand if needed
                        } else {
                                $this->mContentModel = strval( $row->rev_content_model );
                        }
 
-                       if ( !isset( $row->rev_content_format ) || is_null( $row->rev_content_format ) ) {
+                       if ( !isset( $row->rev_content_format ) ) {
                                $this->mContentFormat = null; # determine on demand if needed
                        } else {
                                $this->mContentFormat = strval( $row->rev_content_format );
@@ -652,7 +657,7 @@ class Revision implements IDBAccessObject {
                                $this->mContentHandler = null;
 
                                $this->mText = $handler->serializeContent( $row['content'], $this->getContentFormat() );
-                       } elseif ( !is_null( $this->mText ) ) {
+                       } elseif ( $this->mText !== null ) {
                                $handler = $this->getContentHandler();
                                $this->mContent = $handler->unserializeContent( $this->mText );
                        }
@@ -674,7 +679,7 @@ class Revision implements IDBAccessObject {
 
                        // If we still have no length, see it we have the text to figure it out
                        if ( !$this->mSize ) {
-                               if ( !is_null( $this->mContent ) ) {
+                               if ( $this->mContent !== null ) {
                                        $this->mSize = $this->mContent->getSize();
                                } else {
                                        #NOTE: this should never happen if we have either text or content object!
@@ -684,7 +689,7 @@ class Revision implements IDBAccessObject {
 
                        // Same for sha1
                        if ( $this->mSha1 === null ) {
-                               $this->mSha1 = is_null( $this->mText ) ? null : self::base36Sha1( $this->mText );
+                               $this->mSha1 = $this->mText === null ? null : self::base36Sha1( $this->mText );
                        }
 
                        // force lazy init
@@ -759,11 +764,11 @@ class Revision implements IDBAccessObject {
         * @return Title|null
         */
        public function getTitle() {
-               if ( isset( $this->mTitle ) ) {
+               if ( $this->mTitle !== null ) {
                        return $this->mTitle;
                }
                //rev_id is defined as NOT NULL, but this revision may not yet have been inserted.
-               if ( !is_null( $this->mId ) ) {
+               if ( $this->mId !== null ) {
                        $dbr = wfGetDB( DB_SLAVE );
                        $row = $dbr->selectRow(
                                array( 'page', 'revision' ),
@@ -776,7 +781,7 @@ class Revision implements IDBAccessObject {
                        }
                }
 
-               if ( !$this->mTitle && !is_null( $this->mPage ) && $this->mPage > 0 ) {
+               if ( !$this->mTitle && $this->mPage !== null && $this->mPage > 0 ) {
                        $this->mTitle = Title::newFromID( $this->mPage );
                }
 
@@ -1031,7 +1036,7 @@ class Revision implements IDBAccessObject {
         * @return string
         */
        public function getSerializedData() {
-               if ( is_null( $this->mText ) ) {
+               if ( $this->mText === null ) {
                        $this->mText = $this->loadText();
                }
 
@@ -1048,9 +1053,9 @@ class Revision implements IDBAccessObject {
         * @return Content|null The Revision's content, or null on failure.
         */
        protected function getContentInternal() {
-               if ( is_null( $this->mContent ) ) {
+               if ( $this->mContent === null ) {
                        // Revision is immutable. Load on demand:
-                       if ( is_null( $this->mText ) ) {
+                       if ( $this->mText === null ) {
                                $this->mText = $this->loadText();
                        }
 
@@ -1184,7 +1189,7 @@ class Revision implements IDBAccessObject {
         * @return int
         */
        private function getPreviousRevisionId( $db ) {
-               if ( is_null( $this->mPage ) ) {
+               if ( $this->mPage === null ) {
                        return 0;
                }
                # Use page_latest if ID is not given
@@ -1355,7 +1360,7 @@ class Revision implements IDBAccessObject {
                }
 
                # Record the text (or external storage URL) to the text table
-               if ( !isset( $this->mTextId ) ) {
+               if ( $this->mTextId === null ) {
                        $old_id = $dbw->nextSequenceValue( 'text_old_id_seq' );
                        $dbw->insert( 'text',
                                array(
@@ -1372,7 +1377,7 @@ class Revision implements IDBAccessObject {
                }
 
                # Record the edit in revisions
-               $rev_id = isset( $this->mId )
+               $rev_id = $this->mId !== null
                        ? $this->mId
                        : $dbw->nextSequenceValue( 'revision_rev_id_seq' );
                $row = array(
@@ -1386,10 +1391,10 @@ class Revision implements IDBAccessObject {
                        'rev_timestamp'  => $dbw->timestamp( $this->mTimestamp ),
                        'rev_deleted'    => $this->mDeleted,
                        'rev_len'        => $this->mSize,
-                       'rev_parent_id'  => is_null( $this->mParentId )
+                       'rev_parent_id'  => $this->mParentId === null
                                ? $this->getPreviousRevisionId( $dbw )
                                : $this->mParentId,
-                       'rev_sha1'       => is_null( $this->mSha1 )
+                       'rev_sha1'       => $this->mSha1 === null
                                ? Revision::base36Sha1( $this->mText )
                                : $this->mSha1,
                );
@@ -1419,7 +1424,7 @@ class Revision implements IDBAccessObject {
 
                $dbw->insert( 'revision', $row, __METHOD__ );
 
-               $this->mId = !is_null( $rev_id ) ? $rev_id : $dbw->insertId();
+               $this->mId = $rev_id !== null ? $rev_id : $dbw->insertId();
 
                wfRunHooks( 'RevisionInsertComplete', array( &$this, $data, $flags ) );
 
@@ -1508,7 +1513,7 @@ class Revision implements IDBAccessObject {
                }
 
                // If we kept data for lazy extraction, use it now...
-               if ( isset( $this->mTextRow ) ) {
+               if ( $this->mTextRow !== null ) {
                        $row = $this->mTextRow;
                        $this->mTextRow = null;
                } else {
@@ -1653,19 +1658,20 @@ class Revision implements IDBAccessObject {
         */
        public static function userCanBitfield( $bitfield, $field, User $user = null ) {
                if ( $bitfield & $field ) { // aspect is deleted
-                       if ( $bitfield & self::DELETED_RESTRICTED ) {
-                               $permission = 'suppressrevision';
-                       } elseif ( $field & self::DELETED_TEXT ) {
-                               $permission = 'deletedtext';
-                       } else {
-                               $permission = 'deletedhistory';
-                       }
-                       wfDebug( "Checking for $permission due to $field match on $bitfield\n" );
                        if ( $user === null ) {
                                global $wgUser;
                                $user = $wgUser;
                        }
-                       return $user->isAllowed( $permission );
+                       if ( $bitfield & self::DELETED_RESTRICTED ) {
+                               $permissions = array( 'suppressrevision', 'viewsuppressed' );
+                       } elseif ( $field & self::DELETED_TEXT ) {
+                               $permissions = array( 'deletedtext' );
+                       } else {
+                               $permissions = array( 'deletedhistory' );
+                       }
+                       $permissionlist = implode( ', ', $permissions );
+                       wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" );
+                       return call_user_func_array( array( $user, 'isAllowedAny' ), $permissions );
                } else {
                        return true;
                }
index 6a568c2..ec17a08 100644 (file)
@@ -383,7 +383,7 @@ class Sanitizer {
                                'h2', 'h3', 'h4', 'h5', 'h6', 'cite', 'code', 'em', 's',
                                'strike', 'strong', 'tt', 'var', 'div', 'center',
                                'blockquote', 'ol', 'ul', 'dl', 'table', 'caption', 'pre',
-                               'ruby', 'rt', 'rb', 'rp', 'p', 'span', 'abbr', 'dfn',
+                               'ruby', 'rb', 'rp', 'rt', 'rtc', 'p', 'span', 'abbr', 'dfn',
                                'kbd', 'samp', 'data', 'time', 'mark'
                        );
                        $htmlsingle = array(
@@ -1685,10 +1685,10 @@ class Sanitizer {
                        # http://www.whatwg.org/html/text-level-semantics.html#the-ruby-element
                        'ruby'       => $common,
                        # rbc
-                       # rtc
                        'rb'         => $common,
-                       'rt'         => $common, #array_merge( $common, array( 'rbspan' ) ),
                        'rp'         => $common,
+                       'rt'         => $common, #array_merge( $common, array( 'rbspan' ) ),
+                       'rtc'         => $common,
 
                        # MathML root element, where used for extensions
                        # 'title' may not be 100% valid here; it's XHTML
index 67d8da3..040aba5 100644 (file)
@@ -106,15 +106,15 @@ if ( $wgDeletedDirectory === false ) {
        $wgDeletedDirectory = "{$wgUploadDirectory}/deleted";
 }
 
-if ( isset( $wgFileStore['deleted']['directory'] ) ) {
-       $wgDeletedDirectory = $wgFileStore['deleted']['directory'];
+if ( $wgGitInfoCacheDirectory === false && $wgCacheDirectory !== false ) {
+       $wgGitInfoCacheDirectory = "{$wgCacheDirectory}/gitinfo";
 }
 
 if ( isset( $wgFooterIcons['copyright'] )
        && isset( $wgFooterIcons['copyright']['copyright'] )
        && $wgFooterIcons['copyright']['copyright'] === array()
 ) {
-       if ( isset( $wgCopyrightIcon ) && $wgCopyrightIcon ) {
+       if ( $wgCopyrightIcon ) {
                $wgFooterIcons['copyright']['copyright'] = $wgCopyrightIcon;
        } elseif ( $wgRightsIcon || $wgRightsText ) {
                $wgFooterIcons['copyright']['copyright'] = array(
@@ -169,11 +169,7 @@ $wgLockManagers[] = array(
  * Initialise $wgLocalFileRepo from backwards-compatible settings
  */
 if ( !$wgLocalFileRepo ) {
-       if ( isset( $wgFileStore['deleted']['hash'] ) ) {
-               $deletedHashLevel = $wgFileStore['deleted']['hash'];
-       } else {
-               $deletedHashLevel = $wgHashedUploadDirectory ? 3 : 0;
-       }
+       $deletedHashLevel = $wgHashedUploadDirectory ? 3 : 0;
        $wgLocalFileRepo = array(
                'class' => 'LocalRepo',
                'name' => 'local',
@@ -374,10 +370,6 @@ if ( !$wgHtml5Version && $wgAllowRdfaAttributes ) {
 // Blacklisted file extensions shouldn't appear on the "allowed" list
 $wgFileExtensions = array_values( array_diff ( $wgFileExtensions, $wgFileBlacklist ) );
 
-if ( $wgArticleCountMethod === null ) {
-       $wgArticleCountMethod = $wgUseCommaCount ? 'comma' : 'link';
-}
-
 if ( $wgInvalidateCacheOnLocalSettingsChange ) {
        // @codingStandardsIgnoreStart Generic.PHP.NoSilencedErrors.Discouraged - No GlobalFunction here yet.
        $wgCacheEpoch = max( $wgCacheEpoch, gmdate( 'YmdHis', @filemtime( "$IP/LocalSettings.php" ) ) );
@@ -623,6 +615,26 @@ $wgTitle = null;
 
 $wgDeferredUpdateList = array();
 
+// Disable all other email settings automatically if $wgEnableEmail
+// is set to false. - bug 63678
+if ( !$wgEnableEmail ) {
+       $wgAllowHTMLEmail = false;
+       $wgEmailAuthentication = false; // do not require auth if you're not sending email anyway
+       $wgEnableUserEmail = false;
+       $wgEnotifFromEditor = false;
+       $wgEnotifImpersonal = false;
+       $wgEnotifMaxRecips = 0;
+       $wgEnotifMinorEdits = false;
+       $wgEnotifRevealEditorAddress = false;
+       $wgEnotifUseJobQ = false;
+       $wgEnotifUseRealName = false;
+       $wgEnotifUserTalk = false;
+       $wgEnotifWatchlist = false;
+       unset( $wgGroupPermissions['user']['sendemail'] );
+       $wgUserEmailUseReplyTo = false;
+       $wgUsersNotifiedOnAllChanges = array();
+}
+
 wfProfileOut( $fname . '-globals' );
 wfProfileIn( $fname . '-extensions' );
 
index b99840f..b877544 100644 (file)
@@ -191,7 +191,7 @@ class SiteConfiguration {
         * @param array $params Array of parameters.
         * @return mixed The value of the setting requested.
         */
-       protected function getSetting( $settingName, $wiki, /*array*/ $params ) {
+       protected function getSetting( $settingName, $wiki, array $params ) {
                $retval = null;
                if ( array_key_exists( $settingName, $this->settings ) ) {
                        $thisSetting =& $this->settings[$settingName];
@@ -207,14 +207,14 @@ class SiteConfiguration {
                                // Do tag settings
                                foreach ( $params['tags'] as $tag ) {
                                        if ( array_key_exists( $tag, $thisSetting ) ) {
-                                               if ( isset( $retval ) && is_array( $retval ) && is_array( $thisSetting[$tag] ) ) {
+                                               if ( is_array( $retval ) && is_array( $thisSetting[$tag] ) ) {
                                                        $retval = self::arrayMerge( $retval, $thisSetting[$tag] );
                                                } else {
                                                        $retval = $thisSetting[$tag];
                                                }
                                                break 2;
                                        } elseif ( array_key_exists( "+$tag", $thisSetting ) && is_array( $thisSetting["+$tag"] ) ) {
-                                               if ( !isset( $retval ) ) {
+                                               if ( $retval === null ) {
                                                        $retval = array();
                                                }
                                                $retval = self::arrayMerge( $retval, $thisSetting["+$tag"] );
@@ -224,7 +224,7 @@ class SiteConfiguration {
                                $suffix = $params['suffix'];
                                if ( !is_null( $suffix ) ) {
                                        if ( array_key_exists( $suffix, $thisSetting ) ) {
-                                               if ( isset( $retval ) && is_array( $retval ) && is_array( $thisSetting[$suffix] ) ) {
+                                               if ( is_array( $retval ) && is_array( $thisSetting[$suffix] ) ) {
                                                        $retval = self::arrayMerge( $retval, $thisSetting[$suffix] );
                                                } else {
                                                        $retval = $thisSetting[$suffix];
@@ -233,7 +233,7 @@ class SiteConfiguration {
                                        } elseif ( array_key_exists( "+$suffix", $thisSetting )
                                                && is_array( $thisSetting["+$suffix"] )
                                        ) {
-                                               if ( !isset( $retval ) ) {
+                                               if ( $retval === null ) {
                                                        $retval = array();
                                                }
                                                $retval = self::arrayMerge( $retval, $thisSetting["+$suffix"] );
@@ -450,7 +450,7 @@ class SiteConfiguration {
         * @param array $wikiTags The tags assigned to the wiki.
         * @return array
         */
-       protected function mergeParams( $wiki, $suffix, /*array*/ $params, /*array*/ $wikiTags ) {
+       protected function mergeParams( $wiki, $suffix, array $params, array $wikiTags ) {
                $ret = $this->getWikiParams( $wiki );
 
                if ( is_null( $ret['suffix'] ) ) {
index 177e2b1..f493b7b 100644 (file)
@@ -155,10 +155,15 @@ abstract class Skin extends ContextSource {
 
                $skinNames = Skin::getSkinNames();
 
+               // Make keys lowercase for case-insensitive matching.
+               $skinNames = array_change_key_case( $skinNames, CASE_LOWER );
+               $key = strtolower( $key );
+               $default = strtolower( $wgDefaultSkin );
+
                if ( $key == '' || $key == 'default' ) {
                        // Don't return the default immediately;
                        // in a misconfiguration we need to fall back.
-                       $key = $wgDefaultSkin;
+                       $key = $default;
                }
 
                if ( isset( $skinNames[$key] ) ) {
@@ -168,7 +173,7 @@ abstract class Skin extends ContextSource {
                // Older versions of the software used a numeric setting
                // in the user preferences.
                $fallback = array(
-                       0 => $wgDefaultSkin,
+                       0 => $default,
                        2 => 'cologneblue'
                );
 
@@ -178,8 +183,8 @@ abstract class Skin extends ContextSource {
 
                if ( isset( $skinNames[$key] ) ) {
                        return $key;
-               } elseif ( isset( $skinNames[$wgDefaultSkin] ) ) {
-                       return $wgDefaultSkin;
+               } elseif ( isset( $skinNames[$default] ) ) {
+                       return $default;
                } else {
                        return 'vector';
                }
@@ -421,21 +426,6 @@ abstract class Skin extends ContextSource {
                }
        }
 
-       /**
-        * Make a "<script>" tag containing global variables
-        *
-        * @deprecated since 1.19
-        * @param mixed $unused
-        * @return string HTML fragment
-        */
-       public static function makeGlobalVariablesScript( $unused ) {
-               global $wgOut;
-
-               wfDeprecated( __METHOD__, '1.19' );
-
-               return self::makeVariablesScript( $wgOut->getJSVars() );
-       }
-
        /**
         * Get the query to generate a dynamic stylesheet
         *
@@ -825,7 +815,7 @@ abstract class Skin extends ContextSource {
         * @return string
         */
        function getCopyright( $type = 'detect' ) {
-               global $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgContLang;
+               global $wgRightsPage, $wgRightsUrl, $wgRightsText;
 
                if ( $type == 'detect' ) {
                        if ( !$this->isRevisionCurrent()
@@ -875,7 +865,7 @@ abstract class Skin extends ContextSource {
 
                $out = '';
 
-               if ( isset( $wgCopyrightIcon ) && $wgCopyrightIcon ) {
+               if ( $wgCopyrightIcon ) {
                        $out = $wgCopyrightIcon;
                } elseif ( $wgRightsIcon ) {
                        $icon = htmlspecialchars( $wgRightsIcon );
index f9799a5..bcd3532 100644 (file)
@@ -112,7 +112,6 @@ class SkinTemplate extends Skin {
         * Generates array of language links for the current page
         *
         * @return array
-        * @public
         */
        public function getLanguages() {
                global $wgHideInterlanguageLinks;
@@ -295,8 +294,7 @@ class SkinTemplate extends Skin {
         * @return QuickTemplate The template to be executed by outputPage
         */
        protected function prepareQuickTemplate() {
-               global $wgContLang, $wgScript, $wgStylePath,
-                       $wgMimeType, $wgJsMimeType, $wgXhtmlNamespaces, $wgHtml5Version,
+               global $wgContLang, $wgScript, $wgStylePath, $wgMimeType, $wgJsMimeType,
                        $wgDisableCounters, $wgSitename, $wgLogo, $wgMaxCredits,
                        $wgShowCreditsIfMax, $wgPageShowWatchingUsers, $wgArticlePath,
                        $wgScriptPath, $wgServer;
@@ -360,13 +358,6 @@ class SkinTemplate extends Skin {
                $tpl->set( 'handheld', $request->getBool( 'handheld' ) );
                $tpl->setRef( 'loggedin', $this->loggedin );
                $tpl->set( 'notspecialpage', !$title->isSpecialPage() );
-               /* XXX currently unused, might get useful later
-               $tpl->set( 'editable', ( !$title->isSpecialPage() ) );
-               $tpl->set( 'exists', $title->getArticleID() != 0 );
-               $tpl->set( 'watch', $user->isWatched( $title ) ? 'unwatch' : 'watch' );
-               $tpl->set( 'protect', count( $title->isProtected() ) ? 'unprotect' : 'protect' );
-               $tpl->set( 'helppage', $this->msg( 'helppage' )->text() );
-               */
                $tpl->set( 'searchaction', $this->escapeSearchLink() );
                $tpl->set( 'searchtitle', SpecialPage::getTitleFor( 'Search' )->getPrefixedDBkey() );
                $tpl->set( 'search', trim( $request->getVal( 'search' ) ) );
@@ -1098,7 +1089,7 @@ class SkinTemplate extends Skin {
                                        /**
                                         * The following actions use messages which, if made particular to
                                         * the any specific skins, would break the Ajax code which makes this
-                                        * action happen entirely inline. Skin::makeGlobalVariablesScript
+                                        * action happen entirely inline. OutputPage::getJSVars
                                         * defines a set of messages in a javascript object - and these
                                         * messages are assumed to be global for all skins. Without making
                                         * a change to that procedure these messages will have to remain as
index 6508bce..ee1df29 100644 (file)
@@ -83,9 +83,9 @@ class StubObject {
         * @param object $obj Object to check.
         * @return void
         */
-       static function unstub( $obj ) {
+       static function unstub( &$obj ) {
                if ( $obj instanceof StubObject ) {
-                       $obj->_unstub( 'unstub', 3 );
+                       $obj = $obj->_unstub( 'unstub', 3 );
                }
        }
 
@@ -134,6 +134,7 @@ class StubObject {
         * @param string $name Name of the method called in this object.
         * @param int $level Level to go in the stack trace to get the function
         *   who called this function.
+        * @return The unstubbed version of itself
         * @throws MWException
         */
        function _unstub( $name = '_unstub', $level = 2 ) {
@@ -157,39 +158,11 @@ class StubObject {
                        $GLOBALS[$this->global] = $this->_newObject();
                        --$recursionLevel;
                        wfProfileOut( $fname );
+                       return $GLOBALS[$this->global];
                }
        }
 }
 
-/**
- * Stub object for the content language of this wiki. This object have to be in
- * $wgContLang global.
- *
- * @deprecated since 1.18
- */
-class StubContLang extends StubObject {
-
-       function __construct() {
-               wfDeprecated( __CLASS__, '1.18' );
-               parent::__construct( 'wgContLang' );
-       }
-
-       function __call( $name, $args ) {
-               return $this->_call( $name, $args );
-       }
-
-       /**
-        * @return Language
-        */
-       function _newObject() {
-               global $wgLanguageCode;
-               $obj = Language::factory( $wgLanguageCode );
-               $obj->initEncoding();
-               $obj->initContLang();
-               return $obj;
-       }
-}
-
 /**
  * Stub object for the user language. It depends of the user preferences and
  * "uselang" parameter that can be passed to index.php. This object have to be
index e038cc7..b7c0a25 100644 (file)
@@ -977,9 +977,9 @@ class Title {
                }
 
                try {
-                       $formatter = $this->getTitleFormatter();
+                       $formatter = self::getTitleFormatter();
                        return $formatter->getNamespaceName( $this->mNamespace, $this->mDbkeyform );
-               } catch ( InvalidArgumentException $ex )  {
+               } catch ( InvalidArgumentException $ex ) {
                        wfDebug( __METHOD__ . ': ' . $ex->getMessage() . "\n" );
                        return false;
                }
@@ -1371,7 +1371,6 @@ class Title {
         *
         * @param string $name The text
         * @return string The prefixed text
-        * @private
         */
        private function prefix( $name ) {
                $p = '';
@@ -1547,18 +1546,6 @@ class Title {
                return Title::makeTitleSafe( $this->getNamespace(), $this->getText() . '/' . $text );
        }
 
-       /**
-        * Get the HTML-escaped displayable text form.
-        * Used for the title field in <a> tags.
-        *
-        * @return string The text, including any prefixes
-        * @deprecated since 1.19
-        */
-       public function getEscapedText() {
-               wfDeprecated( __METHOD__, '1.19' );
-               return htmlspecialchars( $this->getPrefixedText() );
-       }
-
        /**
         * Get a URL-encoded form of the subpage text
         *
@@ -1776,34 +1763,6 @@ class Title {
                return $ret;
        }
 
-       /**
-        * Get an HTML-escaped version of the URL form, suitable for
-        * using in a link, without a server name or fragment
-        *
-        * @see self::getLocalURL for the arguments.
-        * @param string $query
-        * @param bool|string $query2
-        * @return string The URL
-        * @deprecated since 1.19
-        */
-       public function escapeLocalURL( $query = '', $query2 = false ) {
-               wfDeprecated( __METHOD__, '1.19' );
-               return htmlspecialchars( $this->getLocalURL( $query, $query2 ) );
-       }
-
-       /**
-        * Get an HTML-escaped version of the URL form, suitable for
-        * using in a link, including the server name and fragment
-        *
-        * @see self::getLocalURL for the arguments.
-        * @return string The URL
-        * @deprecated since 1.19
-        */
-       public function escapeFullURL( $query = '', $query2 = false ) {
-               wfDeprecated( __METHOD__, '1.19' );
-               return htmlspecialchars( $this->getFullURL( $query, $query2 ) );
-       }
-
        /**
         * Get the URL form for an internal link.
         * - Used in various Squid-related code, in case we have a different
@@ -1843,19 +1802,6 @@ class Title {
                return $url;
        }
 
-       /**
-        * HTML-escaped version of getCanonicalURL()
-        *
-        * @see self::getLocalURL for the arguments.
-        * @since 1.18
-        * @return string
-        * @deprecated since 1.19
-        */
-       public function escapeCanonicalURL( $query = '', $query2 = false ) {
-               wfDeprecated( __METHOD__, '1.19' );
-               return htmlspecialchars( $this->getCanonicalURL( $query, $query2 ) );
-       }
-
        /**
         * Get the edit URL for this Title
         *
@@ -1889,17 +1835,6 @@ class Title {
                return $this->mWatched;
        }
 
-       /**
-        * Can $wgUser read this page?
-        *
-        * @deprecated since 1.19; use userCan(), quickUserCan() or getUserPermissionsErrors() instead
-        * @return bool
-        */
-       public function userCanRead() {
-               wfDeprecated( __METHOD__, '1.19' );
-               return $this->userCan( 'read' );
-       }
-
        /**
         * Can $user perform $action on this page?
         * This skips potentially expensive cascading permission checks
@@ -2569,7 +2504,7 @@ class Title {
                        return false;
                }
 
-               if ( !isset( $this->mTitleProtection ) ) {
+               if ( $this->mTitleProtection === null ) {
                        $dbr = wfGetDB( DB_SLAVE );
                        $res = $dbr->select(
                                'protected_titles',
@@ -2584,30 +2519,6 @@ class Title {
                return $this->mTitleProtection;
        }
 
-       /**
-        * Update the title protection status
-        *
-        * @deprecated since 1.19; use WikiPage::doUpdateRestrictions() instead.
-        * @param string $create_perm Permission required for creation
-        * @param string $reason Reason for protection
-        * @param string $expiry Expiry timestamp
-        * @return bool
-        */
-       public function updateTitleProtection( $create_perm, $reason, $expiry ) {
-               wfDeprecated( __METHOD__, '1.19' );
-
-               global $wgUser;
-
-               $limit = array( 'create' => $create_perm );
-               $expiry = array( 'create' => $expiry );
-
-               $page = WikiPage::factory( $this );
-               $cascade = false;
-               $status = $page->doUpdateRestrictions( $limit, $expiry, $cascade, $reason, $wgUser );
-
-               return $status->isOK();
-       }
-
        /**
         * Remove any title protection due to page existing
         */
@@ -2722,7 +2633,7 @@ class Title {
         * @since 1.23
         */
        public function areCascadeProtectionSourcesLoaded( $getPages = true ) {
-               return $getPages ? isset( $this->mCascadeSources ) : isset( $this->mHasCascadingRestrictions );
+               return $getPages ? $this->mCascadeSources !== null : $this->mHasCascadingRestrictions !== null;
        }
 
        /**
@@ -2742,9 +2653,9 @@ class Title {
                global $wgContLang;
                $pagerestrictions = array();
 
-               if ( isset( $this->mCascadeSources ) && $getPages ) {
+               if ( $this->mCascadeSources !== null && $getPages ) {
                        return array( $this->mCascadeSources, $this->mCascadingRestrictions );
-               } elseif ( isset( $this->mHasCascadingRestrictions ) && !$getPages ) {
+               } elseif ( $this->mHasCascadingRestrictions !== null && !$getPages ) {
                        return array( $this->mHasCascadingRestrictions, $pagerestrictions );
                }
 
@@ -3061,7 +2972,7 @@ class Title {
 
                $method = __METHOD__;
                $dbw = wfGetDB( DB_MASTER );
-               $dbw->onTransactionIdle( function() use ( $dbw, $method ) {
+               $dbw->onTransactionIdle( function () use ( $dbw, $method ) {
                        $dbw->delete(
                                'page_restrictions',
                                array( 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ),
@@ -3090,7 +3001,7 @@ class Title {
                # alone to cache the result.  There's no point in having it hanging
                # around uninitialized in every Title object; therefore we only add it
                # if needed and don't declare it statically.
-               if ( !isset( $this->mHasSubpages ) ) {
+               if ( $this->mHasSubpages === null ) {
                        $this->mHasSubpages = false;
                        $subpages = $this->getSubpages( 1 );
                        if ( $subpages instanceof TitleArray ) {
@@ -3369,7 +3280,7 @@ class Title {
                        // @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
                        //        the parsing code with Title, while avoiding massive refactoring.
                        // @todo: get rid of secureAndSplit, refactor parsing code.
-                       $parser = $this->getTitleParser();
+                       $parser = self::getTitleParser();
                        $parts = $parser->splitTitleString( $dbkey, $this->getDefaultNamespace() );
                } catch ( MalformedTitleException $ex ) {
                        return false;
@@ -3903,13 +3814,31 @@ class Title {
                        $log->addRelations( 'pr_id', $logRelationsValues, $logId );
                }
 
+               // Update *_from_namespace fields as needed
+               if ( $this->getNamespace() != $nt->getNamespace() ) {
+                       $dbw->update( 'pagelinks',
+                               array( 'pl_from_namespace' => $nt->getNamespace() ),
+                               array( 'pl_from' => $pageid ),
+                               __METHOD__
+                       );
+                       $dbw->update( 'templatelinks',
+                               array( 'tl_from_namespace' => $nt->getNamespace() ),
+                               array( 'tl_from' => $pageid ),
+                               __METHOD__
+                       );
+                       $dbw->update( 'imagelinks',
+                               array( 'il_from_namespace' => $nt->getNamespace() ),
+                               array( 'il_from' => $pageid ),
+                               __METHOD__
+                       );
+               }
+
                # Update watchlists
-               $oldnamespace = MWNamespace::getSubject( $this->getNamespace() );
-               $newnamespace = MWNamespace::getSubject( $nt->getNamespace() );
                $oldtitle = $this->getDBkey();
                $newtitle = $nt->getDBkey();
-
-               if ( $oldnamespace != $newnamespace || $oldtitle != $newtitle ) {
+               $oldsnamespace = MWNamespace::getSubject( $this->getNamespace() );
+               $newsnamespace = MWNamespace::getSubject( $nt->getNamespace() );
+               if ( $oldsnamespace != $newsnamespace || $oldtitle != $newtitle ) {
                        WatchedItem::duplicateEntries( $this, $nt );
                }
 
@@ -4745,7 +4674,7 @@ class Title {
                $method = __METHOD__;
                $dbw = wfGetDB( DB_MASTER );
                $conds = $this->pageCond();
-               $dbw->onTransactionIdle( function() use ( $dbw, $conds, $method ) {
+               $dbw->onTransactionIdle( function () use ( $dbw, $conds, $method ) {
                        $dbw->update(
                                'page',
                                array( 'page_touched' => $dbw->timestamp() ),
@@ -4779,7 +4708,9 @@ class Title {
         * @return string Last-touched timestamp
         */
        public function getTouched( $db = null ) {
-               $db = isset( $db ) ? $db : wfGetDB( DB_SLAVE );
+               if ( $db === null ) {
+                       $db = wfGetDB( DB_SLAVE );
+               }
                $touched = $db->selectField( 'page', 'page_touched', $this->pageCond(), __METHOD__ );
                return $touched;
        }
index 67ee7f9..ce3ea74 100644 (file)
@@ -175,6 +175,7 @@ class User implements IDBAccessObject {
                'userrights-interwiki',
                'viewmyprivateinfo',
                'viewmywatchlist',
+               'viewsuppressed',
                'writeapi',
        );
 
@@ -892,38 +893,6 @@ class User implements IDBAccessObject {
                return $this->mPasswordExpires;
        }
 
-       /**
-        * Does a string look like an e-mail address?
-        *
-        * This validates an email address using an HTML5 specification found at:
-        * http://www.whatwg.org/html/states-of-the-type-attribute.html#valid-e-mail-address
-        * Which as of 2011-01-24 says:
-        *
-        *     A valid e-mail address is a string that matches the ABNF production
-        *   1*( atext / "." ) "@" ldh-str *( "." ldh-str ) where atext is defined
-        *   in RFC 5322 section 3.2.3, and ldh-str is defined in RFC 1034 section
-        *   3.5.
-        *
-        * This function is an implementation of the specification as requested in
-        * bug 22449.
-        *
-        * Client-side forms will use the same standard validation rules via JS or
-        * HTML 5 validation; additional restrictions can be enforced server-side
-        * by extensions via the 'isValidEmailAddr' hook.
-        *
-        * Note that this validation doesn't 100% match RFC 2822, but is believed
-        * to be liberal enough for wide use. Some invalid addresses will still
-        * pass validation here.
-        *
-        * @param string $addr E-mail address
-        * @return bool
-        * @deprecated since 1.18 call Sanitizer::isValidEmail() directly
-        */
-       public static function isValidEmailAddr( $addr ) {
-               wfDeprecated( __METHOD__, '1.18' );
-               return Sanitizer::validateEmail( $addr );
-       }
-
        /**
         * Given unvalidated user input, return a canonical username, or false if
         * the username is invalid.
@@ -1537,10 +1506,9 @@ class User implements IDBAccessObject {
         * @return bool True if blacklisted.
         */
        public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
-               global $wgEnableSorbs, $wgEnableDnsBlacklist,
-                       $wgSorbsUrl, $wgDnsBlacklistUrls, $wgProxyWhitelist;
+               global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
 
-               if ( !$wgEnableDnsBlacklist && !$wgEnableSorbs ) {
+               if ( !$wgEnableDnsBlacklist ) {
                        return false;
                }
 
@@ -1548,8 +1516,7 @@ class User implements IDBAccessObject {
                        return false;
                }
 
-               $urls = array_merge( $wgDnsBlacklistUrls, (array)$wgSorbsUrl );
-               return $this->inDnsBlacklist( $ip, $urls );
+               return $this->inDnsBlacklist( $ip, $wgDnsBlacklistUrls );
        }
 
        /**
@@ -2209,7 +2176,7 @@ class User implements IDBAccessObject {
                        $userid = $this->mId;
                        $touched = $this->mTouched;
                        $method = __METHOD__;
-                       $dbw->onTransactionIdle( function() use ( $dbw, $userid, $touched, $method ) {
+                       $dbw->onTransactionIdle( function () use ( $dbw, $userid, $touched, $method ) {
                                // Prevent contention slams by checking user_touched first
                                $encTouched = $dbw->addQuotes( $dbw->timestamp( $touched ) );
                                $needsPurge = $dbw->selectField( 'user', '1',
@@ -2778,6 +2745,8 @@ class User implements IDBAccessObject {
                        }
                }
 
+               wfRunHooks( 'UserResetAllOptions', array( $this, &$newOptions, $this->mOptions, $resetKinds ) );
+
                $this->mOptions = $newOptions;
                $this->mOptionsLoaded = true;
        }
@@ -2946,7 +2915,7 @@ class User implements IDBAccessObject {
                        return null;
                }
 
-               if ( !isset( $this->mEditCount ) ) {
+               if ( $this->mEditCount === null ) {
                        /* Populate the count, if it has not been populated yet */
                        wfProfileIn( __METHOD__ );
                        $dbr = wfGetDB( DB_SLAVE );
index d73f6b4..25be921 100644 (file)
@@ -151,13 +151,14 @@ class UserMailer {
         * array of parameters. It requires PEAR:Mail to do that.
         * Otherwise it just uses the standard PHP 'mail' function.
         *
-        * @param MailAddress $to Recipient's email (or an array of them)
+        * @param MailAddress|MailAddress[] $to Recipient's email (or an array of them)
         * @param MailAddress $from Sender's email
         * @param string $subject Email's subject.
         * @param string $body Email's text or Array of two strings to be the text and html bodies
         * @param MailAddress $replyto Optional reply-to email (default: null).
         * @param string $contentType Optional custom Content-Type (default: text/plain; charset=UTF-8)
         * @throws MWException
+        * @throws Exception
         * @return Status
         */
        public static function send( $to, $from, $subject, $body, $replyto = null,
@@ -239,7 +240,17 @@ class UserMailer {
                # -- hashar 20120218
 
                $headers['From'] = $from->toString();
-               $headers['Return-Path'] = $from->address;
+               $returnPath = $from->address;
+               $extraParams = $wgAdditionalMailParams;
+
+               // Hook to generate custom VERP address for 'Return-Path'
+               wfRunHooks( 'UserMailerChangeReturnPath', array( $to, &$returnPath ) );
+               # Add the envelope sender address using the -f command line option when PHP mail() is used.
+               # Will default to the $from->address when the UserMailerChangeReturnPath hook fails and the
+               # generated VERP address when the hook runs effectively.
+               $extraParams .= ' -f ' . $returnPath;
+
+               $headers['Return-Path'] = $returnPath;
 
                if ( $replyto ) {
                        $headers['Reply-To'] = $replyto->toString();
@@ -371,7 +382,7 @@ class UserMailer {
                                                        self::quotedPrintable( $subject ),
                                                        $body,
                                                        $headers,
-                                                       $wgAdditionalMailParams
+                                                       $extraParams
                                                );
                                        }
                                }
@@ -543,7 +554,7 @@ class EmailNotification {
                                // Update wl_notificationtimestamp for all watching users except the editor
                                $fname = __METHOD__;
                                $dbw->onTransactionIdle(
-                                       function() use ( $dbw, $timestamp, $watchers, $title, $fname ) {
+                                       function () use ( $dbw, $timestamp, $watchers, $title, $fname ) {
                                                $dbw->update( 'watchlist',
                                                        array( /* SET */
                                                                'wl_notificationtimestamp' => $dbw->timestamp( $timestamp )
index 09f01c0..e137628 100644 (file)
  * @file
  */
 
-# Protect against register_globals
+# Die if register_globals is enabled (PHP <=5.3)
 # This must be done before any globals are set by the code
 if ( ini_get( 'register_globals' ) ) {
-       if ( isset( $_REQUEST['GLOBALS'] ) || isset( $_FILES['GLOBALS'] ) ) {
-               die( '<a href="http://www.hardened-php.net/globals-problem">'
-                       . '$GLOBALS overwrite vulnerability</a>' );
-       }
-
-       $verboten = array(
-               'GLOBALS',
-               '_SERVER',
-               'HTTP_SERVER_VARS',
-               '_GET',
-               'HTTP_GET_VARS',
-               '_POST',
-               'HTTP_POST_VARS',
-               '_COOKIE',
-               'HTTP_COOKIE_VARS',
-               '_FILES',
-               'HTTP_POST_FILES',
-               '_ENV',
-               'HTTP_ENV_VARS',
-               '_REQUEST',
-               '_SESSION',
-               'HTTP_SESSION_VARS'
-       );
-
-       foreach ( $_REQUEST as $name => $value ) {
-               if ( in_array( $name, $verboten ) ) {
-                       header( "HTTP/1.1 500 Internal Server Error" );
-                       echo "register_globals security paranoia: trying to overwrite superglobals, aborting.";
-                       die( -1 );
-               }
-               unset( $GLOBALS[$name] );
-       }
+       die( 'MediaWiki does not support installations where register_globals is enabled. '
+               . 'Please see <a href="https://www.mediawiki.org/wiki/register_globals">mediawiki.org</a> '
+               . 'for help on how to disable it.' );
 }
 
 # bug 15461: Make IE8 turn off content sniffing. Everybody else should ignore this
@@ -70,11 +41,7 @@ header( 'X-Content-Type-Options: nosniff' );
 
 $wgRequestTime = microtime( true );
 # getrusage() does not exist on the Microsoft Windows platforms, catching this
-if ( function_exists ( 'getrusage' ) ) {
-       $wgRUstart = getrusage();
-} else {
-       $wgRUstart = array();
-}
+$wgRUstart = function_exists( 'getrusage' ) ? getrusage() : array();
 unset( $IP );
 
 # Valid web server entry point, enable includes.
@@ -90,11 +57,7 @@ define( 'MEDIAWIKI', true );
 # if we don't have permissions on parent directories.
 $IP = getenv( 'MW_INSTALL_PATH' );
 if ( $IP === false ) {
-       if ( realpath( '.' ) ) {
-               $IP = realpath( '.' );
-       } else {
-               $IP = dirname( __DIR__ );
-       }
+       $IP = realpath( '.' ) ?: dirname( __DIR__ );
 }
 
 # Start the autoloader, so that extensions can derive classes from core files
diff --git a/includes/Wiki.php b/includes/Wiki.php
deleted file mode 100644 (file)
index a8bafa3..0000000
+++ /dev/null
@@ -1,722 +0,0 @@
-<?php
-/**
- * Helper class for the index.php entry point.
- *
- * 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
- */
-
-/**
- * The MediaWiki class is the helper class for the index.php entry point.
- *
- * @internal documentation reviewed 15 Mar 2010
- */
-class MediaWiki {
-       /**
-        * @todo Fold $output, etc, into this
-        * @var IContextSource
-        */
-       private $context;
-
-       /**
-        * @param null|WebRequest $x
-        * @return WebRequest
-        */
-       public function request( WebRequest $x = null ) {
-               $old = $this->context->getRequest();
-               $this->context->setRequest( $x );
-               return $old;
-       }
-
-       /**
-        * @param null|OutputPage $x
-        * @return OutputPage
-        */
-       public function output( OutputPage $x = null ) {
-               $old = $this->context->getOutput();
-               $this->context->setOutput( $x );
-               return $old;
-       }
-
-       /**
-        * @param IContextSource|null $context
-        */
-       public function __construct( IContextSource $context = null ) {
-               if ( !$context ) {
-                       $context = RequestContext::getMain();
-               }
-
-               $this->context = $context;
-       }
-
-       /**
-        * Parse the request to get the Title object
-        *
-        * @return Title Title object to be $wgTitle
-        */
-       private function parseTitle() {
-               global $wgContLang;
-
-               $request = $this->context->getRequest();
-               $curid = $request->getInt( 'curid' );
-               $title = $request->getVal( 'title' );
-               $action = $request->getVal( 'action', 'view' );
-
-               if ( $request->getCheck( 'search' ) ) {
-                       // Compatibility with old search URLs which didn't use Special:Search
-                       // Just check for presence here, so blank requests still
-                       // show the search page when using ugly URLs (bug 8054).
-                       $ret = SpecialPage::getTitleFor( 'Search' );
-               } elseif ( $curid ) {
-                       // URLs like this are generated by RC, because rc_title isn't always accurate
-                       $ret = Title::newFromID( $curid );
-               } else {
-                       $ret = Title::newFromURL( $title );
-                       // Alias NS_MEDIA page URLs to NS_FILE...we only use NS_MEDIA
-                       // in wikitext links to tell Parser to make a direct file link
-                       if ( !is_null( $ret ) && $ret->getNamespace() == NS_MEDIA ) {
-                               $ret = Title::makeTitle( NS_FILE, $ret->getDBkey() );
-                       }
-                       // Check variant links so that interwiki links don't have to worry
-                       // about the possible different language variants
-                       if ( count( $wgContLang->getVariants() ) > 1
-                               && !is_null( $ret ) && $ret->getArticleID() == 0
-                       ) {
-                               $wgContLang->findVariantLink( $title, $ret );
-                       }
-               }
-
-               // If title is not provided, always allow oldid and diff to set the title.
-               // If title is provided, allow oldid and diff to override the title, unless
-               // we are talking about a special page which might use these parameters for
-               // other purposes.
-               if ( $ret === null || !$ret->isSpecialPage() ) {
-                       // We can have urls with just ?diff=,?oldid= or even just ?diff=
-                       $oldid = $request->getInt( 'oldid' );
-                       $oldid = $oldid ? $oldid : $request->getInt( 'diff' );
-                       // Allow oldid to override a changed or missing title
-                       if ( $oldid ) {
-                               $rev = Revision::newFromId( $oldid );
-                               $ret = $rev ? $rev->getTitle() : $ret;
-                       }
-               }
-
-               // Use the main page as default title if nothing else has been provided
-               if ( $ret === null
-                       && strval( $title ) === ''
-                       && !$request->getCheck( 'curid' )
-                       && $action !== 'delete'
-               ) {
-                       $ret = Title::newMainPage();
-               }
-
-               if ( $ret === null || ( $ret->getDBkey() == '' && !$ret->isExternal() ) ) {
-                       $ret = SpecialPage::getTitleFor( 'Badtitle' );
-               }
-
-               return $ret;
-       }
-
-       /**
-        * Get the Title object that we'll be acting on, as specified in the WebRequest
-        * @return Title
-        */
-       public function getTitle() {
-               if ( $this->context->getTitle() === null ) {
-                       $this->context->setTitle( $this->parseTitle() );
-               }
-               return $this->context->getTitle();
-       }
-
-       /**
-        * Returns the name of the action that will be executed.
-        *
-        * @return string Action
-        */
-       public function getAction() {
-               static $action = null;
-
-               if ( $action === null ) {
-                       $action = Action::getActionName( $this->context );
-               }
-
-               return $action;
-       }
-
-       /**
-        * Performs the request.
-        * - bad titles
-        * - read restriction
-        * - local interwiki redirects
-        * - redirect loop
-        * - special pages
-        * - normal pages
-        *
-        * @throws MWException|PermissionsError|BadTitleError|HttpError
-        * @return void
-        */
-       private function performRequest() {
-               global $wgServer, $wgUsePathInfo, $wgTitle;
-
-               wfProfileIn( __METHOD__ );
-
-               $request = $this->context->getRequest();
-               $requestTitle = $title = $this->context->getTitle();
-               $output = $this->context->getOutput();
-               $user = $this->context->getUser();
-
-               if ( $request->getVal( 'printable' ) === 'yes' ) {
-                       $output->setPrintable();
-               }
-
-               $unused = null; // To pass it by reference
-               wfRunHooks( 'BeforeInitialize', array( &$title, &$unused, &$output, &$user, $request, $this ) );
-
-               // Invalid titles. Bug 21776: The interwikis must redirect even if the page name is empty.
-               if ( is_null( $title ) || ( $title->getDBkey() == '' && !$title->isExternal() )
-                       || $title->isSpecial( 'Badtitle' )
-               ) {
-                       $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) );
-                       wfProfileOut( __METHOD__ );
-                       throw new BadTitleError();
-               }
-
-               // Check user's permissions to read this page.
-               // We have to check here to catch special pages etc.
-               // We will check again in Article::view().
-               $permErrors = $title->getUserPermissionsErrors( 'read', $user );
-               if ( count( $permErrors ) ) {
-                       // Bug 32276: allowing the skin to generate output with $wgTitle or
-                       // $this->context->title set to the input title would allow anonymous users to
-                       // determine whether a page exists, potentially leaking private data. In fact, the
-                       // curid and oldid request  parameters would allow page titles to be enumerated even
-                       // when they are not guessable. So we reset the title to Special:Badtitle before the
-                       // permissions error is displayed.
-                       //
-                       // The skin mostly uses $this->context->getTitle() these days, but some extensions
-                       // still use $wgTitle.
-
-                       $badTitle = SpecialPage::getTitleFor( 'Badtitle' );
-                       $this->context->setTitle( $badTitle );
-                       $wgTitle = $badTitle;
-
-                       wfProfileOut( __METHOD__ );
-                       throw new PermissionsError( 'read', $permErrors );
-               }
-
-               $pageView = false; // was an article or special page viewed?
-
-               // Interwiki redirects
-               if ( $title->isExternal() ) {
-                       $rdfrom = $request->getVal( 'rdfrom' );
-                       if ( $rdfrom ) {
-                               $url = $title->getFullURL( array( 'rdfrom' => $rdfrom ) );
-                       } else {
-                               $query = $request->getValues();
-                               unset( $query['title'] );
-                               $url = $title->getFullURL( $query );
-                       }
-                       // Check for a redirect loop
-                       if ( !preg_match( '/^' . preg_quote( $wgServer, '/' ) . '/', $url )
-                               && $title->isLocal()
-                       ) {
-                               // 301 so google et al report the target as the actual url.
-                               $output->redirect( $url, 301 );
-                       } else {
-                               $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) );
-                               wfProfileOut( __METHOD__ );
-                               throw new BadTitleError();
-                       }
-               // Redirect loops, no title in URL, $wgUsePathInfo URLs, and URLs with a variant
-               } elseif ( $request->getVal( 'action', 'view' ) == 'view' && !$request->wasPosted()
-                       && ( $request->getVal( 'title' ) === null
-                               || $title->getPrefixedDBkey() != $request->getVal( 'title' ) )
-                       && !count( $request->getValueNames( array( 'action', 'title' ) ) )
-                       && wfRunHooks( 'TestCanonicalRedirect', array( $request, $title, $output ) )
-               ) {
-                       if ( $title->isSpecialPage() ) {
-                               list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
-                               if ( $name ) {
-                                       $title = SpecialPage::getTitleFor( $name, $subpage );
-                               }
-                       }
-                       $targetUrl = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
-                       // Redirect to canonical url, make it a 301 to allow caching
-                       if ( $targetUrl == $request->getFullRequestURL() ) {
-                               $message = "Redirect loop detected!\n\n" .
-                                       "This means the wiki got confused about what page was " .
-                                       "requested; this sometimes happens when moving a wiki " .
-                                       "to a new server or changing the server configuration.\n\n";
-
-                               if ( $wgUsePathInfo ) {
-                                       $message .= "The wiki is trying to interpret the page " .
-                                               "title from the URL path portion (PATH_INFO), which " .
-                                               "sometimes fails depending on the web server. Try " .
-                                               "setting \"\$wgUsePathInfo = false;\" in your " .
-                                               "LocalSettings.php, or check that \$wgArticlePath " .
-                                               "is correct.";
-                               } else {
-                                       $message .= "Your web server was detected as possibly not " .
-                                               "supporting URL path components (PATH_INFO) correctly; " .
-                                               "check your LocalSettings.php for a customized " .
-                                               "\$wgArticlePath setting and/or toggle \$wgUsePathInfo " .
-                                               "to true.";
-                               }
-                               throw new HttpError( 500, $message );
-                       } else {
-                               $output->setSquidMaxage( 1200 );
-                               $output->redirect( $targetUrl, '301' );
-                       }
-               // Special pages
-               } elseif ( NS_SPECIAL == $title->getNamespace() ) {
-                       $pageView = true;
-                       // Actions that need to be made when we have a special pages
-                       SpecialPageFactory::executePath( $title, $this->context );
-               } else {
-                       // ...otherwise treat it as an article view. The article
-                       // may be a redirect to another article or URL.
-                       $article = $this->initializeArticle();
-                       if ( is_object( $article ) ) {
-                               $pageView = true;
-                               $this->performAction( $article, $requestTitle );
-                       } elseif ( is_string( $article ) ) {
-                               $output->redirect( $article );
-                       } else {
-                               wfProfileOut( __METHOD__ );
-                               throw new MWException( "Shouldn't happen: MediaWiki::initializeArticle()"
-                                       . " returned neither an object nor a URL" );
-                       }
-               }
-
-               if ( $pageView ) {
-                       // Promote user to any groups they meet the criteria for
-                       $user->addAutopromoteOnceGroups( 'onView' );
-               }
-
-               wfProfileOut( __METHOD__ );
-       }
-
-       /**
-        * Initialize the main Article object for "standard" actions (view, etc)
-        * Create an Article object for the page, following redirects if needed.
-        *
-        * @return mixed An Article, or a string to redirect to another URL
-        */
-       private function initializeArticle() {
-               global $wgDisableHardRedirects;
-
-               wfProfileIn( __METHOD__ );
-
-               $title = $this->context->getTitle();
-               if ( $this->context->canUseWikiPage() ) {
-                       // Try to use request context wiki page, as there
-                       // is already data from db saved in per process
-                       // cache there from this->getAction() call.
-                       $page = $this->context->getWikiPage();
-                       $article = Article::newFromWikiPage( $page, $this->context );
-               } else {
-                       // This case should not happen, but just in case.
-                       $article = Article::newFromTitle( $title, $this->context );
-                       $this->context->setWikiPage( $article->getPage() );
-               }
-
-               // NS_MEDIAWIKI has no redirects.
-               // It is also used for CSS/JS, so performance matters here...
-               if ( $title->getNamespace() == NS_MEDIAWIKI ) {
-                       wfProfileOut( __METHOD__ );
-                       return $article;
-               }
-
-               $request = $this->context->getRequest();
-
-               // Namespace might change when using redirects
-               // Check for redirects ...
-               $action = $request->getVal( 'action', 'view' );
-               $file = ( $title->getNamespace() == NS_FILE ) ? $article->getFile() : null;
-               if ( ( $action == 'view' || $action == 'render' ) // ... for actions that show content
-                       && !$request->getVal( 'oldid' ) // ... and are not old revisions
-                       && !$request->getVal( 'diff' ) // ... and not when showing diff
-                       && $request->getVal( 'redirect' ) != 'no' // ... unless explicitly told not to
-                       // ... and the article is not a non-redirect image page with associated file
-                       && !( is_object( $file ) && $file->exists() && !$file->getRedirected() )
-               ) {
-                       // Give extensions a change to ignore/handle redirects as needed
-                       $ignoreRedirect = $target = false;
-
-                       wfRunHooks( 'InitializeArticleMaybeRedirect',
-                               array( &$title, &$request, &$ignoreRedirect, &$target, &$article ) );
-
-                       // Follow redirects only for... redirects.
-                       // If $target is set, then a hook wanted to redirect.
-                       if ( !$ignoreRedirect && ( $target || $article->isRedirect() ) ) {
-                               // Is the target already set by an extension?
-                               $target = $target ? $target : $article->followRedirect();
-                               if ( is_string( $target ) ) {
-                                       if ( !$wgDisableHardRedirects ) {
-                                               // we'll need to redirect
-                                               wfProfileOut( __METHOD__ );
-                                               return $target;
-                                       }
-                               }
-                               if ( is_object( $target ) ) {
-                                       // Rewrite environment to redirected article
-                                       $rarticle = Article::newFromTitle( $target, $this->context );
-                                       $rarticle->loadPageData();
-                                       if ( $rarticle->exists() || ( is_object( $file ) && !$file->isLocal() ) ) {
-                                               $rarticle->setRedirectedFrom( $title );
-                                               $article = $rarticle;
-                                               $this->context->setTitle( $target );
-                                               $this->context->setWikiPage( $article->getPage() );
-                                       }
-                               }
-                       } else {
-                               $this->context->setTitle( $article->getTitle() );
-                               $this->context->setWikiPage( $article->getPage() );
-                       }
-               }
-
-               wfProfileOut( __METHOD__ );
-               return $article;
-       }
-
-       /**
-        * Perform one of the "standard" actions
-        *
-        * @param Page $page
-        * @param Title $requestTitle The original title, before any redirects were applied
-        */
-       private function performAction( Page $page, Title $requestTitle ) {
-               global $wgUseSquid, $wgSquidMaxage;
-
-               wfProfileIn( __METHOD__ );
-
-               $request = $this->context->getRequest();
-               $output = $this->context->getOutput();
-               $title = $this->context->getTitle();
-               $user = $this->context->getUser();
-
-               if ( !wfRunHooks( 'MediaWikiPerformAction',
-                               array( $output, $page, $title, $user, $request, $this ) )
-               ) {
-                       wfProfileOut( __METHOD__ );
-                       return;
-               }
-
-               $act = $this->getAction();
-
-               $action = Action::factory( $act, $page, $this->context );
-
-               if ( $action instanceof Action ) {
-                       # Let Squid cache things if we can purge them.
-                       if ( $wgUseSquid &&
-                               in_array( $request->getFullRequestURL(), $requestTitle->getSquidURLs() )
-                       ) {
-                               $output->setSquidMaxage( $wgSquidMaxage );
-                       }
-
-                       $action->show();
-                       wfProfileOut( __METHOD__ );
-                       return;
-               }
-
-               if ( wfRunHooks( 'UnknownAction', array( $request->getVal( 'action', 'view' ), $page ) ) ) {
-                       $output->setStatusCode( 404 );
-                       $output->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
-               }
-
-               wfProfileOut( __METHOD__ );
-       }
-
-       /**
-        * Run the current MediaWiki instance
-        * index.php just calls this
-        */
-       public function run() {
-               try {
-                       $this->checkMaxLag();
-                       try {
-                               $this->main();
-                       } catch ( ErrorPageError $e ) {
-                               // Bug 62091: while exceptions are convenient to bubble up GUI errors,
-                               // they are not internal application faults. As with normal requests, this
-                               // should commit, print the output, do deferred updates, jobs, and profiling.
-                               wfGetLBFactory()->commitMasterChanges();
-                               $e->report(); // display the GUI error
-                       }
-                       if ( function_exists( 'fastcgi_finish_request' ) ) {
-                               fastcgi_finish_request();
-                       }
-                       $this->triggerJobs();
-                       $this->restInPeace();
-               } catch ( Exception $e ) {
-                       MWExceptionHandler::handle( $e );
-               }
-       }
-
-       /**
-        * Checks if the request should abort due to a lagged server,
-        * for given maxlag parameter.
-        * @return bool
-        */
-       private function checkMaxLag() {
-               global $wgShowHostnames;
-
-               wfProfileIn( __METHOD__ );
-               $maxLag = $this->context->getRequest()->getVal( 'maxlag' );
-               if ( !is_null( $maxLag ) ) {
-                       list( $host, $lag ) = wfGetLB()->getMaxLag();
-                       if ( $lag > $maxLag ) {
-                               $resp = $this->context->getRequest()->response();
-                               $resp->header( 'HTTP/1.1 503 Service Unavailable' );
-                               $resp->header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
-                               $resp->header( 'X-Database-Lag: ' . intval( $lag ) );
-                               $resp->header( 'Content-Type: text/plain' );
-                               if ( $wgShowHostnames ) {
-                                       echo "Waiting for $host: $lag seconds lagged\n";
-                               } else {
-                                       echo "Waiting for a database server: $lag seconds lagged\n";
-                               }
-
-                               wfProfileOut( __METHOD__ );
-
-                               exit;
-                       }
-               }
-               wfProfileOut( __METHOD__ );
-               return true;
-       }
-
-       private function main() {
-               global $wgUseFileCache, $wgTitle, $wgUseAjax;
-
-               wfProfileIn( __METHOD__ );
-
-               $request = $this->context->getRequest();
-
-               // Send Ajax requests to the Ajax dispatcher.
-               if ( $wgUseAjax && $request->getVal( 'action', 'view' ) == 'ajax' ) {
-
-                       // Set a dummy title, because $wgTitle == null might break things
-                       $title = Title::makeTitle( NS_MAIN, 'AJAX' );
-                       $this->context->setTitle( $title );
-                       $wgTitle = $title;
-
-                       $dispatcher = new AjaxDispatcher();
-                       $dispatcher->performAction();
-                       wfProfileOut( __METHOD__ );
-                       return;
-               }
-
-               // Get title from request parameters,
-               // is set on the fly by parseTitle the first time.
-               $title = $this->getTitle();
-               $action = $this->getAction();
-               $wgTitle = $title;
-
-               // If the user has forceHTTPS set to true, or if the user
-               // is in a group requiring HTTPS, or if they have the HTTPS
-               // preference set, redirect them to HTTPS.
-               // Note: Do this after $wgTitle is setup, otherwise the hooks run from
-               // isLoggedIn() will do all sorts of weird stuff.
-               if (
-                       $request->getProtocol() == 'http' &&
-                       (
-                               $request->getCookie( 'forceHTTPS', '' ) ||
-                               // check for prefixed version for currently logged in users
-                               $request->getCookie( 'forceHTTPS' ) ||
-                               // Avoid checking the user and groups unless it's enabled.
-                               (
-                                       $this->context->getUser()->isLoggedIn()
-                                       && $this->context->getUser()->requiresHTTPS()
-                               )
-                       )
-               ) {
-                       $oldUrl = $request->getFullRequestURL();
-                       $redirUrl = preg_replace( '#^http://#', 'https://', $oldUrl );
-
-                       // ATTENTION: This hook is likely to be removed soon due to overall design of the system.
-                       if ( wfRunHooks( 'BeforeHttpsRedirect', array( $this->context, &$redirUrl ) ) ) {
-
-                               if ( $request->wasPosted() ) {
-                                       // This is weird and we'd hope it almost never happens. This
-                                       // means that a POST came in via HTTP and policy requires us
-                                       // redirecting to HTTPS. It's likely such a request is going
-                                       // to fail due to post data being lost, but let's try anyway
-                                       // and just log the instance.
-                                       //
-                                       // @todo @fixme See if we could issue a 307 or 308 here, need
-                                       // to see how clients (automated & browser) behave when we do
-                                       wfDebugLog( 'RedirectedPosts', "Redirected from HTTP to HTTPS: $oldUrl" );
-                               }
-                               // Setup dummy Title, otherwise OutputPage::redirect will fail
-                               $title = Title::newFromText( NS_MAIN, 'REDIR' );
-                               $this->context->setTitle( $title );
-                               $output = $this->context->getOutput();
-                               // Since we only do this redir to change proto, always send a vary header
-                               $output->addVaryHeader( 'X-Forwarded-Proto' );
-                               $output->redirect( $redirUrl );
-                               $output->output();
-                               wfProfileOut( __METHOD__ );
-                               return;
-                       }
-               }
-
-               if ( $wgUseFileCache && $title->getNamespace() >= 0 ) {
-                       wfProfileIn( 'main-try-filecache' );
-                       if ( HTMLFileCache::useFileCache( $this->context ) ) {
-                               // Try low-level file cache hit
-                               $cache = HTMLFileCache::newFromTitle( $title, $action );
-                               if ( $cache->isCacheGood( /* Assume up to date */ ) ) {
-                                       // Check incoming headers to see if client has this cached
-                                       $timestamp = $cache->cacheTimestamp();
-                                       if ( !$this->context->getOutput()->checkLastModified( $timestamp ) ) {
-                                               $cache->loadFromFileCache( $this->context );
-                                       }
-                                       // Do any stats increment/watchlist stuff
-                                       // Assume we're viewing the latest revision (this should always be the case with file cache)
-                                       $this->context->getWikiPage()->doViewUpdates( $this->context->getUser() );
-                                       // Tell OutputPage that output is taken care of
-                                       $this->context->getOutput()->disable();
-                                       wfProfileOut( 'main-try-filecache' );
-                                       wfProfileOut( __METHOD__ );
-                                       return;
-                               }
-                       }
-                       wfProfileOut( 'main-try-filecache' );
-               }
-
-               // Actually do the work of the request and build up any output
-               $this->performRequest();
-
-               // Either all DB and deferred updates should happen or none.
-               // The later should not be cancelled due to client disconnect.
-               ignore_user_abort( true );
-               // Now commit any transactions, so that unreported errors after
-               // output() don't roll back the whole DB transaction
-               wfGetLBFactory()->commitMasterChanges();
-
-               // Output everything!
-               $this->context->getOutput()->output();
-
-               wfProfileOut( __METHOD__ );
-       }
-
-       /**
-        * Ends this task peacefully
-        */
-       public function restInPeace() {
-               // Do any deferred jobs
-               DeferredUpdates::doUpdates( 'commit' );
-
-               // Log profiling data, e.g. in the database or UDP
-               wfLogProfilingData();
-
-               // Commit and close up!
-               $factory = wfGetLBFactory();
-               $factory->commitMasterChanges();
-               $factory->shutdown();
-
-               wfDebug( "Request ended normally\n" );
-       }
-
-       /**
-        * Potentially open a socket and sent an HTTP request back to the server
-        * to run a specified number of jobs. This registers a callback to cleanup
-        * the socket once it's done.
-        */
-       protected function triggerJobs() {
-               global $wgJobRunRate, $wgServer, $wgRunJobsAsync;
-
-               if ( $wgJobRunRate <= 0 || wfReadOnly() ) {
-                       return;
-               } elseif ( $this->getTitle()->isSpecial( 'RunJobs' ) ) {
-                       return; // recursion guard
-               }
-
-               $section = new ProfileSection( __METHOD__ );
-
-               if ( $wgJobRunRate < 1 ) {
-                       $max = mt_getrandmax();
-                       if ( mt_rand( 0, $max ) > $max * $wgJobRunRate ) {
-                               return; // the higher $wgJobRunRate, the less likely we return here
-                       }
-                       $n = 1;
-               } else {
-                       $n = intval( $wgJobRunRate );
-               }
-
-               if ( !$wgRunJobsAsync ) {
-                       // If running jobs asynchronously has been disabled, run the job here
-                       // while the user waits
-                       SpecialRunJobs::executeJobs( $n );
-                       return;
-               }
-
-               try {
-                       if ( !JobQueueGroup::singleton()->queuesHaveJobs( JobQueueGroup::TYPE_DEFAULT ) ) {
-                               return; // do not send request if there are probably no jobs
-                       }
-               } catch ( JobQueueError $e ) {
-                       MWExceptionHandler::logException( $e );
-                       return; // do not make the site unavailable
-               }
-
-               $query = array( 'title' => 'Special:RunJobs',
-                       'tasks' => 'jobs', 'maxjobs' => $n, 'sigexpiry' => time() + 5 );
-               $query['signature'] = SpecialRunJobs::getQuerySignature( $query );
-
-               $errno = $errstr = null;
-               $info = wfParseUrl( $wgServer );
-               wfSuppressWarnings();
-               $sock = fsockopen(
-                       $info['host'],
-                       isset( $info['port'] ) ? $info['port'] : 80,
-                       $errno,
-                       $errstr,
-                       // If it takes more than 100ms to connect to ourselves there
-                       // is a problem elsewhere.
-                       0.1
-               );
-               wfRestoreWarnings();
-               if ( !$sock ) {
-                       wfDebugLog( 'runJobs', "Failed to start cron API (socket error $errno): $errstr\n" );
-                       // Fall back to running the job here while the user waits
-                       SpecialRunJobs::executeJobs( $n );
-                       return;
-               }
-
-               $url = wfAppendQuery( wfScript( 'index' ), $query );
-               $req = "POST $url HTTP/1.1\r\nHost: {$info['host']}\r\nConnection: Close\r\n\r\n";
-
-               wfDebugLog( 'runJobs', "Running $n job(s) via '$url'\n" );
-               // Send a cron API request to be performed in the background.
-               // Give up if this takes too long to send (which should be rare).
-               stream_set_timeout( $sock, 1 );
-               $bytes = fwrite( $sock, $req );
-               if ( $bytes !== strlen( $req ) ) {
-                       wfDebugLog( 'runJobs', "Failed to start cron API (socket write error)\n" );
-               } else {
-                       // Do not wait for the response (the script should handle client aborts).
-                       // Make sure that we don't close before that script reaches ignore_user_abort().
-                       $status = fgets( $sock );
-                       if ( !preg_match( '#^HTTP/\d\.\d 202 #', $status ) ) {
-                               wfDebugLog( 'runJobs', "Failed to start cron API: received '$status'\n" );
-                       }
-               }
-               fclose( $sock );
-       }
-}
index d4b08b2..839d0ed 100644 (file)
@@ -360,10 +360,4 @@ abstract class Action {
         * @throws ErrorPageError
         */
        abstract public function show();
-
-       /**
-        * Execute the action in a silent fashion: do not display anything or release any errors.
-        * @return bool whether execution was successful
-        */
-       abstract public function execute();
 }
index 32efc68..bc4df34 100644 (file)
@@ -110,7 +110,7 @@ abstract class CachedAction extends FormlessAction implements ICacheHelper {
         *
         * @since 1.20
         *
-        * @param {function} $computeFunction
+        * @param callable $computeFunction
         * @param array|mixed $args
         * @param string|null $key
         *
@@ -128,7 +128,7 @@ abstract class CachedAction extends FormlessAction implements ICacheHelper {
         *
         * @since 1.20
         *
-        * @param {function} $computeFunction
+        * @param callable $computeFunction
         * @param array $args
         * @param string|null $key
         */
index 7477d11..c6fcdde 100644 (file)
@@ -121,48 +121,4 @@ abstract class FormAction extends Action {
                        $this->onSuccess();
                }
        }
-
-       /**
-        * @see Action::execute()
-        *
-        * @param array|null $data
-        * @param bool $captureErrors
-        * @throws ErrorPageError|Exception
-        * @return bool
-        */
-       public function execute( array $data = null, $captureErrors = true ) {
-               try {
-                       // Set a new context so output doesn't leak.
-                       $this->context = clone $this->getContext();
-
-                       // This will throw exceptions if there's a problem
-                       $this->checkCanExecute( $this->getUser() );
-
-                       $fields = array();
-                       foreach ( $this->fields as $key => $params ) {
-                               if ( isset( $data[$key] ) ) {
-                                       $fields[$key] = $data[$key];
-                               } elseif ( isset( $params['default'] ) ) {
-                                       $fields[$key] = $params['default'];
-                               } else {
-                                       $fields[$key] = null;
-                               }
-                       }
-                       $status = $this->onSubmit( $fields );
-                       if ( $status === true ) {
-                               // This might do permanent stuff
-                               $this->onSuccess();
-                               return true;
-                       } else {
-                               return false;
-                       }
-               }
-               catch ( ErrorPageError $e ) {
-                       if ( $captureErrors ) {
-                               return false;
-                       } else {
-                               throw $e;
-                       }
-               }
-       }
 }
index 0039838..f61fc97 100644 (file)
@@ -35,29 +35,6 @@ abstract class FormlessAction extends Action {
         */
        abstract public function onView();
 
-       /**
-        * We don't want an HTMLForm
-        * @return bool
-        */
-       protected function getFormFields() {
-               return false;
-       }
-
-       /**
-        * @param array $data
-        * @return bool
-        */
-       public function onSubmit( $data ) {
-               return false;
-       }
-
-       /**
-        * @return bool
-        */
-       public function onSuccess() {
-               return false;
-       }
-
        public function show() {
                $this->setHeaders();
 
@@ -66,35 +43,4 @@ abstract class FormlessAction extends Action {
 
                $this->getOutput()->addHTML( $this->onView() );
        }
-
-       /**
-        * Execute the action silently, not giving any output.  Since these actions don't have
-        * forms, they probably won't have any data, but some (eg rollback) may do
-        * @param array $data Values that would normally be in the GET request
-        * @param bool $captureErrors Whether to catch exceptions and just return false
-        * @throws ErrorPageError|Exception
-        * @return bool Whether execution was successful
-        */
-       public function execute( array $data = null, $captureErrors = true ) {
-               try {
-                       // Set a new context so output doesn't leak.
-                       $this->context = clone $this->getContext();
-                       if ( is_array( $data ) ) {
-                               $this->context->setRequest( new FauxRequest( $data, false ) );
-                       }
-
-                       // This will throw exceptions if there's a problem
-                       $this->checkCanExecute( $this->getUser() );
-
-                       $this->onView();
-                       return true;
-               }
-               catch ( ErrorPageError $e ) {
-                       if ( $captureErrors ) {
-                               return false;
-                       } else {
-                               throw $e;
-                       }
-               }
-       }
 }
index b0274ff..7b3a356 100644 (file)
@@ -214,7 +214,7 @@ class HistoryAction extends FormlessAction {
         *
         * @param int $limit The limit number of revisions to get
         * @param int $offset
-        * @param int $direction Either HistoryPage::DIR_PREV or HistoryPage::DIR_NEXT
+        * @param int $direction Either self::DIR_PREV or self::DIR_NEXT
         * @return ResultWrapper
         */
        function fetchRevisions( $limit, $offset, $direction ) {
@@ -225,9 +225,9 @@ class HistoryAction extends FormlessAction {
 
                $dbr = wfGetDB( DB_SLAVE );
 
-               if ( $direction == HistoryPage::DIR_PREV ) {
+               if ( $direction === self::DIR_PREV ) {
                        list( $dirs, $oper ) = array( "ASC", ">=" );
-               } else { /* $direction == HistoryPage::DIR_NEXT */
+               } else { /* $direction === self::DIR_NEXT */
                        list( $dirs, $oper ) = array( "DESC", "<=" );
                }
 
@@ -273,7 +273,7 @@ class HistoryAction extends FormlessAction {
                $limit = $request->getInt( 'limit', 10 );
                $limit = min( max( $limit, 1 ), $wgFeedLimit );
 
-               $items = $this->fetchRevisions( $limit, 0, HistoryPage::DIR_NEXT );
+               $items = $this->fetchRevisions( $limit, 0, self::DIR_NEXT );
 
                // Generate feed elements enclosed between header and footer.
                $feed->outHeader();
@@ -886,18 +886,3 @@ class HistoryPager extends ReverseChronologicalPager {
                return $this->preventClickjacking;
        }
 }
-
-/**
- * Backwards-compatibility alias
- */
-class HistoryPage extends HistoryAction {
-       // @codingStandardsIgnoreStart Needed "useless" override to make it public.
-       public function __construct( Page $article ) {
-               parent::__construct( $article );
-       }
-       // @codingStandardsIgnoreEnd
-
-       public function history() {
-               $this->onView();
-       }
-}
index a212915..4baf7b9 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright © 2004 Gabriel Wicke <wicke@wikidev.net>
  * http://wikidev.net/
  *
- * Based on HistoryPage and SpecialExport
+ * Based on HistoryAction and SpecialExport
  *
  * 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
@@ -252,40 +252,3 @@ class RawAction extends FormlessAction {
                return $ctype;
        }
 }
-
-/**
- * Backward compatibility for extensions
- *
- * @deprecated since 1.19
- */
-class RawPage extends RawAction {
-       public $mOldId;
-
-       /**
-        * @param Page $page
-        * @param WebRequest|bool $request The WebRequest (default: false).
-        */
-       function __construct( Page $page, $request = false ) {
-               wfDeprecated( __CLASS__, '1.19' );
-               parent::__construct( $page );
-
-               if ( $request !== false ) {
-                       $context = new DerivativeContext( $this->getContext() );
-                       $context->setRequest( $request );
-                       $this->context = $context;
-               }
-       }
-
-       public function view() {
-               $this->onView();
-       }
-
-       public function getOldId() {
-               # Some extensions like to set $mOldId
-               if ( $this->mOldId !== null ) {
-                       return $this->mOldId;
-               }
-
-               return parent::getOldId();
-       }
-}
index cdd139e..6481630 100644 (file)
  */
 
 /**
- * Dummy class for pages not in NS_FILE
- *
- * @ingroup Actions
- */
-class RevertAction extends Action {
-
-       public function getName() {
-               return 'revert';
-       }
-
-       public function show() {
-               $this->getOutput()->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
-       }
-
-       public function execute() {
-       }
-}
-
-/**
- * Class for pages in NS_FILE
+ * File reversion user interface
  *
  * @ingroup Actions
  */
-class RevertFileAction extends FormAction {
+class RevertAction extends FormAction {
        /**
         * @var OldLocalFile
         */
@@ -62,6 +43,9 @@ class RevertFileAction extends FormAction {
        }
 
        protected function checkCanExecute( User $user ) {
+               if ( $this->getTitle()->getNamespace() !== NS_FILE ) {
+                       throw new ErrorPageError( $this->msg( 'nosuchaction' ), $this->msg( 'nosuchactiontext' ) );
+               }
                parent::checkCanExecute( $user );
 
                $oldimage = $this->getRequest()->getText( 'oldimage' );
@@ -86,6 +70,7 @@ class RevertFileAction extends FormAction {
                $form->setWrapperLegendMsg( 'filerevert-legend' );
                $form->setSubmitTextMsg( 'filerevert-submit' );
                $form->addHiddenField( 'oldimage', $this->getRequest()->getText( 'oldimage' ) );
+               $form->setTokenSalt( array( 'revert', $this->getTitle()->getPrefixedDBkey() ) );
        }
 
        protected function getFormFields() {
index d221799..7ebd0c3 100644 (file)
@@ -251,10 +251,8 @@ abstract class ApiBase extends ContextSource {
                }
                $msg = array();
                ApiResult::setContent( $msg, $warning );
-               $result->disableSizeCheck();
                $result->addValue( 'warnings', $moduleName,
-                       $msg, ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP );
-               $result->enableSizeCheck();
+                       $msg, ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
        }
 
        /**
@@ -1189,9 +1187,9 @@ abstract class ApiBase extends ContextSource {
         * @param mixed $value The value being parsed
         * @param bool $allowMultiple Can $value contain more than one value
         *  separated by '|'?
-        * @param mixed $allowedValues An array of values to check against. If
+        * @param string[]|null $allowedValues An array of values to check against. If
         *  null, all values are accepted.
-        * @return mixed (allowMultiple ? an_array_of_values : a_single_value)
+        * @return string|string[] (allowMultiple ? an_array_of_values : a_single_value)
         */
        protected function parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues ) {
                if ( trim( $value ) === '' && $allowMultiple ) {
index 82d303f..b3a9d83 100644 (file)
@@ -42,8 +42,10 @@ class ApiExpandTemplates extends ApiBase {
                $this->requireMaxOneParameter( $params, 'prop', 'generatexml' );
 
                if ( $params['prop'] === null ) {
-                       $this->setWarning( 'Because no values have been specified for the prop parameter, a legacy format has been used for the output.'
-                                . ' This format is deprecated, and in the future, a default value will be set for the prop parameter, causing the new format to always be used.' );
+                       $this->setWarning( 'Because no values have been specified for the prop parameter, a ' .
+                               'legacy format has been used for the output. This format is deprecated, and in ' .
+                               'the future, a default value will be set for the prop parameter, causing the new' .
+                               'format to always be used.' );
                        $prop = array();
                } else {
                        $prop = array_flip( $params['prop'] );
@@ -159,9 +161,12 @@ class ApiExpandTemplates extends ApiBase {
                        'prop' => array(
                                'Which pieces of information to get',
                                ' wikitext   - The expanded wikitext',
-                               ' categories - Any categories present in the input that are not represented in the wikitext output',
-                               ' volatile   - Whether the output is volatile and should not be reused elsewhere within the page',
-                               ' ttl        - The maximum time after which caches of the result should be invalidated',
+                               ' categories - Any categories present in the input that are not represented in ' .
+                                       'the wikitext output',
+                               ' volatile   - Whether the output is volatile and should not be reused ' .
+                                       'elsewhere within the page',
+                               ' ttl        - The maximum time after which caches of the result should be ' .
+                                       'invalidated',
                                ' parsetree  - The XML parse tree of the input',
                                'Note that if no values are selected, the result will contain the wikitext,',
                                'but the output will be in a deprecated format.',
index 03a6843..848d129 100644 (file)
@@ -362,10 +362,8 @@ class ApiFormatFeedWrapper extends ApiFormatBase {
                // Disable size checking for this because we can't continue
                // cleanly; size checking would cause more problems than it'd
                // solve
-               $result->disableSizeCheck();
-               $result->addValue( null, '_feed', $feed );
-               $result->addValue( null, '_feeditems', $feedItems );
-               $result->enableSizeCheck();
+               $result->addValue( null, '_feed', $feed, ApiResult::NO_SIZE_CHECK );
+               $result->addValue( null, '_feeditems', $feedItems, ApiResult::NO_SIZE_CHECK );
        }
 
        /**
index b8e16ab..c932a74 100644 (file)
@@ -52,6 +52,8 @@ class ApiImageRotate extends ApiBase {
                $params = $this->extractRequestParams();
                $rotation = $params['rotation'];
 
+               $this->getResult()->beginContinuation( $params['continue'], array(), array() );
+
                $pageSet = $this->getPageSet();
                $pageSet->execute();
 
@@ -131,6 +133,7 @@ class ApiImageRotate extends ApiBase {
                $apiResult = $this->getResult();
                $apiResult->setIndexedTagName( $result, 'page' );
                $apiResult->addValue( null, $this->getModuleName(), $result );
+               $apiResult->endContinuation();
        }
 
        /**
@@ -185,6 +188,7 @@ class ApiImageRotate extends ApiBase {
                                ApiBase::PARAM_TYPE => 'string',
                                ApiBase::PARAM_REQUIRED => true
                        ),
+                       'continue' => '',
                );
                if ( $flags ) {
                        $result += $this->getPageSet()->getFinalParams( $flags );
@@ -199,6 +203,7 @@ class ApiImageRotate extends ApiBase {
                return $pageSet->getFinalParamDescription() + array(
                        'rotation' => 'Degrees to rotate image clockwise',
                        'token' => 'Edit token. You can get one of these through action=tokens',
+                       'continue' => 'When more results are available, use this to continue',
                );
        }
 
index 84db9ed..a5873e6 100644 (file)
@@ -699,21 +699,20 @@ class ApiMain extends ApiBase {
                $warnings = isset( $oldResult['warnings'] ) ? $oldResult['warnings'] : null;
 
                $result->reset();
-               $result->disableSizeCheck();
                // Re-add the id
                $requestid = $this->getParameter( 'requestid' );
                if ( !is_null( $requestid ) ) {
-                       $result->addValue( null, 'requestid', $requestid );
+                       $result->addValue( null, 'requestid', $requestid, ApiResult::NO_SIZE_CHECK );
                }
                if ( $config->get( 'ShowHostnames' ) ) {
                        // servedby is especially useful when debugging errors
-                       $result->addValue( null, 'servedby', wfHostName() );
+                       $result->addValue( null, 'servedby', wfHostName(), ApiResult::NO_SIZE_CHECK );
                }
                if ( $warnings !== null ) {
-                       $result->addValue( null, 'warnings', $warnings );
+                       $result->addValue( null, 'warnings', $warnings, ApiResult::NO_SIZE_CHECK );
                }
 
-               $result->addValue( null, 'error', $errMessage );
+               $result->addValue( null, 'error', $errMessage, ApiResult::NO_SIZE_CHECK );
 
                return $errMessage['code'];
        }
index b906b59..2e993e3 100644 (file)
@@ -213,7 +213,7 @@ class ApiParse extends ApiBase {
                        }
 
                        if ( $this->section !== false ) {
-                               $this->content = $this->getSectionContent( $this->content, $titleObj->getText() );
+                               $this->content = $this->getSectionContent( $this->content, $titleObj->getPrefixedText() );
                        }
 
                        if ( $params['pst'] || $params['onlypst'] ) {
@@ -450,7 +450,7 @@ class ApiParse extends ApiBase {
                if ( $this->section !== false && $this->content !== null ) {
                        $this->content = $this->getSectionContent(
                                $this->content,
-                               !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getText()
+                               !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
                        );
 
                        // Not cached (save or load)
@@ -470,6 +470,10 @@ class ApiParse extends ApiBase {
                return $pout;
        }
 
+       /**
+        * @param Content $content
+        * @param string $what Identifies the content in error messages, e.g. page title.
+        */
        private function getSectionContent( Content $content, $what ) {
                // Not cached (save or load)
                $section = $content->getSection( $this->section );
index 981dc18..3399843 100644 (file)
@@ -38,6 +38,8 @@ class ApiPurge extends ApiBase {
        public function execute() {
                $params = $this->extractRequestParams();
 
+               $this->getResult()->beginContinuation( $params['continue'], array(), array() );
+
                $forceLinkUpdate = $params['forcelinkupdate'];
                $forceRecursiveLinkUpdate = $params['forcerecursivelinkupdate'];
                $pageSet = $this->getPageSet();
@@ -102,6 +104,8 @@ class ApiPurge extends ApiBase {
                if ( $values ) {
                        $apiResult->addValue( null, 'redirects', $values );
                }
+
+               $apiResult->endContinuation();
        }
 
        /**
@@ -128,7 +132,8 @@ class ApiPurge extends ApiBase {
        public function getAllowedParams( $flags = 0 ) {
                $result = array(
                        'forcelinkupdate' => false,
-                       'forcerecursivelinkupdate' => false
+                       'forcerecursivelinkupdate' => false,
+                       'continue' => '',
                );
                if ( $flags ) {
                        $result += $this->getPageSet()->getFinalParams( $flags );
@@ -143,6 +148,7 @@ class ApiPurge extends ApiBase {
                                'forcelinkupdate' => 'Update the links tables',
                                'forcerecursivelinkupdate' => 'Update the links table, and update ' .
                                        'the links tables for any page that uses this page as a template',
+                               'continue' => 'When more results are available, use this to continue',
                        );
        }
 
index a2f4121..f4b28fa 100644 (file)
@@ -118,8 +118,6 @@ class ApiQuery extends ApiBase {
        private $mParams;
        private $mNamedDB = array();
        private $mModuleMgr;
-       private $mGeneratorContinue;
-       private $mUseLegacyContinue;
 
        /**
         * @param ApiMain $main
@@ -245,23 +243,24 @@ class ApiQuery extends ApiBase {
        public function execute() {
                $this->mParams = $this->extractRequestParams();
 
-               // $pagesetParams is a array of parameter names used by the pageset generator
-               //   or null if pageset has already finished and is no longer needed
-               // $completeModules is a set of complete modules with the name as key
-               $this->initContinue( $pagesetParams, $completeModules );
-
                // Instantiate requested modules
                $allModules = array();
                $this->instantiateModules( $allModules, 'prop' );
-               $propModules = $allModules; // Keep a copy
+               $propModules = array_keys( $allModules );
                $this->instantiateModules( $allModules, 'list' );
                $this->instantiateModules( $allModules, 'meta' );
 
                // Filter modules based on continue parameter
-               $modules = $this->initModules( $allModules, $completeModules, $pagesetParams !== null );
+               list( $generatorDone, $modules ) = $this->getResult()->beginContinuation(
+                       $this->mParams['continue'], $allModules, $propModules
+               );
 
-               // Execute pageset if in legacy mode or if pageset is not done
-               if ( $completeModules === null || $pagesetParams !== null ) {
+               if ( !$generatorDone ) {
+                       // Query modules may optimize data requests through the $this->getPageSet()
+                       // object by adding extra fields from the page table.
+                       foreach ( $modules as $module ) {
+                               $module->requestExtraData( $this->mPageSet );
+                       }
                        // Populate page/revision information
                        $this->mPageSet->execute();
                        // Record page information (title, namespace, if exists, etc)
@@ -287,135 +286,10 @@ class ApiQuery extends ApiBase {
                // Set the cache mode
                $this->getMain()->setCacheMode( $cacheMode );
 
-               if ( $completeModules === null ) {
-                       return; // Legacy continue, we are done
-               }
-
-               // Reformat query-continue result section
-               $result = $this->getResult();
-               $qc = $result->getData();
-               if ( isset( $qc['query-continue'] ) ) {
-                       $qc = $qc['query-continue'];
-                       $result->unsetValue( null, 'query-continue' );
-               } elseif ( $this->mGeneratorContinue !== null ) {
-                       $qc = array();
-               } else {
-                       // no more "continue"s, we are done!
-                       return;
-               }
-
-               // we are done with all the modules that do not have result in query-continue
-               $completeModules = array_merge( $completeModules, array_diff_key( $modules, $qc ) );
-               if ( $pagesetParams !== null ) {
-                       // The pageset is still in use, check if all props have finished
-                       $incompleteProps = array_intersect_key( $propModules, $qc );
-                       if ( count( $incompleteProps ) > 0 ) {
-                               // Properties are not done, continue with the same pageset state - copy current parameters
-                               $main = $this->getMain();
-                               $contValues = array();
-                               foreach ( $pagesetParams as $param ) {
-                                       // The param name is already prefix-encoded
-                                       $contValues[$param] = $main->getVal( $param );
-                               }
-                       } elseif ( $this->mGeneratorContinue !== null ) {
-                               // Move to the next set of pages produced by pageset, properties need to be restarted
-                               $contValues = $this->mGeneratorContinue;
-                               $pagesetParams = array_keys( $contValues );
-                               $completeModules = array_diff_key( $completeModules, $propModules );
-                       } else {
-                               // Done with the pageset, finish up with the the lists and meta modules
-                               $pagesetParams = null;
-                       }
-               }
-
-               $continue = '||' . implode( '|', array_keys( $completeModules ) );
-               if ( $pagesetParams !== null ) {
-                       // list of all pageset parameters to use in the next request
-                       $continue = implode( '|', $pagesetParams ) . $continue;
-               } else {
-                       // we are done with the pageset
-                       $contValues = array();
-                       $continue = '-' . $continue;
-               }
-               $contValues['continue'] = $continue;
-               foreach ( $qc as $qcModule ) {
-                       foreach ( $qcModule as $qcKey => $qcValue ) {
-                               $contValues[$qcKey] = $qcValue;
-                       }
-               }
-               $this->getResult()->addValue( null, 'continue', $contValues );
-       }
-
-       /**
-        * Parse 'continue' parameter into the list of complete modules and a list of generator parameters
-        * @param array|null $pagesetParams Returns list of generator params or null if pageset is done
-        * @param array|null $completeModules Returns list of finished modules (as keys), or null if legacy
-        */
-       private function initContinue( &$pagesetParams, &$completeModules ) {
-               $pagesetParams = array();
-               $continue = $this->mParams['continue'];
-               if ( $continue !== null ) {
-                       $this->mUseLegacyContinue = false;
-                       if ( $continue !== '' ) {
-                               // Format: ' pagesetParam1 | pagesetParam2 || module1 | module2 | module3 | ...
-                               // If pageset is done, use '-'
-                               $continue = explode( '||', $continue );
-                               $this->dieContinueUsageIf( count( $continue ) !== 2 );
-                               if ( $continue[0] === '-' ) {
-                                       $pagesetParams = null; // No need to execute pageset
-                               } elseif ( $continue[0] !== '' ) {
-                                       // list of pageset params that might need to be repeated
-                                       $pagesetParams = explode( '|', $continue[0] );
-                               }
-                               $continue = $continue[1];
-                       }
-                       if ( $continue !== '' ) {
-                               $completeModules = array_flip( explode( '|', $continue ) );
-                       } else {
-                               $completeModules = array();
-                       }
-               } else {
-                       $this->mUseLegacyContinue = true;
-                       $completeModules = null;
-               }
-       }
-
-       /**
-        * Validate sub-modules, filter out completed ones, and do requestExtraData()
-        * @param array $allModules An dict of name=>instance of all modules requested by the client
-        * @param array|null $completeModules List of finished modules, or null if legacy continue
-        * @param bool $usePageset True if pageset will be executed
-        * @return array Array of modules to be processed during this execution
-        */
-       private function initModules( $allModules, $completeModules, $usePageset ) {
-               $modules = $allModules;
-               $tmp = $completeModules;
-               $wasPosted = $this->getRequest()->wasPosted();
-
-               /** @var $module ApiQueryBase */
-               foreach ( $allModules as $moduleName => $module ) {
-                       if ( !$wasPosted && $module->mustBePosted() ) {
-                               $this->dieUsageMsgOrDebug( array( 'mustbeposted', $moduleName ) );
-                       }
-                       if ( $completeModules !== null && array_key_exists( $moduleName, $completeModules ) ) {
-                               // If this module is done, mark all its params as used
-                               $module->extractRequestParams();
-                               // Make sure this module is not used during execution
-                               unset( $modules[$moduleName] );
-                               unset( $tmp[$moduleName] );
-                       } elseif ( $completeModules === null || $usePageset ) {
-                               // Query modules may optimize data requests through the $this->getPageSet()
-                               // object by adding extra fields from the page table.
-                               // This function will gather all the extra request fields from the modules.
-                               $module->requestExtraData( $this->mPageSet );
-                       } else {
-                               // Error - this prop module must have finished before generator is done
-                               $this->dieContinueUsageIf( $this->mModuleMgr->getModuleGroup( $moduleName ) === 'prop' );
-                       }
-               }
-               $this->dieContinueUsageIf( $completeModules !== null && count( $tmp ) !== 0 );
-
-               return $modules;
+               // Write the continuation data into the result
+               $this->getResult()->endContinuation(
+                       $this->mParams['continue'] === null ? 'raw' : 'standard'
+               );
        }
 
        /**
@@ -447,12 +321,16 @@ class ApiQuery extends ApiBase {
         * @param string $param Parameter name to read modules from
         */
        private function instantiateModules( &$modules, $param ) {
+               $wasPosted = $this->getRequest()->wasPosted();
                if ( isset( $this->mParams[$param] ) ) {
                        foreach ( $this->mParams[$param] as $moduleName ) {
                                $instance = $this->mModuleMgr->getModule( $moduleName, $param );
                                if ( $instance === null ) {
                                        ApiBase::dieDebug( __METHOD__, 'Error instantiating module' );
                                }
+                               if ( !$wasPosted && $instance->mustBePosted() ) {
+                                       $this->dieUsageMsgOrDebug( array( 'mustbeposted', $moduleName ) );
+                               }
                                // Ignore duplicates. TODO 2.0: die()?
                                if ( !array_key_exists( $moduleName, $modules ) ) {
                                        $modules[$moduleName] = $instance;
@@ -563,22 +441,16 @@ class ApiQuery extends ApiBase {
         * This method is called by the generator base when generator in the smart-continue
         * mode tries to set 'query-continue' value. ApiQuery stores those values separately
         * until the post-processing when it is known if the generation should continue or repeat.
+        * @deprecated @since 1.24
         * @param ApiQueryGeneratorBase $module Generator module
         * @param string $paramName
         * @param mixed $paramValue
         * @return bool True if processed, false if this is a legacy continue
         */
        public function setGeneratorContinue( $module, $paramName, $paramValue ) {
-               if ( $this->mUseLegacyContinue ) {
-                       return false;
-               }
-               $paramName = $module->encodeParamName( $paramName );
-               if ( $this->mGeneratorContinue === null ) {
-                       $this->mGeneratorContinue = array();
-               }
-               $this->mGeneratorContinue[$paramName] = $paramValue;
-
-               return true;
+               wfDeprecated( __METHOD__, '1.24' );
+               $this->getResult()->setGeneratorContinueParam( $module, $paramName, $paramValue );
+               return $this->getParameter( 'continue' ) !== null;
        }
 
        /**
@@ -613,18 +485,16 @@ class ApiQuery extends ApiBase {
                // Don't check the size of exported stuff
                // It's not continuable, so it would cause more
                // problems than it'd solve
-               $result->disableSizeCheck();
                if ( $this->mParams['exportnowrap'] ) {
                        $result->reset();
                        // Raw formatter will handle this
-                       $result->addValue( null, 'text', $exportxml );
-                       $result->addValue( null, 'mime', 'text/xml' );
+                       $result->addValue( null, 'text', $exportxml, ApiResult::NO_SIZE_CHECK );
+                       $result->addValue( null, 'mime', 'text/xml', ApiResult::NO_SIZE_CHECK );
                } else {
                        $r = array();
                        ApiResult::setContent( $r, $exportxml );
-                       $result->addValue( 'query', 'export', $r );
+                       $result->addValue( 'query', 'export', $r, ApiResult::NO_SIZE_CHECK );
                }
-               $result->enableSizeCheck();
        }
 
        public function getAllowedParams( $flags = 0 ) {
index e32104f..d0980e6 100644 (file)
@@ -45,9 +45,15 @@ class ApiQueryAllUsers extends ApiQueryBase {
        }
 
        public function execute() {
-               $db = $this->getDB();
                $params = $this->extractRequestParams();
 
+               if ( $params['activeusers'] ) {
+                       // Update active user cache
+                       SpecialActiveUsers::mergeActiveUsers( 600 );
+               }
+
+               $db = $this->getDB();
+
                $prop = $params['prop'];
                if ( !is_null( $prop ) ) {
                        $prop = array_flip( $prop );
@@ -71,9 +77,9 @@ class ApiQueryAllUsers extends ApiQueryBase {
                $from = is_null( $params['from'] ) ? null : $this->getCanonicalUserName( $params['from'] );
                $to = is_null( $params['to'] ) ? null : $this->getCanonicalUserName( $params['to'] );
 
-               # MySQL doesn't seem to use 'equality propagation' here, so like the
-               # ActiveUsers special page, we have to use rc_user_text for some cases.
-               $userFieldToSort = $params['activeusers'] ? 'rc_user_text' : 'user_name';
+               # MySQL can't figure out that 'user_name' and 'qcc_title' are the same
+               # despite the JOIN condition, so manually sort on the correct one.
+               $userFieldToSort = $params['activeusers'] ? 'qcc_title' : 'user_name';
 
                $this->addWhereRange( $userFieldToSort, $dir, $from, $to );
 
@@ -155,19 +161,32 @@ class ApiQueryAllUsers extends ApiQueryBase {
                }
 
                if ( $params['activeusers'] ) {
-                       $this->addTables( 'recentchanges' );
-
-                       $this->addJoinConds( array( 'recentchanges' => array(
-                               'INNER JOIN', 'rc_user_text=user_name'
+                       $activeUserSeconds = $this->getConfig()->get( 'ActiveUserDays' ) * 86400;
+
+                       // Filter query to only include users in the active users cache
+                       $this->addTables( 'querycachetwo' );
+                       $this->addJoinConds( array( 'querycachetwo' => array(
+                               'INNER JOIN', array(
+                                       'qcc_type' => 'activeusers',
+                                       'qcc_namespace' => NS_USER,
+                                       'qcc_title=user_name',
+                               ),
                        ) ) );
 
-                       $this->addFields( array( 'recentedits' => 'COUNT(*)' ) );
-
-                       $this->addWhere( 'rc_log_type IS NULL OR rc_log_type != ' . $db->addQuotes( 'newusers' ) );
-                       $timestamp = $db->timestamp( wfTimestamp( TS_UNIX ) - $this->getConfig()->get( 'ActiveUserDays' ) * 24 * 3600 );
-                       $this->addWhere( 'rc_timestamp >= ' . $db->addQuotes( $timestamp ) );
-
-                       $this->addOption( 'GROUP BY', $userFieldToSort );
+                       // Actually count the actions using a subquery (bug 64505 and bug 64507)
+                       $timestamp = $db->timestamp( wfTimestamp( TS_UNIX ) - $activeUserSeconds );
+                       $this->addFields( array(
+                               'recentactions' => '(' . $db->selectSQLText(
+                                       'recentchanges',
+                                       'COUNT(*)',
+                                       array(
+                                               'rc_user_text = user_name',
+                                               'rc_type != ' . $db->addQuotes( RC_EXTERNAL ), // no wikidata
+                                               'rc_log_type IS NULL OR rc_log_type != ' . $db->addQuotes( 'newusers' ),
+                                               'rc_timestamp >= ' . $db->addQuotes( $timestamp ),
+                                       )
+                               ) . ')'
+                       ) );
                }
 
                $this->addOption( 'LIMIT', $sqlLimit );
@@ -203,8 +222,13 @@ class ApiQueryAllUsers extends ApiQueryBase {
                        if ( $lastUser !== $row->user_name ) {
                                // Save the last pass's user data
                                if ( is_array( $lastUserData ) ) {
-                                       $fit = $result->addValue( array( 'query', $this->getModuleName() ),
-                                               null, $lastUserData );
+                                       if ( $params['activeusers'] && $lastUserData['recentactions'] === 0 ) {
+                                               // activeusers cache was out of date
+                                               $fit = true;
+                                       } else {
+                                               $fit = $result->addValue( array( 'query', $this->getModuleName() ),
+                                                       null, $lastUserData );
+                                       }
 
                                        $lastUserData = null;
 
@@ -241,7 +265,9 @@ class ApiQueryAllUsers extends ApiQueryBase {
                                        $lastUserData['editcount'] = intval( $row->user_editcount );
                                }
                                if ( $params['activeusers'] ) {
-                                       $lastUserData['recenteditcount'] = intval( $row->recentedits );
+                                       $lastUserData['recentactions'] = intval( $row->recentactions );
+                                       // @todo 'recenteditcount' is set for BC, remove in 1.25
+                                       $lastUserData['recenteditcount'] = $lastUserData['recentactions'];
                                }
                                if ( $fld_registration ) {
                                        $lastUserData['registration'] = $row->user_registration ?
@@ -302,7 +328,9 @@ class ApiQueryAllUsers extends ApiQueryBase {
                        }
                }
 
-               if ( is_array( $lastUserData ) ) {
+               if ( is_array( $lastUserData ) &&
+                       !( $params['activeusers'] && $lastUserData['recentactions'] === 0 )
+               ) {
                        $fit = $result->addValue( array( 'query', $this->getModuleName() ),
                                null, $lastUserData );
                        if ( !$fit ) {
@@ -397,7 +425,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
                        '' => array(
                                'userid' => 'integer',
                                'name' => 'string',
-                               'recenteditcount' => array(
+                               'recentactions' => array(
                                        ApiBase::PROP_TYPE => 'integer',
                                        ApiBase::PROP_NULLABLE => true
                                )
index 8e014df..ebfd8b2 100644 (file)
@@ -75,8 +75,8 @@ abstract class ApiQueryBase extends ApiBase {
 
        /**
         * Add a set of tables to the internal array
-        * @param mixed $tables Table name or array of table names
-        * @param mixed $alias Table alias, or null for no alias. Cannot be
+        * @param string|string[] $tables Table name or array of table names
+        * @param string|null $alias Table alias, or null for no alias. Cannot be
         *  used with multiple tables
         */
        protected function addTables( $tables, $alias = null ) {
@@ -398,15 +398,10 @@ abstract class ApiQueryBase extends ApiBase {
        /**
         * Set a query-continue value
         * @param string $paramName Parameter name
-        * @param string $paramValue Parameter value
+        * @param string|array $paramValue Parameter value
         */
        protected function setContinueEnumParameter( $paramName, $paramValue ) {
-               $paramName = $this->encodeParamName( $paramName );
-               $msg = array( $paramName => $paramValue );
-               $result = $this->getResult();
-               $result->disableSizeCheck();
-               $result->addValue( 'query-continue', $this->getModuleName(), $msg, ApiResult::ADD_ON_TOP );
-               $result->enableSizeCheck();
+               $this->getResult()->setContinueParam( $this, $paramName, $paramValue );
        }
 
        /**
@@ -615,7 +610,12 @@ abstract class ApiQueryBase extends ApiBase {
         * @return bool
         */
        public function userCanSeeRevDel() {
-               return $this->getUser()->isAllowedAny( 'deletedhistory', 'deletedtext', 'suppressrevision' );
+               return $this->getUser()->isAllowedAny(
+                       'deletedhistory',
+                       'deletedtext',
+                       'suppressrevision',
+                       'viewsuppressed'
+               );
        }
 }
 
@@ -667,16 +667,14 @@ abstract class ApiQueryGeneratorBase extends ApiQueryBase {
        }
 
        /**
-        * Overrides base in case of generator & smart continue to
-        * notify ApiQueryMain instead of adding them to the result right away.
+        * Overridden to set the generator param if in generator mode
         * @param string $paramName Parameter name
-        * @param string $paramValue Parameter value
+        * @param string|array $paramValue Parameter value
         */
        protected function setContinueEnumParameter( $paramName, $paramValue ) {
-               // If this is a generator and query->setGeneratorContinue() returns false, treat as before
-               if ( $this->mGeneratorPageSet === null
-                       || !$this->getQuery()->setGeneratorContinue( $this, $paramName, $paramValue )
-               ) {
+               if ( $this->mGeneratorPageSet !== null ) {
+                       $this->getResult()->setGeneratorContinueParam( $this, $paramName, $paramValue );
+               } else {
                        parent::setContinueEnumParameter( $paramName, $paramValue );
                }
        }
index af0d938..4f77078 100644 (file)
@@ -134,11 +134,17 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
                }
 
                if ( $fld_content ) {
+                       // Modern MediaWiki has the content for deleted revs in the 'text'
+                       // table using fields old_text and old_flags. But revisions deleted
+                       // pre-1.5 store the content in the 'archive' table directly using
+                       // fields ar_text and ar_flags, and no corresponding 'text' row. So
+                       // we have to LEFT JOIN and fetch all four fields, plus ar_text_id
+                       // to be able to tell the difference.
                        $this->addTables( 'text' );
                        $this->addJoinConds(
-                               array( 'text' => array( 'INNER JOIN', array( 'ar_text_id=old_id' ) ) )
+                               array( 'text' => array( 'LEFT JOIN', array( 'ar_text_id=old_id' ) ) )
                        );
-                       $this->addFields( array( 'ar_text', 'ar_text_id', 'old_text', 'old_flags' ) );
+                       $this->addFields( array( 'ar_text', 'ar_flags', 'ar_text_id', 'old_text', 'old_flags' ) );
 
                        // This also means stricter restrictions
                        if ( !$user->isAllowedAny( 'undelete', 'deletedtext' ) ) {
@@ -204,7 +210,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
                        // check it again just in case)
                        if ( !$user->isAllowed( 'deletedhistory' ) ) {
                                $bitmask = Revision::DELETED_USER;
-                       } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+                       } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                                $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
@@ -353,7 +359,12 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
                                        $anyHidden = true;
                                }
                                if ( Revision::userCanBitfield( $row->ar_deleted, Revision::DELETED_TEXT, $user ) ) {
-                                       ApiResult::setContent( $rev, Revision::getRevisionText( $row ) );
+                                       if ( isset( $row->ar_text ) && !$row->ar_text_id ) {
+                                               // Pre-1.5 ar_text row (if condition from Revision::newFromArchiveRow)
+                                               ApiResult::setContent( $rev, Revision::getRevisionText( $row, 'ar_' ) );
+                                       } else {
+                                               ApiResult::setContent( $rev, Revision::getRevisionText( $row ) );
+                                       }
                                }
                        }
 
index 97918e3..a94b4fa 100644 (file)
@@ -67,9 +67,8 @@ class ApiQueryFilearchive extends ApiQueryBase {
                $this->addTables( 'filearchive' );
 
                $this->addFields( ArchivedFile::selectFields() );
-               $this->addFields( array( 'fa_name', 'fa_deleted' ) );
+               $this->addFields( array( 'fa_id', 'fa_name', 'fa_timestamp', 'fa_deleted' ) );
                $this->addFieldsIf( 'fa_sha1', $fld_sha1 );
-               $this->addFieldsIf( 'fa_timestamp', $fld_timestamp );
                $this->addFieldsIf( array( 'fa_user', 'fa_user_text' ), $fld_user );
                $this->addFieldsIf( array( 'fa_height', 'fa_width', 'fa_size' ), $fld_dimensions || $fld_size );
                $this->addFieldsIf( 'fa_description', $fld_description );
@@ -81,18 +80,23 @@ class ApiQueryFilearchive extends ApiQueryBase {
 
                if ( !is_null( $params['continue'] ) ) {
                        $cont = explode( '|', $params['continue'] );
-                       $this->dieContinueUsageIf( count( $cont ) != 1 );
+                       $this->dieContinueUsageIf( count( $cont ) != 3 );
                        $op = $params['dir'] == 'descending' ? '<' : '>';
                        $cont_from = $db->addQuotes( $cont[0] );
-                       $this->addWhere( "fa_name $op= $cont_from" );
+                       $cont_timestamp = $db->addQuotes( $db->timestamp( $cont[1] ) );
+                       $cont_id = (int)$cont[2];
+                       $this->dieContinueUsageIf( $cont[2] !== (string)$cont_id );
+                       $this->addWhere( "fa_name $op $cont_from OR " .
+                               "(fa_name = $cont_from AND " .
+                               "(fa_timestamp $op $cont_timestamp OR " .
+                               "(fa_timestamp = $cont_timestamp AND " .
+                               "fa_id $op= $cont_id )))"
+                       );
                }
 
                // Image filters
                $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
                $from = ( $params['from'] === null ? null : $this->titlePartToKey( $params['from'], NS_FILE ) );
-               if ( !is_null( $params['continue'] ) ) {
-                       $from = $params['continue'];
-               }
                $to = ( $params['to'] === null ? null : $this->titlePartToKey( $params['to'], NS_FILE ) );
                $this->addWhereRange( 'fa_name', $dir, $from, $to );
                if ( isset( $params['prefix'] ) ) {
@@ -125,7 +129,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
                // Exclude files this user can't view.
                if ( !$user->isAllowed( 'deletedtext' ) ) {
                        $bitmask = File::DELETED_FILE;
-               } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                        $bitmask = File::DELETED_FILE | File::DELETED_RESTRICTED;
                } else {
                        $bitmask = 0;
@@ -137,7 +141,11 @@ class ApiQueryFilearchive extends ApiQueryBase {
                $limit = $params['limit'];
                $this->addOption( 'LIMIT', $limit + 1 );
                $sort = ( $params['dir'] == 'descending' ? ' DESC' : '' );
-               $this->addOption( 'ORDER BY', 'fa_name' . $sort );
+               $this->addOption( 'ORDER BY', array(
+                       'fa_name' . $sort,
+                       'fa_timestamp' . $sort,
+                       'fa_id' . $sort,
+               ) );
 
                $res = $this->select( __METHOD__ );
 
@@ -147,11 +155,14 @@ class ApiQueryFilearchive extends ApiQueryBase {
                        if ( ++$count > $limit ) {
                                // We've reached the one extra which shows that there are
                                // additional pages to be had. Stop here...
-                               $this->setContinueEnumParameter( 'continue', $row->fa_name );
+                               $this->setContinueEnumParameter(
+                                       'continue', "$row->fa_name|$row->fa_timestamp|$row->fa_id"
+                               );
                                break;
                        }
 
                        $file = array();
+                       $file['id'] = $row->fa_id;
                        $file['name'] = $row->fa_name;
                        $title = Title::makeTitle( NS_FILE, $row->fa_name );
                        self::addTitleInfo( $file, $title );
@@ -222,7 +233,9 @@ class ApiQueryFilearchive extends ApiQueryBase {
 
                        $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $file );
                        if ( !$fit ) {
-                               $this->setContinueEnumParameter( 'continue', $row->fa_name );
+                               $this->setContinueEnumParameter(
+                                       'continue', "$row->fa_name|$row->fa_timestamp|$row->fa_id"
+                               );
                                break;
                        }
                }
index 3aad785..d79deec 100644 (file)
@@ -204,7 +204,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
                        if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) {
                                $titleBits = LogPage::DELETED_ACTION;
                                $userBits = LogPage::DELETED_USER;
-                       } elseif ( !$this->getUser()->isAllowed( 'suppressrevision' ) ) {
+                       } elseif ( !$this->getUser()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                                $titleBits = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED;
                                $userBits = LogPage::DELETED_USER | LogPage::DELETED_RESTRICTED;
                        } else {
index e4078d5..44d287b 100644 (file)
@@ -329,7 +329,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) {
                        if ( !$user->isAllowed( 'deletedhistory' ) ) {
                                $bitmask = Revision::DELETED_USER;
-                       } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+                       } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                                $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
@@ -342,7 +342,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                        // LogPage::DELETED_ACTION hides the affected page, too.
                        if ( !$user->isAllowed( 'deletedhistory' ) ) {
                                $bitmask = LogPage::DELETED_ACTION;
-                       } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+                       } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                                $bitmask = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
@@ -405,7 +405,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
        /**
         * Extracts from a single sql row the data needed to describe one recent change.
         *
-        * @param mixed $row The row from which to extract the data.
+        * @param stdClass $row The row from which to extract the data.
         * @return array An array mapping strings (descriptors) to their respective string values.
         * @access public
         */
index 3ff6805..582f61e 100644 (file)
@@ -318,7 +318,7 @@ class ApiQueryRevisions extends ApiQueryBase {
                                // Paranoia: avoid brute force searches (bug 17342)
                                if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) {
                                        $bitmask = Revision::DELETED_USER;
-                               } elseif ( !$this->getUser()->isAllowed( 'suppressrevision' ) ) {
+                               } elseif ( !$this->getUser()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                                        $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
                                } else {
                                        $bitmask = 0;
index aacf091..30201fc 100644 (file)
@@ -136,7 +136,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
 
                $data['generator'] = "MediaWiki {$config->get( 'Version' )}";
 
-               $data['phpversion'] = phpversion();
+               $data['phpversion'] = PHP_VERSION;
                $data['phpsapi'] = PHP_SAPI;
                $data['dbtype'] = $config->get( 'DBtype' );
                $data['dbversion'] = $this->getDB()->getServerVersion();
@@ -242,7 +242,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                $data['articlepath'] = $config->get( 'ArticlePath' );
                $data['scriptpath'] = $config->get( 'ScriptPath' );
                $data['script'] = $config->get( 'Script' );
-               $data['variantarticlepath'] = $config->get( 'VariantArticlePath'  );
+               $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
                $data['server'] = $config->get( 'Server' );
                $data['servername'] = $config->get( 'ServerName' );
                $data['wikiid'] = wfWikiID();
@@ -262,8 +262,8 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                        $data['imagelimits'][$k] = array( 'width' => $limit[0], 'height' => $limit[1] );
                }
 
-                $favicon = $config->get( 'Favicon' );
-                if ( !empty( $favicon ) ) {
+               $favicon = $config->get( 'Favicon' );
+               if ( !empty( $favicon ) ) {
                        // wgFavicon can either be a relative or an absolute path
                        // make sure we always return an absolute path
                        $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
@@ -314,7 +314,8 @@ class ApiQuerySiteinfo extends ApiQueryBase {
 
        protected function appendNamespaceAliases( $property ) {
                global $wgContLang;
-               $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ), $wgContLang->getNamespaceAliases() );
+               $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ),
+                       $wgContLang->getNamespaceAliases() );
                $namespaces = $wgContLang->getNamespaces();
                $data = array();
                foreach ( $aliases as $title => $ns ) {
@@ -420,7 +421,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                        }
 
                        $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
-                       if (substr( $row['iw_url'], 0, 2) == '//') {
+                       if ( substr( $row['iw_url'], 0, 2 ) == '//' ) {
                                $val['protorel'] = '';
                        }
                        if ( isset( $row['iw_wikiid'] ) ) {
index 24c4c20..29d0300 100644 (file)
@@ -193,7 +193,7 @@ class ApiQueryContributions extends ApiQueryBase {
                // see the username.
                if ( !$user->isAllowed( 'deletedhistory' ) ) {
                        $bitmask = Revision::DELETED_USER;
-               } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                        $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
                } else {
                        $bitmask = 0;
@@ -326,7 +326,7 @@ class ApiQueryContributions extends ApiQueryBase {
        /**
         * Extract fields from the database row and append them to a result array
         *
-        * @param mixed $row
+        * @param stdClass $row
         * @return array
         */
        private function extractRowInfo( $row ) {
index 506fb59..b1b84d8 100644 (file)
@@ -224,7 +224,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) {
                        if ( !$user->isAllowed( 'deletedhistory' ) ) {
                                $bitmask = Revision::DELETED_USER;
-                       } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+                       } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                                $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
                        } else {
                                $bitmask = 0;
@@ -238,7 +238,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                // entirely from the watchlist, or someone could guess the title.
                if ( !$user->isAllowed( 'deletedhistory' ) ) {
                        $bitmask = LogPage::DELETED_ACTION;
-               } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                        $bitmask = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED;
                } else {
                        $bitmask = 0;
index 7d0a15a..97b74e5 100644 (file)
@@ -58,8 +58,23 @@ class ApiResult extends ApiBase {
         */
        const ADD_ON_TOP = 2;
 
+       /**
+        * For addValue() and setElement(), do not check size while adding a value
+        * Don't use this unless you REALLY know what you're doing.
+        * Values added while the size checking was disabled will never be counted
+        * @since 1.24
+        */
+       const NO_SIZE_CHECK = 4;
+
        private $mData, $mIsRawMode, $mSize, $mCheckingSize;
 
+       private $continueAllModules = array();
+       private $continueGeneratedModules = array();
+       private $continuationData = array();
+       private $generatorContinuationData = array();
+       private $generatorParams = array();
+       private $generatorDone = false;
+
        /**
         * @param ApiMain $main
         */
@@ -136,6 +151,7 @@ class ApiResult extends ApiBase {
         * Disable size checking in addValue(). Don't use this unless you
         * REALLY know what you're doing. Values added while size checking
         * was disabled will not be counted (ever)
+        * @deprecated since 1.24, use ApiResult::NO_SIZE_CHECK
         */
        public function disableSizeCheck() {
                $this->mCheckingSize = false;
@@ -143,6 +159,7 @@ class ApiResult extends ApiBase {
 
        /**
         * Re-enable size checking in addValue()
+        * @deprecated since 1.24, use ApiResult::NO_SIZE_CHECK
         */
        public function enableSizeCheck() {
                $this->mCheckingSize = true;
@@ -305,17 +322,16 @@ class ApiResult extends ApiBase {
         * @param array|string|null $path
         * @param string $name
         * @param mixed $value
-        * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP. This
-        *    parameter used to be boolean, and the value of OVERRIDE=1 was specifically
-        *    chosen so that it would be backwards compatible with the new method
-        *    signature.
+        * @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
+        *   This parameter used to be boolean, and the value of OVERRIDE=1 was specifically
+        *   chosen so that it would be backwards compatible with the new method signature.
         * @return bool True if $value fits in the result, false if not
         *
         * @since 1.21 int $flags replaced boolean $override
         */
        public function addValue( $path, $name, $value, $flags = 0 ) {
                $data = &$this->mData;
-               if ( $this->mCheckingSize ) {
+               if ( $this->mCheckingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
                        $newsize = $this->mSize + self::size( $value );
                        $maxResultSize = $this->getConfig()->get( 'APIMaxResultSize' );
                        if ( $newsize > $maxResultSize ) {
@@ -437,4 +453,179 @@ class ApiResult extends ApiBase {
        public function execute() {
                ApiBase::dieDebug( __METHOD__, 'execute() is not supported on Result object' );
        }
+
+       /**
+        * Parse a 'continue' parameter and return status information.
+        *
+        * This must be balanced by a call to endContinuation().
+        *
+        * @since 1.24
+        * @param string|null $continue The "continue" parameter, if any
+        * @param array $allModules Contains ApiBase instances that will be executed
+        * @param array $generatedModules Names of modules that depend on the generator
+        * @return array Two elements: a boolean indicating if the generator is done,
+        *   and an array of modules to actually execute.
+        */
+       public function beginContinuation(
+               $continue, array $allModules = array(), array $generatedModules = array()
+       ) {
+               $this->continueGeneratedModules = $generatedModules
+                       ? array_combine( $generatedModules, $generatedModules )
+                       : array();
+               $this->continuationData = array();
+               $this->generatorContinuationData = array();
+               $this->generatorParams = array();
+
+               $skip = array();
+               if ( is_string( $continue ) && $continue !== '' ) {
+                       $continue = explode( '||', $continue );
+                       $this->dieContinueUsageIf( count( $continue ) !== 2 );
+                       $this->generatorDone = ( $continue[0] === '-' );
+                       if ( !$this->generatorDone ) {
+                               $this->generatorParams = explode( '|', $continue[0] );
+                       }
+                       $skip = explode( '|', $continue[1] );
+               }
+
+               $this->continueAllModules = array();
+               $runModules = array();
+               foreach ( $allModules as $module ) {
+                       $name = $module->getModuleName();
+                       if ( in_array( $name, $skip ) ) {
+                               $this->continueAllModules[$name] = false;
+                               // Prevent spurious "unused parameter" warnings
+                               $module->extractRequestParams();
+                       } else {
+                               $this->continueAllModules[$name] = true;
+                               $runModules[] = $module;
+                       }
+               }
+
+               return array(
+                       $this->generatorDone,
+                       $runModules,
+               );
+       }
+
+       /**
+        * Set the continuation parameter for a module
+        *
+        * @since 1.24
+        * @param ApiBase $module
+        * @param string $paramName
+        * @param string|array $paramValue
+        */
+       public function setContinueParam( ApiBase $module, $paramName, $paramValue ) {
+               $name = $module->getModuleName();
+               if ( !isset( $this->continueAllModules[$name] ) ) {
+                       throw new MWException(
+                               "Module '$name' called ApiResult::setContinueParam but was not " .
+                               'passed to ApiResult::beginContinuation'
+                       );
+               }
+               if ( !$this->continueAllModules[$name] ) {
+                       throw new MWException(
+                               "Module '$name' was not supposed to have been executed, but " .
+                               'it was executed anyway'
+                       );
+               }
+               $paramName = $module->encodeParamName( $paramName );
+               if ( is_array( $paramValue ) ) {
+                       $paramValue = join( '|', $paramValue );
+               }
+               $this->continuationData[$name][$paramName] = $paramValue;
+       }
+
+       /**
+        * Set the continuation parameter for the generator module
+        *
+        * @since 1.24
+        * @param ApiBase $module
+        * @param string $paramName
+        * @param string|array $paramValue
+        */
+       public function setGeneratorContinueParam( ApiBase $module, $paramName, $paramValue ) {
+               $name = $module->getModuleName();
+               $paramName = $module->encodeParamName( $paramName );
+               if ( is_array( $paramValue ) ) {
+                       $paramValue = join( '|', $paramValue );
+               }
+               $this->generatorContinuationData[$name][$paramName] = $paramValue;
+       }
+
+       /**
+        * Close continuation, writing the data into the result
+        *
+        * @since 1.24
+        * @param string $style 'standard' for the new style since 1.21, 'raw' for
+        *   the style used in 1.20 and earlier.
+        */
+       public function endContinuation( $style = 'standard' ) {
+               if ( $style === 'raw' ) {
+                       $key = 'query-continue';
+                       $data = array_merge_recursive(
+                               $this->continuationData, $this->generatorContinuationData
+                       );
+               } else {
+                       $key = 'continue';
+                       $data = array();
+
+                       $finishedModules = array_diff(
+                               array_keys( $this->continueAllModules ),
+                               array_keys( $this->continuationData )
+                       );
+
+                       // First, grab the non-generator-using continuation data
+                       $continuationData = array_diff_key(
+                               $this->continuationData, $this->continueGeneratedModules
+                       );
+                       foreach ( $continuationData as $module => $kvp ) {
+                               $data += $kvp;
+                       }
+
+                       // Next, handle the generator-using continuation data
+                       $continuationData = array_intersect_key(
+                               $this->continuationData, $this->continueGeneratedModules
+                       );
+                       if ( $continuationData ) {
+                               // Some modules are unfinished: include those params, and copy
+                               // the generator params.
+                               foreach ( $continuationData as $module => $kvp ) {
+                                       $data += $kvp;
+                               }
+                               $data += array_intersect_key(
+                                       $this->getMain()->getRequest()->getValues(),
+                                       array_flip( $this->generatorParams )
+                               );
+                       } elseif ( $this->generatorContinuationData ) {
+                               // All the generator-using modules are complete, but the
+                               // generator isn't. Continue the generator and restart the
+                               // generator-using modules
+                               $this->generatorParams = array();
+                               foreach ( $this->generatorContinuationData as $kvp ) {
+                                       $this->generatorParams = array_merge(
+                                               $this->generatorParams, array_keys( $kvp )
+                                       );
+                                       $data += $kvp;
+                               }
+                               $finishedModules = array_diff(
+                                       $finishedModules, $this->continueGeneratedModules
+                               );
+                       } else {
+                               // Generator and prop modules are all done. Mark it so.
+                               $this->generatorDone = true;
+                       }
+
+                       // Set 'continue' if any continuation data is set or if the generator
+                       // still needs to run
+                       if ( $data || !$this->generatorDone ) {
+                               $data['continue'] =
+                                       ( $this->generatorDone ? '-' : join( '|', $this->generatorParams ) ) .
+                                       '||' . join( '|', $finishedModules );
+                       }
+               }
+               if ( $data ) {
+                       $this->addValue( null, $key, $data, ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
+               }
+       }
 }
index dc593e5..04be450 100644 (file)
@@ -46,6 +46,8 @@ class ApiSetNotificationTimestamp extends ApiBase {
                $params = $this->extractRequestParams();
                $this->requireMaxOneParameter( $params, 'timestamp', 'torevid', 'newerthanrevid' );
 
+               $this->getResult()->beginContinuation( $params['continue'], array(), array() );
+
                $pageSet = $this->getPageSet();
                if ( $params['entirewatchlist'] && $pageSet->getDataSource() !== null ) {
                        $this->dieUsage(
@@ -70,22 +72,26 @@ class ApiSetNotificationTimestamp extends ApiBase {
                                $this->dieUsage( 'torevid may only be used with a single page', 'multpages' );
                        }
                        $title = reset( $pageSet->getGoodTitles() );
-                       $timestamp = Revision::getTimestampFromId( $title, $params['torevid'] );
-                       if ( $timestamp ) {
-                               $timestamp = $dbw->timestamp( $timestamp );
-                       } else {
-                               $timestamp = null;
+                       if ( $title ) {
+                               $timestamp = Revision::getTimestampFromId( $title, $params['torevid'] );
+                               if ( $timestamp ) {
+                                       $timestamp = $dbw->timestamp( $timestamp );
+                               } else {
+                                       $timestamp = null;
+                               }
                        }
                } elseif ( isset( $params['newerthanrevid'] ) ) {
                        if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
                                $this->dieUsage( 'newerthanrevid may only be used with a single page', 'multpages' );
                        }
                        $title = reset( $pageSet->getGoodTitles() );
-                       $revid = $title->getNextRevisionID( $params['newerthanrevid'] );
-                       if ( $revid ) {
-                               $timestamp = $dbw->timestamp( Revision::getTimestampFromId( $title, $revid ) );
-                       } else {
-                               $timestamp = null;
+                       if ( $title ) {
+                               $revid = $title->getNextRevisionID( $params['newerthanrevid'] );
+                               if ( $revid ) {
+                                       $timestamp = $dbw->timestamp( Revision::getTimestampFromId( $title, $revid ) );
+                               } else {
+                                       $timestamp = null;
+                               }
                        }
                }
 
@@ -124,51 +130,55 @@ class ApiSetNotificationTimestamp extends ApiBase {
                                $result[] = $rev;
                        }
 
-                       // Now process the valid titles
-                       $lb = new LinkBatch( $pageSet->getTitles() );
-                       $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $timestamp ),
-                               array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
-                               __METHOD__
-                       );
-
-                       // Query the results of our update
-                       $timestamps = array();
-                       $res = $dbw->select(
-                               'watchlist',
-                               array( 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ),
-                               array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
-                               __METHOD__
-                       );
-                       foreach ( $res as $row ) {
-                               $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp;
-                       }
+                       if ( $pageSet->getTitles() ) {
+                               // Now process the valid titles
+                               $lb = new LinkBatch( $pageSet->getTitles() );
+                               $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $timestamp ),
+                                       array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
+                                       __METHOD__
+                               );
 
-                       // Now, put the valid titles into the result
-                       /** @var $title Title */
-                       foreach ( $pageSet->getTitles() as $title ) {
-                               $ns = $title->getNamespace();
-                               $dbkey = $title->getDBkey();
-                               $r = array(
-                                       'ns' => intval( $ns ),
-                                       'title' => $title->getPrefixedText(),
+                               // Query the results of our update
+                               $timestamps = array();
+                               $res = $dbw->select(
+                                       'watchlist',
+                                       array( 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ),
+                                       array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
+                                       __METHOD__
                                );
-                               if ( !$title->exists() ) {
-                                       $r['missing'] = '';
+                               foreach ( $res as $row ) {
+                                       $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp;
                                }
-                               if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] ) ) {
-                                       $r['notificationtimestamp'] = '';
-                                       if ( $timestamps[$ns][$dbkey] !== null ) {
-                                               $r['notificationtimestamp'] = wfTimestamp( TS_ISO_8601, $timestamps[$ns][$dbkey] );
+
+                               // Now, put the valid titles into the result
+                               /** @var $title Title */
+                               foreach ( $pageSet->getTitles() as $title ) {
+                                       $ns = $title->getNamespace();
+                                       $dbkey = $title->getDBkey();
+                                       $r = array(
+                                               'ns' => intval( $ns ),
+                                               'title' => $title->getPrefixedText(),
+                                       );
+                                       if ( !$title->exists() ) {
+                                               $r['missing'] = '';
                                        }
-                               } else {
-                                       $r['notwatched'] = '';
+                                       if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] ) ) {
+                                               $r['notificationtimestamp'] = '';
+                                               if ( $timestamps[$ns][$dbkey] !== null ) {
+                                                       $r['notificationtimestamp'] = wfTimestamp( TS_ISO_8601, $timestamps[$ns][$dbkey] );
+                                               }
+                                       } else {
+                                               $r['notwatched'] = '';
+                                       }
+                                       $result[] = $r;
                                }
-                               $result[] = $r;
                        }
 
                        $apiResult->setIndexedTagName( $result, 'page' );
                }
                $apiResult->addValue( null, $this->getModuleName(), $result );
+
+               $apiResult->endContinuation();
        }
 
        /**
@@ -214,6 +224,7 @@ class ApiSetNotificationTimestamp extends ApiBase {
                        'newerthanrevid' => array(
                                ApiBase::PARAM_TYPE => 'integer'
                        ),
+                       'continue' => '',
                );
                if ( $flags ) {
                        $result += $this->getPageSet()->getFinalParams( $flags );
@@ -229,6 +240,7 @@ class ApiSetNotificationTimestamp extends ApiBase {
                        'torevid' => 'Revision to set the notification timestamp to (one page only)',
                        'newerthanrevid' => 'Revision to set the notification timestamp newer than (one page only)',
                        'token' => 'A token previously acquired via prop=info',
+                       'continue' => 'When more results are available, use this to continue',
                );
        }
 
index 6dfb1b4..c5aa90e 100644 (file)
@@ -43,6 +43,9 @@ class ApiWatch extends ApiBase {
                }
 
                $params = $this->extractRequestParams();
+
+               $this->getResult()->beginContinuation( $params['continue'], array(), array() );
+
                $pageSet = $this->getPageSet();
                // by default we use pageset to extract the page to work on.
                // title is still supported for backward compatibility
@@ -88,6 +91,7 @@ class ApiWatch extends ApiBase {
                        $res = $this->watchTitle( $title, $user, $params, true );
                }
                $this->getResult()->addValue( null, $this->getModuleName(), $res );
+               $this->getResult()->endContinuation();
        }
 
        private function watchTitle( Title $title, User $user, array $params,
@@ -180,6 +184,7 @@ class ApiWatch extends ApiBase {
                                ApiBase::PARAM_TYPE => 'string',
                                ApiBase::PARAM_REQUIRED => true
                        ),
+                       'continue' => '',
                );
                if ( $flags ) {
                        $result += $this->getPageSet()->getFinalParams( $flags );
@@ -196,6 +201,7 @@ class ApiWatch extends ApiBase {
                        'unwatch' => 'If set the page will be unwatched rather than watched',
                        'uselang' => 'Language to show the message in',
                        'token' => 'A token previously acquired via prop=info',
+                       'continue' => 'When more results are available, use this to continue',
                );
        }
 
index 7b83990..15d7c89 100644 (file)
@@ -101,7 +101,7 @@ class DependencyWrapper {
         * @param BagOStuff $cache A cache object such as $wgMemc
         * @param string $key The cache key
         * @param int $expiry The expiry timestamp or interval in seconds
-        * @param bool|array $callback The callback for generating the value, or false
+        * @param bool|callable $callback The callback for generating the value, or false
         * @param array $callbackParams The function parameters for the callback
         * @param array $deps The dependencies to store on a cache miss. Note: these
         *    are not the dependencies used on a cache hit! Cache hits use the stored
diff --git a/includes/cache/CacheHelper.php b/includes/cache/CacheHelper.php
new file mode 100644 (file)
index 0000000..401c2b9
--- /dev/null
@@ -0,0 +1,386 @@
+<?php
+/**
+ * Cache of various elements in a single cache entry.
+ *
+ * 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
+ * @license GNU GPL v2 or later
+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
+ */
+
+/**
+ * Interface for all classes implementing CacheHelper functionality.
+ *
+ * @since 1.20
+ */
+interface ICacheHelper {
+       /**
+        * Sets if the cache should be enabled or not.
+        *
+        * @since 1.20
+        * @param bool $cacheEnabled
+        */
+       function setCacheEnabled( $cacheEnabled );
+
+       /**
+        * Initializes the caching.
+        * Should be called before the first time anything is added via addCachedHTML.
+        *
+        * @since 1.20
+        *
+        * @param int|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
+        * @param bool|null $cacheEnabled Sets if the cache should be enabled or not.
+        */
+       function startCache( $cacheExpiry = null, $cacheEnabled = null );
+
+       /**
+        * Get a cached value if available or compute it if not and then cache it if possible.
+        * The provided $computeFunction is only called when the computation needs to happen
+        * and should return a result value. $args are arguments that will be passed to the
+        * compute function when called.
+        *
+        * @since 1.20
+        *
+        * @param callable $computeFunction
+        * @param array|mixed $args
+        * @param string|null $key
+        *
+        * @return mixed
+        */
+       function getCachedValue( $computeFunction, $args = array(), $key = null );
+
+       /**
+        * Saves the HTML to the cache in case it got recomputed.
+        * Should be called after the last time anything is added via addCachedHTML.
+        *
+        * @since 1.20
+        */
+       function saveCache();
+
+       /**
+        * Sets the time to live for the cache, in seconds or a unix timestamp
+        * indicating the point of expiry...
+        *
+        * @since 1.20
+        *
+        * @param int $cacheExpiry
+        */
+       function setExpiry( $cacheExpiry );
+}
+
+/**
+ * Helper class for caching various elements in a single cache entry.
+ *
+ * To get a cached value or compute it, use getCachedValue like this:
+ * $this->getCachedValue( $callback );
+ *
+ * To add HTML that should be cached, use addCachedHTML like this:
+ * $this->addCachedHTML( $callback );
+ *
+ * The callback function is only called when needed, so do all your expensive
+ * computations here. This function should returns the HTML to be cached.
+ * It should not add anything to the PageOutput object!
+ *
+ * Before the first addCachedHTML call, you should call $this->startCache();
+ * After adding the last HTML that should be cached, call $this->saveCache();
+ *
+ * @since 1.20
+ */
+class CacheHelper implements ICacheHelper {
+       /**
+        * The time to live for the cache, in seconds or a unix timestamp indicating the point of expiry.
+        *
+        * @since 1.20
+        * @var int
+        */
+       protected $cacheExpiry = 3600;
+
+       /**
+        * List of HTML chunks to be cached (if !hasCached) or that where cached (of hasCached).
+        * If not cached already, then the newly computed chunks are added here,
+        * if it as cached already, chunks are removed from this list as they are needed.
+        *
+        * @since 1.20
+        * @var array
+        */
+       protected $cachedChunks;
+
+       /**
+        * Indicates if the to be cached content was already cached.
+        * Null if this information is not available yet.
+        *
+        * @since 1.20
+        * @var bool|null
+        */
+       protected $hasCached = null;
+
+       /**
+        * If the cache is enabled or not.
+        *
+        * @since 1.20
+        * @var bool
+        */
+       protected $cacheEnabled = true;
+
+       /**
+        * Function that gets called when initialization is done.
+        *
+        * @since 1.20
+        * @var callable
+        */
+       protected $onInitHandler = false;
+
+       /**
+        * Elements to build a cache key with.
+        *
+        * @since 1.20
+        * @var array
+        */
+       protected $cacheKey = array();
+
+       /**
+        * Sets if the cache should be enabled or not.
+        *
+        * @since 1.20
+        * @param bool $cacheEnabled
+        */
+       public function setCacheEnabled( $cacheEnabled ) {
+               $this->cacheEnabled = $cacheEnabled;
+       }
+
+       /**
+        * Initializes the caching.
+        * Should be called before the first time anything is added via addCachedHTML.
+        *
+        * @since 1.20
+        *
+        * @param int|null $cacheExpiry Sets the cache expiry, either ttl in seconds or unix timestamp.
+        * @param bool|null $cacheEnabled Sets if the cache should be enabled or not.
+        */
+       public function startCache( $cacheExpiry = null, $cacheEnabled = null ) {
+               if ( is_null( $this->hasCached ) ) {
+                       if ( !is_null( $cacheExpiry ) ) {
+                               $this->cacheExpiry = $cacheExpiry;
+                       }
+
+                       if ( !is_null( $cacheEnabled ) ) {
+                               $this->setCacheEnabled( $cacheEnabled );
+                       }
+
+                       $this->initCaching();
+               }
+       }
+
+       /**
+        * Returns a message that notifies the user he/she is looking at
+        * a cached version of the page, including a refresh link.
+        *
+        * @since 1.20
+        *
+        * @param IContextSource $context
+        * @param bool $includePurgeLink
+        *
+        * @return string
+        */
+       public function getCachedNotice( IContextSource $context, $includePurgeLink = true ) {
+               if ( $this->cacheExpiry < 86400 * 3650 ) {
+                       $message = $context->msg(
+                               'cachedspecial-viewing-cached-ttl',
+                               $context->getLanguage()->formatDuration( $this->cacheExpiry )
+                       )->escaped();
+               } else {
+                       $message = $context->msg(
+                               'cachedspecial-viewing-cached-ts'
+                       )->escaped();
+               }
+
+               if ( $includePurgeLink ) {
+                       $refreshArgs = $context->getRequest()->getQueryValues();
+                       unset( $refreshArgs['title'] );
+                       $refreshArgs['action'] = 'purge';
+
+                       $subPage = $context->getTitle()->getFullText();
+                       $subPage = explode( '/', $subPage, 2 );
+                       $subPage = count( $subPage ) > 1 ? $subPage[1] : false;
+
+                       $message .= ' ' . Linker::link(
+                               $context->getTitle( $subPage ),
+                               $context->msg( 'cachedspecial-refresh-now' )->escaped(),
+                               array(),
+                               $refreshArgs
+                       );
+               }
+
+               return $message;
+       }
+
+       /**
+        * Initializes the caching if not already done so.
+        * Should be called before any of the caching functionality is used.
+        *
+        * @since 1.20
+        */
+       protected function initCaching() {
+               if ( $this->cacheEnabled && is_null( $this->hasCached ) ) {
+                       $cachedChunks = wfGetCache( CACHE_ANYTHING )->get( $this->getCacheKeyString() );
+
+                       $this->hasCached = is_array( $cachedChunks );
+                       $this->cachedChunks = $this->hasCached ? $cachedChunks : array();
+
+                       if ( $this->onInitHandler !== false ) {
+                               call_user_func( $this->onInitHandler, $this->hasCached );
+                       }
+               }
+       }
+
+       /**
+        * Get a cached value if available or compute it if not and then cache it if possible.
+        * The provided $computeFunction is only called when the computation needs to happen
+        * and should return a result value. $args are arguments that will be passed to the
+        * compute function when called.
+        *
+        * @since 1.20
+        *
+        * @param callable $computeFunction
+        * @param array|mixed $args
+        * @param string|null $key
+        *
+        * @return mixed
+        */
+       public function getCachedValue( $computeFunction, $args = array(), $key = null ) {
+               $this->initCaching();
+
+               if ( $this->cacheEnabled && $this->hasCached ) {
+                       $value = null;
+
+                       if ( is_null( $key ) ) {
+                               $itemKey = array_keys( array_slice( $this->cachedChunks, 0, 1 ) );
+                               $itemKey = array_shift( $itemKey );
+
+                               if ( !is_integer( $itemKey ) ) {
+                                       wfWarn( "Attempted to get item with non-numeric key while " .
+                                               "the next item in the queue has a key ($itemKey) in " . __METHOD__ );
+                               } elseif ( is_null( $itemKey ) ) {
+                                       wfWarn( "Attempted to get an item while the queue is empty in " . __METHOD__ );
+                               } else {
+                                       $value = array_shift( $this->cachedChunks );
+                               }
+                       } 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__ );
+                               }
+                       }
+               } else {
+                       if ( !is_array( $args ) ) {
+                               $args = array( $args );
+                       }
+
+                       $value = call_user_func_array( $computeFunction, $args );
+
+                       if ( $this->cacheEnabled ) {
+                               if ( is_null( $key ) ) {
+                                       $this->cachedChunks[] = $value;
+                               } else {
+                                       $this->cachedChunks[$key] = $value;
+                               }
+                       }
+               }
+
+               return $value;
+       }
+
+       /**
+        * Saves the HTML to the cache in case it got recomputed.
+        * Should be called after the last time anything is added via addCachedHTML.
+        *
+        * @since 1.20
+        */
+       public function saveCache() {
+               if ( $this->cacheEnabled && $this->hasCached === false && !empty( $this->cachedChunks ) ) {
+                       wfGetCache( CACHE_ANYTHING )->set(
+                               $this->getCacheKeyString(),
+                               $this->cachedChunks,
+                               $this->cacheExpiry
+                       );
+               }
+       }
+
+       /**
+        * Sets the time to live for the cache, in seconds or a unix timestamp
+        * indicating the point of expiry...
+        *
+        * @since 1.20
+        *
+        * @param int $cacheExpiry
+        */
+       public function setExpiry( $cacheExpiry ) {
+               $this->cacheExpiry = $cacheExpiry;
+       }
+
+       /**
+        * Returns the cache key to use to cache this page's HTML output.
+        * Is constructed from the special page name and language code.
+        *
+        * @since 1.20
+        *
+        * @return string
+        * @throws MWException
+        */
+       protected function getCacheKeyString() {
+               if ( $this->cacheKey === array() ) {
+                       throw new MWException( 'No cache key set, so cannot obtain or save the CacheHelper values.' );
+               }
+
+               return call_user_func_array( 'wfMemcKey', $this->cacheKey );
+       }
+
+       /**
+        * Sets the cache key that should be used.
+        *
+        * @since 1.20
+        *
+        * @param array $cacheKey
+        */
+       public function setCacheKey( array $cacheKey ) {
+               $this->cacheKey = $cacheKey;
+       }
+
+       /**
+        * Rebuild the content, even if it's already cached.
+        * This effectively has the same effect as purging the cache,
+        * since it will be overridden with the new value on the next request.
+        *
+        * @since 1.20
+        */
+       public function rebuildOnDemand() {
+               $this->hasCached = false;
+       }
+
+       /**
+        * Sets a function that gets called when initialization of the cache is done.
+        *
+        * @since 1.20
+        *
+        * @param callable $handlerFunction
+        */
+       public function setOnInitializedHandler( $handlerFunction ) {
+               $this->onInitHandler = $handlerFunction;
+       }
+}
index ec36cfb..91fb878 100644 (file)
@@ -1163,8 +1163,8 @@ class LCStoreDB implements LCStore {
        private $readOnly = false;
 
        public function get( $code, $key ) {
-               if ( $this->writesDone ) {
-                       $db = wfGetDB( DB_MASTER );
+               if ( $this->writesDone && $this->dbw ) {
+                       $db = $this->dbw;
                } else {
                        $db = wfGetDB( DB_SLAVE );
                }
@@ -1184,7 +1184,16 @@ class LCStoreDB implements LCStore {
                        throw new MWException( __METHOD__ . ": Invalid language \"$code\"" );
                }
 
-               $this->dbw = wfGetDB( DB_MASTER );
+               // We must keep a separate connection to MySQL in order to avoid breaking
+               // main transactions. However, SQLite deadlocks when using two connections.
+               // @todo get this trick to work on PostgreSQL too
+               if ( wfGetDB( DB_MASTER )->getType() == 'mysql' ) {
+                       $lb = wfGetLBFactory()->newMainLB();
+                       $this->dbw = $lb->getConnection( DB_MASTER );
+                       $this->dbw->clearFlag( DBO_TRX ); // auto-commit mode
+               } else {
+                       $this->dbw = wfGetDB( DB_MASTER );
+               }
 
                $this->currentLang = $code;
                $this->batch = array();
diff --git a/includes/changes/ChangesFeed.php b/includes/changes/ChangesFeed.php
new file mode 100644 (file)
index 0000000..fb491e5
--- /dev/null
@@ -0,0 +1,239 @@
+<?php
+/**
+ * Feed for list of changes.
+ *
+ * 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
+ */
+
+/**
+ * Feed to Special:RecentChanges and Special:RecentChangesLiked
+ *
+ * @ingroup Feed
+ */
+class ChangesFeed {
+       public $format, $type, $titleMsg, $descMsg;
+
+       /**
+        * Constructor
+        *
+        * @param string $format Feed's format (either 'rss' or 'atom')
+        * @param string $type Type of feed (for cache keys)
+        */
+       public function __construct( $format, $type ) {
+               $this->format = $format;
+               $this->type = $type;
+       }
+
+       /**
+        * Get a ChannelFeed subclass object to use
+        *
+        * @param string $title Feed's title
+        * @param string $description Feed's description
+        * @param string $url Url of origin page
+        * @return ChannelFeed|bool ChannelFeed subclass or false on failure
+        */
+       public function getFeedObject( $title, $description, $url ) {
+               global $wgSitename, $wgLanguageCode, $wgFeedClasses;
+
+               if ( !isset( $wgFeedClasses[$this->format] ) ) {
+                       return false;
+               }
+
+               if ( !array_key_exists( $this->format, $wgFeedClasses ) ) {
+                       // falling back to atom
+                       $this->format = 'atom';
+               }
+
+               $feedTitle = "$wgSitename  - {$title} [$wgLanguageCode]";
+               return new $wgFeedClasses[$this->format](
+                       $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;
+               }
+
+               $optionsHash = md5( serialize( $opts->getAllValues() ) ) . $wgRenderHashAppend;
+               $timekey = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash, 'timestamp' );
+               $key = wfMemcKey( $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 $messageMemc
+        *
+        * @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 ) {
+               global $messageMemc;
+               $expire = 3600 * 24; # One day
+               $messageMemc->set( $key, $feed, $expire );
+               $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire );
+       }
+
+       /**
+        * Try to load the feed result from $messageMemc
+        *
+        * @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, $messageMemc;
+
+               $feedLastmod = $messageMemc->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 ); // bug 21916
+                               }
+                               return $messageMemc->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 DatabaseBase resource with recentchanges rows
+        * @param Feed $feed
+        */
+       public static function generateFeed( $rows, &$feed ) {
+               wfProfileIn( __METHOD__ );
+               $items = self::buildItems( $rows );
+               $feed->outHeader();
+               foreach ( $items as $item ) {
+                       $feed->outItem( $item );
+               }
+               $feed->outFooter();
+               wfProfileOut( __METHOD__ );
+       }
+
+       /**
+        * Generate the feed items given a row from the database.
+        * @param object $rows DatabaseBase resource with recentchanges rows
+        */
+       public static function buildItems( $rows ) {
+               wfProfileIn( __METHOD__ );
+               $items = array();
+
+               # Merge adjacent edits by one user
+               $sorted = array();
+               $n = 0;
+               foreach ( $rows as $obj ) {
+                       if ( $n > 0 &&
+                               $obj->rc_type == RC_EDIT &&
+                               $obj->rc_namespace >= 0 &&
+                               $obj->rc_cur_id == $sorted[$n - 1]->rc_cur_id &&
+                               $obj->rc_user_text == $sorted[$n - 1]->rc_user_text ) {
+                               $sorted[$n - 1]->rc_last_oldid = $obj->rc_last_oldid;
+                       } else {
+                               $sorted[$n] = $obj;
+                               $n++;
+                       }
+               }
+
+               foreach ( $sorted as $obj ) {
+                       $title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title );
+                       $talkpage = MWNamespace::canTalk( $obj->rc_namespace )
+                               ? $title->getTalkPage()->getFullURL()
+                               : '';
+
+                       // Skip items with deleted content (avoids partially complete/inconsistent output)
+                       if ( $obj->rc_deleted ) {
+                               continue;
+                       }
+
+                       if ( $obj->rc_this_oldid ) {
+                               $url = $title->getFullURL( array(
+                                       'diff' => $obj->rc_this_oldid,
+                                       'oldid' => $obj->rc_last_oldid,
+                               ) );
+                       } else {
+                               // log entry or something like that.
+                               $url = $title->getFullURL();
+                       }
+
+                       $items[] = new FeedItem(
+                               $title->getPrefixedText(),
+                               FeedUtils::formatDiff( $obj ),
+                               $url,
+                               $obj->rc_timestamp,
+                               ( $obj->rc_deleted & Revision::DELETED_USER )
+                                       ? wfMessage( 'rev-deleted-user' )->escaped() : $obj->rc_user_text,
+                               $talkpage
+                       );
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $items;
+       }
+}
index 36d2731..d2c504a 100644 (file)
@@ -101,7 +101,7 @@ class RedisConnectionPool {
                        $options['connectTimeout'] = 1;
                }
                if ( !isset( $options['readTimeout'] ) ) {
-                       $options['readTimeout'] = 31; // handles up to 30 second blocking commands
+                       $options['readTimeout'] = 1;
                }
                if ( !isset( $options['persistent'] ) ) {
                        $options['persistent'] = false;
@@ -120,7 +120,7 @@ class RedisConnectionPool {
         *                      Optional, default is 1 second.
         *   - readTimeout    : The timeout for operation reads, in seconds.
         *                      Commands like BLPOP can fail if told to wait longer than this.
-        *                      Optional, default is 60 seconds.
+        *                      Optional, default is 1 second.
         *   - persistent     : Set this to true to allow connections to persist across
         *                      multiple web requests. False by default.
         *   - password       : The authentication password, will be sent to Redis in clear text.
@@ -342,6 +342,16 @@ class RedisConnectionPool {
                return true;
        }
 
+       /**
+        * Adjust or reset the connection handle read timeout value
+        *
+        * @param Redis $conn
+        * @param integer $timeout Optional
+        */
+       public function resetTimeout( Redis $conn, $timeout = null ) {
+               $conn->setOption( Redis::OPT_READ_TIMEOUT, $timeout ?: $this->readTimeout );
+       }
+
        /**
         * Make sure connections are closed for sanity
         */
@@ -401,17 +411,34 @@ class RedisConnRef {
        public function __call( $name, $arguments ) {
                $conn = $this->conn; // convenience
 
+               // Work around https://github.com/nicolasff/phpredis/issues/70
+               $lname = strtolower( $name );
+               if ( ( $lname === 'blpop' || $lname == 'brpop' )
+                       && is_array( $arguments[0] ) && isset( $arguments[1] )
+               ) {
+                       $this->pool->resetTimeout( $conn, $arguments[1] + 1 );
+               } elseif ( $lname === 'brpoplpush' && isset( $arguments[2] ) ) {
+                       $this->pool->resetTimeout( $conn, $arguments[2] + 1 );
+               }
+
                $conn->clearLastError();
-               $res = call_user_func_array( array( $conn, $name ), $arguments );
-               if ( preg_match( '/^ERR operation not permitted\b/', $conn->getLastError() ) ) {
-                       $this->pool->reauthenticateConnection( $this->server, $conn );
-                       $conn->clearLastError();
+               try {
                        $res = call_user_func_array( array( $conn, $name ), $arguments );
-                       wfDebugLog( 'redis', "Used automatic re-authentication for method '$name'." );
+                       if ( preg_match( '/^ERR operation not permitted\b/', $conn->getLastError() ) ) {
+                               $this->pool->reauthenticateConnection( $this->server, $conn );
+                               $conn->clearLastError();
+                               $res = call_user_func_array( array( $conn, $name ), $arguments );
+                               wfDebugLog( 'redis', "Used automatic re-authentication for method '$name'." );
+                       }
+               } catch ( RedisException $e ) {
+                       $this->pool->resetTimeout( $conn ); // restore
+                       throw $e;
                }
 
                $this->lastError = $conn->getLastError() ?: $this->lastError;
 
+               $this->pool->resetTimeout( $conn ); // restore
+
                return $res;
        }
 
index 368ca5a..75cd5ee 100644 (file)
@@ -25,4 +25,5 @@
  *
  * @since 1.23
  */
-class ConfigException extends MWException {}
+class ConfigException extends MWException {
+}
index b5b4d13..1343858 100644 (file)
@@ -460,7 +460,7 @@ abstract class ContentHandler {
         * Apply import transformation (per default, returns $blob unchanged).
         * This gives subclasses an opportunity to transform data blobs on import.
         *
-        * @singe 1.24
+        * @since 1.24
         *
         * @param string $blob
         * @param string|null $format
@@ -837,7 +837,7 @@ abstract class ContentHandler {
         * @return mixed String containing deletion reason or empty string, or
         *    boolean false if no revision occurred
         *
-        * @XXX &$hasHistory is extremely ugly, it's here because
+        * @todo &$hasHistory is extremely ugly, it's here because
         * WikiPage::getAutoDeleteReason() and Article::generateReason()
         * have it / want it.
         */
index d0c0bdc..076504e 100644 (file)
@@ -34,9 +34,9 @@ abstract class ContextSource implements IContextSource {
        private $context;
 
        /**
-        * Get the RequestContext object
+        * Get the base IContextSource object
         * @since 1.18
-        * @return RequestContext
+        * @return IContextSource
         */
        public function getContext() {
                if ( $this->context === null ) {
index f550e9e..d78f420 100644 (file)
@@ -126,12 +126,8 @@ class DerivativeContext extends ContextSource {
         * Set the Title object
         *
         * @param Title $t
-        * @throws MWException
         */
-       public function setTitle( $t ) {
-               if ( $t !== null && !$t instanceof Title ) {
-                       throw new MWException( __METHOD__ . " expects an instance of Title" );
-               }
+       public function setTitle( Title $t ) {
                $this->title = $t;
        }
 
index d4bf0b4..2c051ba 100644 (file)
@@ -124,12 +124,8 @@ class RequestContext implements IContextSource {
         * Set the Title object
         *
         * @param Title $t
-        * @throws MWException
         */
-       public function setTitle( $t ) {
-               if ( $t !== null && !$t instanceof Title ) {
-                       throw new MWException( __METHOD__ . " expects an instance of Title" );
-               }
+       public function setTitle( Title $t ) {
                $this->title = $t;
                // Erase the WikiPage so a new one with the new title gets created.
                $this->wikipage = null;
@@ -158,18 +154,14 @@ class RequestContext implements IContextSource {
         * @return bool
         */
        public function canUseWikiPage() {
-               if ( $this->wikipage !== null ) {
-                       # If there's a WikiPage object set, we can for sure get it
+               if ( $this->wikipage ) {
+                       // If there's a WikiPage object set, we can for sure get it
                        return true;
                }
+               // Only pages with legitimate titles can have WikiPages.
+               // That usually means pages in non-virtual namespaces.
                $title = $this->getTitle();
-               if ( $title === null ) {
-                       # No Title, no WikiPage
-                       return false;
-               } else {
-                       # Only namespaces whose pages are stored in the database can have WikiPage
-                       return $title->canExist();
-               }
+               return $title ? $title->canExist() : false;
        }
 
        /**
@@ -265,7 +257,7 @@ class RequestContext implements IContextSource {
                $code = strtolower( $code );
 
                # Validate $code
-               if ( empty( $code ) || !Language::isValidCode( $code ) || ( $code === 'qqq' ) ) {
+               if ( !$code || !Language::isValidCode( $code ) || $code === 'qqq' ) {
                        wfDebug( "Invalid user language code\n" );
                        $code = $wgLanguageCode;
                }
@@ -475,7 +467,8 @@ class RequestContext implements IContextSource {
 
                if ( $params['userId'] ) { // logged-in user
                        $user = User::newFromId( $params['userId'] );
-                       if ( !$user ) {
+                       $user->load();
+                       if ( !$user->getId() ) {
                                throw new MWException( "No user with ID '{$params['userId']}'." );
                        }
                } elseif ( !IP::isValid( $params['ip'] ) ) {
index 699ab71..3207a1b 100644 (file)
@@ -600,7 +600,18 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
         * @return bool
         */
        public function doneWrites() {
-               return $this->mDoneWrites;
+               return (bool)$this->mDoneWrites;
+       }
+
+       /**
+        * Returns the last time the connection may have been used for write queries.
+        * Should return a timestamp if unsure.
+        *
+        * @return int|float UNIX timestamp or false
+        * @since 1.24
+        */
+       public function lastDoneWrites() {
+               return $this->mDoneWrites ?: false;
        }
 
        /**
@@ -1020,10 +1031,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                global $wgUser, $wgDebugDBTransactions;
 
                $this->mLastQuery = $sql;
-               if ( !$this->mDoneWrites && $this->isWriteQuery( $sql ) ) {
+               if ( $this->isWriteQuery( $sql ) ) {
                        # Set a flag indicating that writes have been done
-                       wfDebug( __METHOD__ . ": Writes done: $sql\n" );
-                       $this->mDoneWrites = true;
+                       wfDebug( __METHOD__ . ': Writes done: ' . DatabaseBase::generalizeSQL( $sql ) . "\n" );
+                       $this->mDoneWrites = microtime( true );
                }
 
                # Add a comment for easy SHOW PROCESSLIST interpretation
@@ -1769,9 +1780,10 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                # All newlines, tabs, etc replaced by single space
                $sql = preg_replace( '/\s+/', ' ', $sql );
 
-               # All numbers => N
+               # All numbers => N,
+               # except the ones surrounded by characters, e.g. l10n
                $sql = preg_replace( '/-?\d+(,-?\d+)+/s', 'N,...,N', $sql );
-               $sql = preg_replace( '/-?\d+/s', 'N', $sql );
+               $sql = preg_replace( '/(?<![a-zA-Z])-?\d+(?![a-zA-Z])/s', 'N', $sql );
 
                return $sql;
        }
index 1d05bf6..be01f1a 100644 (file)
@@ -1004,6 +1004,11 @@ class DatabaseMssql extends DatabaseBase {
                        return false;
                }
 
+               if ( $schema === false ) {
+                       global $wgDBmwschema;
+                       $schema = $wgDBmwschema;
+               }
+
                $res = $this->query( "SELECT 1 FROM INFORMATION_SCHEMA.TABLES
                        WHERE TABLE_TYPE = 'BASE TABLE'
                        AND TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table'" );
@@ -1295,9 +1300,6 @@ class DatabaseMssql extends DatabaseBase {
                        : array();
        }
 
-       /**
-        * @void
-        */
        private function populateColumnCaches() {
                $res = $this->select( 'INFORMATION_SCHEMA.COLUMNS', '*',
                        array(
@@ -1344,7 +1346,7 @@ class DatabaseMssql extends DatabaseBase {
                        // 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 );
-                       if ( count( $table ) == 2 ) {
+                       while ( count( $table ) < 3 ) {
                                array_unshift( $table, false );
                        }
                }
index 3d7267a..49dcbc0 100644 (file)
@@ -827,6 +827,8 @@ __INDEXATTR__;
         * In Postgres when using FOR UPDATE, only the main table and tables that are inner joined
         * can be locked. That means tables in an outer join cannot be FOR UPDATE locked. Trying to do
         * so causes a DB error. This wrapper checks which tables can be locked and adjusts it accordingly.
+        *
+        * MySQL uses "ORDER BY NULL" as an optimization hint, but that syntax is illegal in PostgreSQL.
         */
        function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__,
                $options = array(), $join_conds = array()
@@ -842,6 +844,10 @@ __INDEXATTR__;
                                        }
                                }
                        }
+
+                       if ( isset( $options['ORDER BY'] ) && $options['ORDER BY'] == 'NULL' ) {
+                               unset( $options['ORDER BY'] );
+                       }
                }
 
                return parent::selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
index 3e063c6..af687b2 100644 (file)
@@ -342,9 +342,9 @@ class DatabaseSqlite extends DatabaseBase {
         */
        function numFields( $res ) {
                $r = $res instanceof ResultWrapper ? $res->result : $res;
-               if ( is_array($r) && count( $r ) > 0 ){
+               if ( is_array( $r ) && count( $r ) > 0 ) {
                        // The size of the result array is twice the number of fields. (Bug: 65578)
-                       return count( $r[0] ) / 2 ;
+                       return count( $r[0] ) / 2;
                } else {
                        // If the result is empty return 0
                        return 0;
index 6219573..3a4d829 100644 (file)
@@ -71,7 +71,7 @@ class LBFactorySingle extends LBFactory {
        }
 
        /**
-        * @param string|array $callback
+        * @param string|callable $callback
         * @param array $params
         */
        function forEachLB( $callback, $params = array() ) {
index b3f9210..01440f4 100644 (file)
@@ -948,6 +948,14 @@ class LoadBalancer {
                }
        }
 
+       /**
+        * @return bool Whether a master connection is already open
+        * @since 1.24
+        */
+       function hasMasterConnection() {
+               return $this->isOpen( $this->getWriterIndex() );
+       }
+
        /**
         * Determine if there are any pending changes that need to be rolled back
         * or committed.
@@ -1048,8 +1056,22 @@ class LoadBalancer {
                $maxLag = -1;
                $host = '';
                $maxIndex = 0;
-               if ( $this->getServerCount() > 1 ) { // no replication = no lag
+
+               if ( $this->getServerCount() <= 1 ) { // no replication = no lag
+                       return array( $host, $maxLag, $maxIndex );
+               }
+
+               // Try to get the max lag info from the server cache
+               $key = 'loadbalancer:maxlag:cluster:' . $this->mServers[0]['host'];
+               $cache = ObjectCache::newAccelerator( array(), 'hash' );
+               $maxLagInfo = $cache->get( $key ); // (host, lag, index)
+
+               // Fallback to connecting to each slave and getting the lag
+               if ( !$maxLagInfo ) {
                        foreach ( $this->mServers as $i => $conn ) {
+                               if ( $i == $this->getWriterIndex() ) {
+                                       continue; // nothing to check
+                               }
                                $conn = false;
                                if ( $wiki === false ) {
                                        $conn = $this->getAnyOpenConnection( $i );
@@ -1067,9 +1089,11 @@ class LoadBalancer {
                                        $maxIndex = $i;
                                }
                        }
+                       $maxLagInfo = array( $host, $maxLag, $maxIndex );
+                       $cache->set( $key, $maxLagInfo, 5 );
                }
 
-               return array( $host, $maxLag, $maxIndex );
+               return $maxLagInfo;
        }
 
        /**
diff --git a/includes/debug/Debug.php b/includes/debug/Debug.php
deleted file mode 100644 (file)
index 0cea658..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-<?php
-/**
- * Debug toolbar related 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
- */
-
-/**
- * New debugger system that outputs a toolbar on page view.
- *
- * By default, most methods do nothing ( self::$enabled = false ). You have
- * to explicitly call MWDebug::init() to enabled them.
- *
- * @todo Profiler support
- *
- * @since 1.19
- */
-class MWDebug {
-       /**
-        * Log lines
-        *
-        * @var array $log
-        */
-       protected static $log = array();
-
-       /**
-        * Debug messages from wfDebug().
-        *
-        * @var array $debug
-        */
-       protected static $debug = array();
-
-       /**
-        * SQL statements of the databses queries.
-        *
-        * @var array $query
-        */
-       protected static $query = array();
-
-       /**
-        * Is the debugger enabled?
-        *
-        * @var bool $enabled
-        */
-       protected static $enabled = false;
-
-       /**
-        * Array of functions that have already been warned, formatted
-        * function-caller to prevent a buttload of warnings
-        *
-        * @var array $deprecationWarnings
-        */
-       protected static $deprecationWarnings = array();
-
-       /**
-        * Enabled the debugger and load resource module.
-        * This is called by Setup.php when $wgDebugToolbar is true.
-        *
-        * @since 1.19
-        */
-       public static function init() {
-               self::$enabled = true;
-       }
-
-       /**
-        * Add ResourceLoader modules to the OutputPage object if debugging is
-        * enabled.
-        *
-        * @since 1.19
-        * @param OutputPage $out
-        */
-       public static function addModules( OutputPage $out ) {
-               if ( self::$enabled ) {
-                       $out->addModules( 'mediawiki.debug.init' );
-               }
-       }
-
-       /**
-        * Adds a line to the log
-        *
-        * @todo Add support for passing objects
-        *
-        * @since 1.19
-        * @param string $str
-        */
-       public static function log( $str ) {
-               if ( !self::$enabled ) {
-                       return;
-               }
-
-               self::$log[] = array(
-                       'msg' => htmlspecialchars( $str ),
-                       'type' => 'log',
-                       'caller' => wfGetCaller(),
-               );
-       }
-
-       /**
-        * Returns internal log array
-        * @since 1.19
-        * @return array
-        */
-       public static function getLog() {
-               return self::$log;
-       }
-
-       /**
-        * Clears internal log array and deprecation tracking
-        * @since 1.19
-        */
-       public static function clearLog() {
-               self::$log = array();
-               self::$deprecationWarnings = array();
-       }
-
-       /**
-        * Adds a warning entry to the log
-        *
-        * @since 1.19
-        * @param string $msg
-        * @param int $callerOffset
-        * @param int $level A PHP error level. See sendMessage()
-        * @param string $log 'production' will always trigger a php error, 'auto'
-        *    will trigger an error if $wgDevelopmentWarnings is true, and 'debug'
-        *    will only write to the debug log(s).
-        *
-        * @return mixed
-        */
-       public static function warning( $msg, $callerOffset = 1, $level = E_USER_NOTICE, $log = 'auto' ) {
-               global $wgDevelopmentWarnings;
-
-               if ( $log === 'auto' && !$wgDevelopmentWarnings ) {
-                       $log = 'debug';
-               }
-
-               if ( $log === 'debug' ) {
-                       $level = false;
-               }
-
-               $callerDescription = self::getCallerDescription( $callerOffset );
-
-               self::sendMessage( $msg, $callerDescription, 'warning', $level );
-
-               if ( self::$enabled ) {
-                       self::$log[] = array(
-                               'msg' => htmlspecialchars( $msg ),
-                               'type' => 'warn',
-                               'caller' => $callerDescription['func'],
-                       );
-               }
-       }
-
-       /**
-        * Show a warning that $function is deprecated.
-        * This will send it to the following locations:
-        * - Debug toolbar, with one item per function and caller, if $wgDebugToolbar
-        *   is set to true.
-        * - PHP's error log, with level E_USER_DEPRECATED, if $wgDevelopmentWarnings
-        *   is set to true.
-        * - MediaWiki's debug log, if $wgDevelopmentWarnings is set to false.
-        *
-        * @since 1.19
-        * @param string $function Function that is deprecated.
-        * @param string|bool $version Version in which the function was deprecated.
-        * @param string|bool $component Component to which the function belongs.
-        *    If false, it is assumbed the function is in MediaWiki core.
-        * @param int $callerOffset How far up the callstack is the original
-        *    caller. 2 = function that called the function that called
-        *    MWDebug::deprecated() (Added in 1.20).
-        * @return mixed
-        */
-       public static function deprecated( $function, $version = false,
-               $component = false, $callerOffset = 2
-       ) {
-               $callerDescription = self::getCallerDescription( $callerOffset );
-               $callerFunc = $callerDescription['func'];
-
-               $sendToLog = true;
-
-               // Check to see if there already was a warning about this function
-               if ( isset( self::$deprecationWarnings[$function][$callerFunc] ) ) {
-                       return;
-               } elseif ( isset( self::$deprecationWarnings[$function] ) ) {
-                       if ( self::$enabled ) {
-                               $sendToLog = false;
-                       } else {
-                               return;
-                       }
-               }
-
-               self::$deprecationWarnings[$function][$callerFunc] = true;
-
-               if ( $version ) {
-                       global $wgDeprecationReleaseLimit;
-                       if ( $wgDeprecationReleaseLimit && $component === false ) {
-                               # Strip -* off the end of $version so that branches can use the
-                               # format #.##-branchname to avoid issues if the branch is merged into
-                               # a version of MediaWiki later than what it was branched from
-                               $comparableVersion = preg_replace( '/-.*$/', '', $version );
-
-                               # If the comparableVersion is larger than our release limit then
-                               # skip the warning message for the deprecation
-                               if ( version_compare( $wgDeprecationReleaseLimit, $comparableVersion, '<' ) ) {
-                                       $sendToLog = false;
-                               }
-                       }
-
-                       $component = $component === false ? 'MediaWiki' : $component;
-                       $msg = "Use of $function was deprecated in $component $version.";
-               } else {
-                       $msg = "Use of $function is deprecated.";
-               }
-
-               if ( $sendToLog ) {
-                       global $wgDevelopmentWarnings; // we could have a more specific $wgDeprecationWarnings setting.
-                       self::sendMessage(
-                               $msg,
-                               $callerDescription,
-                               'deprecated',
-                               $wgDevelopmentWarnings ? E_USER_DEPRECATED : false
-                       );
-               }
-
-               if ( self::$enabled ) {
-                       $logMsg = htmlspecialchars( $msg ) .
-                               Html::rawElement( 'div', array( 'class' => 'mw-debug-backtrace' ),
-                                       Html::element( 'span', array(), 'Backtrace:' ) . wfBacktrace()
-                               );
-
-                       self::$log[] = array(
-                               'msg' => $logMsg,
-                               'type' => 'deprecated',
-                               'caller' => $callerFunc,
-                       );
-               }
-       }
-
-       /**
-        * Get an array describing the calling function at a specified offset.
-        *
-        * @param int $callerOffset How far up the callstack is the original
-        *    caller. 0 = function that called getCallerDescription()
-        * @return array Array with two keys: 'file' and 'func'
-        */
-       private static function getCallerDescription( $callerOffset ) {
-               $callers = wfDebugBacktrace();
-
-               if ( isset( $callers[$callerOffset] ) ) {
-                       $callerfile = $callers[$callerOffset];
-                       if ( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) {
-                               $file = $callerfile['file'] . ' at line ' . $callerfile['line'];
-                       } else {
-                               $file = '(internal function)';
-                       }
-               } else {
-                       $file = '(unknown location)';
-               }
-
-               if ( isset( $callers[$callerOffset + 1] ) ) {
-                       $callerfunc = $callers[$callerOffset + 1];
-                       $func = '';
-                       if ( isset( $callerfunc['class'] ) ) {
-                               $func .= $callerfunc['class'] . '::';
-                       }
-                       if ( isset( $callerfunc['function'] ) ) {
-                               $func .= $callerfunc['function'];
-                       }
-               } else {
-                       $func = 'unknown';
-               }
-
-               return array( 'file' => $file, 'func' => $func );
-       }
-
-       /**
-        * Send a message to the debug log and optionally also trigger a PHP
-        * error, depending on the $level argument.
-        *
-        * @param string $msg Message to send
-        * @param array $caller Caller description get from getCallerDescription()
-        * @param string $group Log group on which to send the message
-        * @param int|bool $level Error level to use; set to false to not trigger an error
-        */
-       private static function sendMessage( $msg, $caller, $group, $level ) {
-               $msg .= ' [Called from ' . $caller['func'] . ' in ' . $caller['file'] . ']';
-
-               if ( $level !== false ) {
-                       trigger_error( $msg, $level );
-               }
-
-               wfDebugLog( $group, $msg, 'log' );
-       }
-
-       /**
-        * This is a method to pass messages from wfDebug to the pretty debugger.
-        * Do NOT use this method, use MWDebug::log or wfDebug()
-        *
-        * @since 1.19
-        * @param string $str
-        */
-       public static function debugMsg( $str ) {
-               global $wgDebugComments, $wgShowDebug;
-
-               if ( self::$enabled || $wgDebugComments || $wgShowDebug ) {
-                       self::$debug[] = rtrim( UtfNormal::cleanUp( $str ) );
-               }
-       }
-
-       /**
-        * Begins profiling on a database query
-        *
-        * @since 1.19
-        * @param string $sql
-        * @param string $function
-        * @param bool $isMaster
-        * @return int ID number of the query to pass to queryTime or -1 if the
-        *  debugger is disabled
-        */
-       public static function query( $sql, $function, $isMaster ) {
-               if ( !self::$enabled ) {
-                       return -1;
-               }
-
-               self::$query[] = array(
-                       'sql' => $sql,
-                       'function' => $function,
-                       'master' => (bool)$isMaster,
-                       'time' => 0.0,
-                       '_start' => microtime( true ),
-               );
-
-               return count( self::$query ) - 1;
-       }
-
-       /**
-        * Calculates how long a query took.
-        *
-        * @since 1.19
-        * @param int $id
-        */
-       public static function queryTime( $id ) {
-               if ( $id === -1 || !self::$enabled ) {
-                       return;
-               }
-
-               self::$query[$id]['time'] = microtime( true ) - self::$query[$id]['_start'];
-               unset( self::$query[$id]['_start'] );
-       }
-
-       /**
-        * Returns a list of files included, along with their size
-        *
-        * @param IContextSource $context
-        * @return array
-        */
-       protected static function getFilesIncluded( IContextSource $context ) {
-               $files = get_included_files();
-               $fileList = array();
-               foreach ( $files as $file ) {
-                       $size = filesize( $file );
-                       $fileList[] = array(
-                               'name' => $file,
-                               'size' => $context->getLanguage()->formatSize( $size ),
-                       );
-               }
-
-               return $fileList;
-       }
-
-       /**
-        * Returns the HTML to add to the page for the toolbar
-        *
-        * @since 1.19
-        * @param IContextSource $context
-        * @return string
-        */
-       public static function getDebugHTML( IContextSource $context ) {
-               global $wgDebugComments;
-
-               $html = '';
-
-               if ( self::$enabled ) {
-                       MWDebug::log( 'MWDebug output complete' );
-                       $debugInfo = self::getDebugInfo( $context );
-
-                       // Cannot use OutputPage::addJsConfigVars because those are already outputted
-                       // by the time this method is called.
-                       $html = Html::inlineScript(
-                               ResourceLoader::makeLoaderConditionalScript(
-                                       ResourceLoader::makeConfigSetScript( array( 'debugInfo' => $debugInfo ) )
-                               )
-                       );
-               }
-
-               if ( $wgDebugComments ) {
-                       $html .= "<!-- Debug output:\n" .
-                               htmlspecialchars( implode( "\n", self::$debug ) ) .
-                               "\n\n-->";
-               }
-
-               return $html;
-       }
-
-       /**
-        * Generate debug log in HTML for displaying at the bottom of the main
-        * content area.
-        * If $wgShowDebug is false, an empty string is always returned.
-        *
-        * @since 1.20
-        * @return string HTML fragment
-        */
-       public static function getHTMLDebugLog() {
-               global $wgDebugTimestamps, $wgShowDebug;
-
-               if ( !$wgShowDebug ) {
-                       return '';
-               }
-
-               $curIdent = 0;
-               $ret = "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">\n<li>";
-
-               foreach ( self::$debug as $line ) {
-                       $pre = '';
-                       if ( $wgDebugTimestamps ) {
-                               $matches = array();
-                               if ( preg_match( '/^(\d+\.\d+ {1,3}\d+.\dM\s{2})/', $line, $matches ) ) {
-                                       $pre = $matches[1];
-                                       $line = substr( $line, strlen( $pre ) );
-                               }
-                       }
-                       $display = ltrim( $line );
-                       $ident = strlen( $line ) - strlen( $display );
-                       $diff = $ident - $curIdent;
-
-                       $display = $pre . $display;
-                       if ( $display == '' ) {
-                               $display = "\xc2\xa0";
-                       }
-
-                       if ( !$ident
-                               && $diff < 0
-                               && substr( $display, 0, 9 ) != 'Entering '
-                               && substr( $display, 0, 8 ) != 'Exiting '
-                       ) {
-                               $ident = $curIdent;
-                               $diff = 0;
-                               $display = '<span style="background:yellow;">' .
-                                       nl2br( htmlspecialchars( $display ) ) . '</span>';
-                       } else {
-                               $display = nl2br( htmlspecialchars( $display ) );
-                       }
-
-                       if ( $diff < 0 ) {
-                               $ret .= str_repeat( "</li></ul>\n", -$diff ) . "</li><li>\n";
-                       } elseif ( $diff == 0 ) {
-                               $ret .= "</li><li>\n";
-                       } else {
-                               $ret .= str_repeat( "<ul><li>\n", $diff );
-                       }
-                       $ret .= "<code>$display</code>\n";
-
-                       $curIdent = $ident;
-               }
-
-               $ret .= str_repeat( '</li></ul>', $curIdent ) . "</li>\n</ul>\n";
-
-               return $ret;
-       }
-
-       /**
-        * Append the debug info to given ApiResult
-        *
-        * @param IContextSource $context
-        * @param ApiResult $result
-        */
-       public static function appendDebugInfoToApiResult( IContextSource $context, ApiResult $result ) {
-               if ( !self::$enabled ) {
-                       return;
-               }
-
-               // output errors as debug info, when display_errors is on
-               // this is necessary for all non html output of the api, because that clears all errors first
-               $obContents = ob_get_contents();
-               if ( $obContents ) {
-                       $obContentArray = explode( '<br />', $obContents );
-                       foreach ( $obContentArray as $obContent ) {
-                               if ( trim( $obContent ) ) {
-                                       self::debugMsg( Sanitizer::stripAllTags( $obContent ) );
-                               }
-                       }
-               }
-
-               MWDebug::log( 'MWDebug output complete' );
-               $debugInfo = self::getDebugInfo( $context );
-
-               $result->setIndexedTagName( $debugInfo, 'debuginfo' );
-               $result->setIndexedTagName( $debugInfo['log'], 'line' );
-               $result->setIndexedTagName( $debugInfo['debugLog'], 'msg' );
-               $result->setIndexedTagName( $debugInfo['queries'], 'query' );
-               $result->setIndexedTagName( $debugInfo['includes'], 'queries' );
-               $result->setIndexedTagName( $debugInfo['profile'], 'function' );
-               $result->addValue( null, 'debuginfo', $debugInfo );
-       }
-
-       /**
-        * Returns the HTML to add to the page for the toolbar
-        *
-        * @param IContextSource $context
-        * @return array
-        */
-       public static function getDebugInfo( IContextSource $context ) {
-               if ( !self::$enabled ) {
-                       return array();
-               }
-
-               global $wgVersion, $wgRequestTime;
-               $request = $context->getRequest();
-
-               // HHVM's reported memory usage from memory_get_peak_usage()
-               // is not useful when passing false, but we continue passing
-               // false for consistency of historical data in zend.
-               // see: https://github.com/facebook/hhvm/issues/2257#issuecomment-39362246
-               $realMemoryUsage = wfIsHHVM();
-
-               return array(
-                       'mwVersion' => $wgVersion,
-                       'phpVersion' => PHP_VERSION,
-                       'gitRevision' => GitInfo::headSHA1(),
-                       'gitBranch' => GitInfo::currentBranch(),
-                       'gitViewUrl' => GitInfo::headViewUrl(),
-                       'time' => microtime( true ) - $wgRequestTime,
-                       'log' => self::$log,
-                       'debugLog' => self::$debug,
-                       'queries' => self::$query,
-                       'request' => array(
-                               'method' => $request->getMethod(),
-                               'url' => $request->getRequestURL(),
-                               'headers' => $request->getAllHeaders(),
-                               'params' => $request->getValues(),
-                       ),
-                       'memory' => $context->getLanguage()->formatSize( memory_get_usage( $realMemoryUsage ) ),
-                       'memoryPeak' => $context->getLanguage()->formatSize( memory_get_peak_usage( $realMemoryUsage ) ),
-                       'includes' => self::getFilesIncluded( $context ),
-                       'profile' => Profiler::instance()->getRawData(),
-               );
-       }
-}
diff --git a/includes/debug/MWDebug.php b/includes/debug/MWDebug.php
new file mode 100644 (file)
index 0000000..0cea658
--- /dev/null
@@ -0,0 +1,562 @@
+<?php
+/**
+ * Debug toolbar related 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
+ */
+
+/**
+ * New debugger system that outputs a toolbar on page view.
+ *
+ * By default, most methods do nothing ( self::$enabled = false ). You have
+ * to explicitly call MWDebug::init() to enabled them.
+ *
+ * @todo Profiler support
+ *
+ * @since 1.19
+ */
+class MWDebug {
+       /**
+        * Log lines
+        *
+        * @var array $log
+        */
+       protected static $log = array();
+
+       /**
+        * Debug messages from wfDebug().
+        *
+        * @var array $debug
+        */
+       protected static $debug = array();
+
+       /**
+        * SQL statements of the databses queries.
+        *
+        * @var array $query
+        */
+       protected static $query = array();
+
+       /**
+        * Is the debugger enabled?
+        *
+        * @var bool $enabled
+        */
+       protected static $enabled = false;
+
+       /**
+        * Array of functions that have already been warned, formatted
+        * function-caller to prevent a buttload of warnings
+        *
+        * @var array $deprecationWarnings
+        */
+       protected static $deprecationWarnings = array();
+
+       /**
+        * Enabled the debugger and load resource module.
+        * This is called by Setup.php when $wgDebugToolbar is true.
+        *
+        * @since 1.19
+        */
+       public static function init() {
+               self::$enabled = true;
+       }
+
+       /**
+        * Add ResourceLoader modules to the OutputPage object if debugging is
+        * enabled.
+        *
+        * @since 1.19
+        * @param OutputPage $out
+        */
+       public static function addModules( OutputPage $out ) {
+               if ( self::$enabled ) {
+                       $out->addModules( 'mediawiki.debug.init' );
+               }
+       }
+
+       /**
+        * Adds a line to the log
+        *
+        * @todo Add support for passing objects
+        *
+        * @since 1.19
+        * @param string $str
+        */
+       public static function log( $str ) {
+               if ( !self::$enabled ) {
+                       return;
+               }
+
+               self::$log[] = array(
+                       'msg' => htmlspecialchars( $str ),
+                       'type' => 'log',
+                       'caller' => wfGetCaller(),
+               );
+       }
+
+       /**
+        * Returns internal log array
+        * @since 1.19
+        * @return array
+        */
+       public static function getLog() {
+               return self::$log;
+       }
+
+       /**
+        * Clears internal log array and deprecation tracking
+        * @since 1.19
+        */
+       public static function clearLog() {
+               self::$log = array();
+               self::$deprecationWarnings = array();
+       }
+
+       /**
+        * Adds a warning entry to the log
+        *
+        * @since 1.19
+        * @param string $msg
+        * @param int $callerOffset
+        * @param int $level A PHP error level. See sendMessage()
+        * @param string $log 'production' will always trigger a php error, 'auto'
+        *    will trigger an error if $wgDevelopmentWarnings is true, and 'debug'
+        *    will only write to the debug log(s).
+        *
+        * @return mixed
+        */
+       public static function warning( $msg, $callerOffset = 1, $level = E_USER_NOTICE, $log = 'auto' ) {
+               global $wgDevelopmentWarnings;
+
+               if ( $log === 'auto' && !$wgDevelopmentWarnings ) {
+                       $log = 'debug';
+               }
+
+               if ( $log === 'debug' ) {
+                       $level = false;
+               }
+
+               $callerDescription = self::getCallerDescription( $callerOffset );
+
+               self::sendMessage( $msg, $callerDescription, 'warning', $level );
+
+               if ( self::$enabled ) {
+                       self::$log[] = array(
+                               'msg' => htmlspecialchars( $msg ),
+                               'type' => 'warn',
+                               'caller' => $callerDescription['func'],
+                       );
+               }
+       }
+
+       /**
+        * Show a warning that $function is deprecated.
+        * This will send it to the following locations:
+        * - Debug toolbar, with one item per function and caller, if $wgDebugToolbar
+        *   is set to true.
+        * - PHP's error log, with level E_USER_DEPRECATED, if $wgDevelopmentWarnings
+        *   is set to true.
+        * - MediaWiki's debug log, if $wgDevelopmentWarnings is set to false.
+        *
+        * @since 1.19
+        * @param string $function Function that is deprecated.
+        * @param string|bool $version Version in which the function was deprecated.
+        * @param string|bool $component Component to which the function belongs.
+        *    If false, it is assumbed the function is in MediaWiki core.
+        * @param int $callerOffset How far up the callstack is the original
+        *    caller. 2 = function that called the function that called
+        *    MWDebug::deprecated() (Added in 1.20).
+        * @return mixed
+        */
+       public static function deprecated( $function, $version = false,
+               $component = false, $callerOffset = 2
+       ) {
+               $callerDescription = self::getCallerDescription( $callerOffset );
+               $callerFunc = $callerDescription['func'];
+
+               $sendToLog = true;
+
+               // Check to see if there already was a warning about this function
+               if ( isset( self::$deprecationWarnings[$function][$callerFunc] ) ) {
+                       return;
+               } elseif ( isset( self::$deprecationWarnings[$function] ) ) {
+                       if ( self::$enabled ) {
+                               $sendToLog = false;
+                       } else {
+                               return;
+                       }
+               }
+
+               self::$deprecationWarnings[$function][$callerFunc] = true;
+
+               if ( $version ) {
+                       global $wgDeprecationReleaseLimit;
+                       if ( $wgDeprecationReleaseLimit && $component === false ) {
+                               # Strip -* off the end of $version so that branches can use the
+                               # format #.##-branchname to avoid issues if the branch is merged into
+                               # a version of MediaWiki later than what it was branched from
+                               $comparableVersion = preg_replace( '/-.*$/', '', $version );
+
+                               # If the comparableVersion is larger than our release limit then
+                               # skip the warning message for the deprecation
+                               if ( version_compare( $wgDeprecationReleaseLimit, $comparableVersion, '<' ) ) {
+                                       $sendToLog = false;
+                               }
+                       }
+
+                       $component = $component === false ? 'MediaWiki' : $component;
+                       $msg = "Use of $function was deprecated in $component $version.";
+               } else {
+                       $msg = "Use of $function is deprecated.";
+               }
+
+               if ( $sendToLog ) {
+                       global $wgDevelopmentWarnings; // we could have a more specific $wgDeprecationWarnings setting.
+                       self::sendMessage(
+                               $msg,
+                               $callerDescription,
+                               'deprecated',
+                               $wgDevelopmentWarnings ? E_USER_DEPRECATED : false
+                       );
+               }
+
+               if ( self::$enabled ) {
+                       $logMsg = htmlspecialchars( $msg ) .
+                               Html::rawElement( 'div', array( 'class' => 'mw-debug-backtrace' ),
+                                       Html::element( 'span', array(), 'Backtrace:' ) . wfBacktrace()
+                               );
+
+                       self::$log[] = array(
+                               'msg' => $logMsg,
+                               'type' => 'deprecated',
+                               'caller' => $callerFunc,
+                       );
+               }
+       }
+
+       /**
+        * Get an array describing the calling function at a specified offset.
+        *
+        * @param int $callerOffset How far up the callstack is the original
+        *    caller. 0 = function that called getCallerDescription()
+        * @return array Array with two keys: 'file' and 'func'
+        */
+       private static function getCallerDescription( $callerOffset ) {
+               $callers = wfDebugBacktrace();
+
+               if ( isset( $callers[$callerOffset] ) ) {
+                       $callerfile = $callers[$callerOffset];
+                       if ( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) {
+                               $file = $callerfile['file'] . ' at line ' . $callerfile['line'];
+                       } else {
+                               $file = '(internal function)';
+                       }
+               } else {
+                       $file = '(unknown location)';
+               }
+
+               if ( isset( $callers[$callerOffset + 1] ) ) {
+                       $callerfunc = $callers[$callerOffset + 1];
+                       $func = '';
+                       if ( isset( $callerfunc['class'] ) ) {
+                               $func .= $callerfunc['class'] . '::';
+                       }
+                       if ( isset( $callerfunc['function'] ) ) {
+                               $func .= $callerfunc['function'];
+                       }
+               } else {
+                       $func = 'unknown';
+               }
+
+               return array( 'file' => $file, 'func' => $func );
+       }
+
+       /**
+        * Send a message to the debug log and optionally also trigger a PHP
+        * error, depending on the $level argument.
+        *
+        * @param string $msg Message to send
+        * @param array $caller Caller description get from getCallerDescription()
+        * @param string $group Log group on which to send the message
+        * @param int|bool $level Error level to use; set to false to not trigger an error
+        */
+       private static function sendMessage( $msg, $caller, $group, $level ) {
+               $msg .= ' [Called from ' . $caller['func'] . ' in ' . $caller['file'] . ']';
+
+               if ( $level !== false ) {
+                       trigger_error( $msg, $level );
+               }
+
+               wfDebugLog( $group, $msg, 'log' );
+       }
+
+       /**
+        * This is a method to pass messages from wfDebug to the pretty debugger.
+        * Do NOT use this method, use MWDebug::log or wfDebug()
+        *
+        * @since 1.19
+        * @param string $str
+        */
+       public static function debugMsg( $str ) {
+               global $wgDebugComments, $wgShowDebug;
+
+               if ( self::$enabled || $wgDebugComments || $wgShowDebug ) {
+                       self::$debug[] = rtrim( UtfNormal::cleanUp( $str ) );
+               }
+       }
+
+       /**
+        * Begins profiling on a database query
+        *
+        * @since 1.19
+        * @param string $sql
+        * @param string $function
+        * @param bool $isMaster
+        * @return int ID number of the query to pass to queryTime or -1 if the
+        *  debugger is disabled
+        */
+       public static function query( $sql, $function, $isMaster ) {
+               if ( !self::$enabled ) {
+                       return -1;
+               }
+
+               self::$query[] = array(
+                       'sql' => $sql,
+                       'function' => $function,
+                       'master' => (bool)$isMaster,
+                       'time' => 0.0,
+                       '_start' => microtime( true ),
+               );
+
+               return count( self::$query ) - 1;
+       }
+
+       /**
+        * Calculates how long a query took.
+        *
+        * @since 1.19
+        * @param int $id
+        */
+       public static function queryTime( $id ) {
+               if ( $id === -1 || !self::$enabled ) {
+                       return;
+               }
+
+               self::$query[$id]['time'] = microtime( true ) - self::$query[$id]['_start'];
+               unset( self::$query[$id]['_start'] );
+       }
+
+       /**
+        * Returns a list of files included, along with their size
+        *
+        * @param IContextSource $context
+        * @return array
+        */
+       protected static function getFilesIncluded( IContextSource $context ) {
+               $files = get_included_files();
+               $fileList = array();
+               foreach ( $files as $file ) {
+                       $size = filesize( $file );
+                       $fileList[] = array(
+                               'name' => $file,
+                               'size' => $context->getLanguage()->formatSize( $size ),
+                       );
+               }
+
+               return $fileList;
+       }
+
+       /**
+        * Returns the HTML to add to the page for the toolbar
+        *
+        * @since 1.19
+        * @param IContextSource $context
+        * @return string
+        */
+       public static function getDebugHTML( IContextSource $context ) {
+               global $wgDebugComments;
+
+               $html = '';
+
+               if ( self::$enabled ) {
+                       MWDebug::log( 'MWDebug output complete' );
+                       $debugInfo = self::getDebugInfo( $context );
+
+                       // Cannot use OutputPage::addJsConfigVars because those are already outputted
+                       // by the time this method is called.
+                       $html = Html::inlineScript(
+                               ResourceLoader::makeLoaderConditionalScript(
+                                       ResourceLoader::makeConfigSetScript( array( 'debugInfo' => $debugInfo ) )
+                               )
+                       );
+               }
+
+               if ( $wgDebugComments ) {
+                       $html .= "<!-- Debug output:\n" .
+                               htmlspecialchars( implode( "\n", self::$debug ) ) .
+                               "\n\n-->";
+               }
+
+               return $html;
+       }
+
+       /**
+        * Generate debug log in HTML for displaying at the bottom of the main
+        * content area.
+        * If $wgShowDebug is false, an empty string is always returned.
+        *
+        * @since 1.20
+        * @return string HTML fragment
+        */
+       public static function getHTMLDebugLog() {
+               global $wgDebugTimestamps, $wgShowDebug;
+
+               if ( !$wgShowDebug ) {
+                       return '';
+               }
+
+               $curIdent = 0;
+               $ret = "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">\n<li>";
+
+               foreach ( self::$debug as $line ) {
+                       $pre = '';
+                       if ( $wgDebugTimestamps ) {
+                               $matches = array();
+                               if ( preg_match( '/^(\d+\.\d+ {1,3}\d+.\dM\s{2})/', $line, $matches ) ) {
+                                       $pre = $matches[1];
+                                       $line = substr( $line, strlen( $pre ) );
+                               }
+                       }
+                       $display = ltrim( $line );
+                       $ident = strlen( $line ) - strlen( $display );
+                       $diff = $ident - $curIdent;
+
+                       $display = $pre . $display;
+                       if ( $display == '' ) {
+                               $display = "\xc2\xa0";
+                       }
+
+                       if ( !$ident
+                               && $diff < 0
+                               && substr( $display, 0, 9 ) != 'Entering '
+                               && substr( $display, 0, 8 ) != 'Exiting '
+                       ) {
+                               $ident = $curIdent;
+                               $diff = 0;
+                               $display = '<span style="background:yellow;">' .
+                                       nl2br( htmlspecialchars( $display ) ) . '</span>';
+                       } else {
+                               $display = nl2br( htmlspecialchars( $display ) );
+                       }
+
+                       if ( $diff < 0 ) {
+                               $ret .= str_repeat( "</li></ul>\n", -$diff ) . "</li><li>\n";
+                       } elseif ( $diff == 0 ) {
+                               $ret .= "</li><li>\n";
+                       } else {
+                               $ret .= str_repeat( "<ul><li>\n", $diff );
+                       }
+                       $ret .= "<code>$display</code>\n";
+
+                       $curIdent = $ident;
+               }
+
+               $ret .= str_repeat( '</li></ul>', $curIdent ) . "</li>\n</ul>\n";
+
+               return $ret;
+       }
+
+       /**
+        * Append the debug info to given ApiResult
+        *
+        * @param IContextSource $context
+        * @param ApiResult $result
+        */
+       public static function appendDebugInfoToApiResult( IContextSource $context, ApiResult $result ) {
+               if ( !self::$enabled ) {
+                       return;
+               }
+
+               // output errors as debug info, when display_errors is on
+               // this is necessary for all non html output of the api, because that clears all errors first
+               $obContents = ob_get_contents();
+               if ( $obContents ) {
+                       $obContentArray = explode( '<br />', $obContents );
+                       foreach ( $obContentArray as $obContent ) {
+                               if ( trim( $obContent ) ) {
+                                       self::debugMsg( Sanitizer::stripAllTags( $obContent ) );
+                               }
+                       }
+               }
+
+               MWDebug::log( 'MWDebug output complete' );
+               $debugInfo = self::getDebugInfo( $context );
+
+               $result->setIndexedTagName( $debugInfo, 'debuginfo' );
+               $result->setIndexedTagName( $debugInfo['log'], 'line' );
+               $result->setIndexedTagName( $debugInfo['debugLog'], 'msg' );
+               $result->setIndexedTagName( $debugInfo['queries'], 'query' );
+               $result->setIndexedTagName( $debugInfo['includes'], 'queries' );
+               $result->setIndexedTagName( $debugInfo['profile'], 'function' );
+               $result->addValue( null, 'debuginfo', $debugInfo );
+       }
+
+       /**
+        * Returns the HTML to add to the page for the toolbar
+        *
+        * @param IContextSource $context
+        * @return array
+        */
+       public static function getDebugInfo( IContextSource $context ) {
+               if ( !self::$enabled ) {
+                       return array();
+               }
+
+               global $wgVersion, $wgRequestTime;
+               $request = $context->getRequest();
+
+               // HHVM's reported memory usage from memory_get_peak_usage()
+               // is not useful when passing false, but we continue passing
+               // false for consistency of historical data in zend.
+               // see: https://github.com/facebook/hhvm/issues/2257#issuecomment-39362246
+               $realMemoryUsage = wfIsHHVM();
+
+               return array(
+                       'mwVersion' => $wgVersion,
+                       'phpVersion' => PHP_VERSION,
+                       'gitRevision' => GitInfo::headSHA1(),
+                       'gitBranch' => GitInfo::currentBranch(),
+                       'gitViewUrl' => GitInfo::headViewUrl(),
+                       'time' => microtime( true ) - $wgRequestTime,
+                       'log' => self::$log,
+                       'debugLog' => self::$debug,
+                       'queries' => self::$query,
+                       'request' => array(
+                               'method' => $request->getMethod(),
+                               'url' => $request->getRequestURL(),
+                               'headers' => $request->getAllHeaders(),
+                               'params' => $request->getValues(),
+                       ),
+                       'memory' => $context->getLanguage()->formatSize( memory_get_usage( $realMemoryUsage ) ),
+                       'memoryPeak' => $context->getLanguage()->formatSize( memory_get_peak_usage( $realMemoryUsage ) ),
+                       'includes' => self::getFilesIncluded( $context ),
+                       'profile' => Profiler::instance()->getRawData(),
+               );
+       }
+}
index 0789b21..2c984f7 100644 (file)
@@ -358,6 +358,7 @@ class LinksUpdate extends SqlDataUpdate {
                        foreach ( $diffs as $dbk => $id ) {
                                $arr[] = array(
                                        'pl_from' => $this->mId,
+                                       'pl_from_namespace' => $this->mTitle->getNamespace(),
                                        'pl_namespace' => $ns,
                                        'pl_title' => $dbk
                                );
@@ -379,6 +380,7 @@ class LinksUpdate extends SqlDataUpdate {
                        foreach ( $diffs as $dbk => $id ) {
                                $arr[] = array(
                                        'tl_from' => $this->mId,
+                                       'tl_from_namespace' => $this->mTitle->getNamespace(),
                                        'tl_namespace' => $ns,
                                        'tl_title' => $dbk
                                );
@@ -400,6 +402,7 @@ class LinksUpdate extends SqlDataUpdate {
                foreach ( $diffs as $iname => $dummy ) {
                        $arr[] = array(
                                'il_from' => $this->mId,
+                               'il_from_namespace' => $this->mTitle->getNamespace(),
                                'il_to' => $iname
                        );
                }
index ddd2e09..901ef9f 100644 (file)
@@ -49,23 +49,32 @@ class ViewCountUpdate implements DeferrableUpdate {
                $dbw = wfGetDB( DB_MASTER );
 
                if ( $wgHitcounterUpdateFreq <= 1 || $dbw->getType() == 'sqlite' ) {
-                       $dbw->update(
-                               'page', array( 'page_counter = page_counter + 1' ),
-                               array( 'page_id' => $this->id ),
-                               __METHOD__
-                       );
-
+                       $id = $this->id;
+                       $method = __METHOD__;
+                       $dbw->onTransactionIdle( function() use ( $dbw, $id, $method ) {
+                               try {
+                                       $dbw->update( 'page',
+                                               array( 'page_counter = page_counter + 1' ),
+                                               array( 'page_id' => $id ),
+                                               $method
+                                       );
+                               } catch ( DBError $e ) {
+                                       MWExceptionHandler::logException( $e );
+                               }
+                       } );
                        return;
                }
 
                # Not important enough to warrant an error page in case of failure
                try {
+                       // Since `hitcounter` is non-transactional, the contention is minimal
                        $dbw->insert( 'hitcounter', array( 'hc_id' => $this->id ), __METHOD__ );
                        $checkfreq = intval( $wgHitcounterUpdateFreq / 25 + 1 );
                        if ( rand() % $checkfreq == 0 && $dbw->lastErrno() == 0 ) {
                                $this->collect();
                        }
                } catch ( DBError $e ) {
+                       MWExceptionHandler::logException( $e );
                }
        }
 
@@ -75,7 +84,6 @@ class ViewCountUpdate implements DeferrableUpdate {
                $dbw = wfGetDB( DB_MASTER );
 
                $rown = $dbw->selectField( 'hitcounter', 'COUNT(*)', array(), __METHOD__ );
-
                if ( $rown < $wgHitcounterUpdateFreq ) {
                        return;
                }
@@ -83,14 +91,13 @@ class ViewCountUpdate implements DeferrableUpdate {
                wfProfileIn( __METHOD__ . '-collect' );
                $old_user_abort = ignore_user_abort( true );
 
-               $dbw->lockTables( array(), array( 'hitcounter' ), __METHOD__, false );
-
                $dbType = $dbw->getType();
                $tabletype = $dbType == 'mysql' ? "ENGINE=HEAP " : '';
                $hitcounterTable = $dbw->tableName( 'hitcounter' );
                $acchitsTable = $dbw->tableName( 'acchits' );
                $pageTable = $dbw->tableName( 'page' );
 
+               $dbw->lockTables( array(), array( 'hitcounter' ), __METHOD__, false );
                $dbw->query( "CREATE TEMPORARY TABLE $acchitsTable $tabletype AS " .
                        "SELECT hc_id,COUNT(*) AS hc_n FROM $hitcounterTable " .
                        'GROUP BY hc_id', __METHOD__ );
index 3aad389..61eb760 100644 (file)
@@ -972,7 +972,7 @@ class DifferenceEngine extends ContextSource {
                }
 
                // Sanity: don't show the notice if too many rows must be scanned
-               // @TODO: show some special message for that case
+               // @todo show some special message for that case
                $nEdits = $this->mNewPage->countRevisionsBetween( $oldRev, $newRev, 1000 );
                if ( $nEdits > 0 && $nEdits <= 1000 ) {
                        $limit = 100; // use diff-multi-manyusers if too many users
index 3f81a94..2b0c3c2 100644 (file)
@@ -213,7 +213,7 @@ class FSFileBackend extends FileBackendStore {
                                wfEscapeShellArg( $this->cleanPathSlashes( $tempFile->getPath() ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
-                       $handler = function( $errors, Status $status, array $params, $cmd ) {
+                       $handler = function ( $errors, Status $status, array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-create', $params['dst'] );
                                        trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
@@ -252,7 +252,7 @@ class FSFileBackend extends FileBackendStore {
                                wfEscapeShellArg( $this->cleanPathSlashes( $params['src'] ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
-                       $handler = function( $errors, Status $status, array $params, $cmd ) {
+                       $handler = function ( $errors, Status $status, array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-store', $params['src'], $params['dst'] );
                                        trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
@@ -310,7 +310,7 @@ class FSFileBackend extends FileBackendStore {
                                wfEscapeShellArg( $this->cleanPathSlashes( $source ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
-                       $handler = function( $errors, Status $status, array $params, $cmd ) {
+                       $handler = function ( $errors, Status $status, array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-copy', $params['src'], $params['dst'] );
                                        trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
@@ -370,7 +370,7 @@ class FSFileBackend extends FileBackendStore {
                                wfEscapeShellArg( $this->cleanPathSlashes( $source ) ),
                                wfEscapeShellArg( $this->cleanPathSlashes( $dest ) )
                        ) );
-                       $handler = function( $errors, Status $status, array $params, $cmd ) {
+                       $handler = function ( $errors, Status $status, array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-move', $params['src'], $params['dst'] );
                                        trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
@@ -415,7 +415,7 @@ class FSFileBackend extends FileBackendStore {
                                wfIsWindows() ? 'DEL' : 'unlink',
                                wfEscapeShellArg( $this->cleanPathSlashes( $source ) )
                        ) );
-                       $handler = function( $errors, Status $status, array $params, $cmd ) {
+                       $handler = function ( $errors, Status $status, array $params, $cmd ) {
                                if ( $errors !== '' && !( wfIsWindows() && $errors[0] === " " ) ) {
                                        $status->fatal( 'backend-fail-delete', $params['src'] );
                                        trigger_error( "$cmd\n$errors", E_USER_WARNING ); // command output
@@ -792,7 +792,7 @@ class FSFileOpHandle extends FileBackendStoreOpHandle {
        /**
         * @param FSFileBackend $backend
         * @param array $params
-        * @param callback $call
+        * @param callable $call
         * @param string $cmd
         * @param int|null $chmodPath
         */
index ee9a49d..631d949 100644 (file)
@@ -69,7 +69,7 @@ abstract class FileBackendStore extends FileBackend {
                $this->mimeCallback = isset( $config['mimeCallback'] )
                        ? $config['mimeCallback']
                        : function ( $storagePath, $content, $fsPath ) {
-                               // @TODO: handle the case of extension-less files using the contents
+                               // @todo handle the case of extension-less files using the contents
                                return StreamFile::contentTypeFromPath( $storagePath ) ?: 'unknown/unknown';
                        };
                $this->memCache = new EmptyBagOStuff(); // disabled by default
@@ -1696,7 +1696,7 @@ abstract class FileBackendStore extends FileBackend {
                if ( !$this->memCache->add( $key, $val, $ttl ) && !empty( $val['latest'] ) ) {
                        $this->memCache->merge(
                                $key,
-                               function( BagOStuff $cache, $key, $cValue ) use ( $val ) {
+                               function ( BagOStuff $cache, $key, $cValue ) use ( $val ) {
                                        return ( is_array( $cValue ) && empty( $cValue['latest'] ) )
                                                ? $val // update the stat cache with the lastest info
                                                : false; // do nothing (cache is salted or some error happened)
index b58e901..450ccc8 100644 (file)
@@ -108,7 +108,7 @@ abstract class DBLockManager extends QuorumLockManager {
                $this->session = wfRandomString( 31 );
        }
 
-       // @TODO: change this code to work in one batch
+       // @todo change this code to work in one batch
        protected function getLocksOnServer( $lockSrv, array $pathsByType ) {
                $status = Status::newGood();
                foreach ( $pathsByType as $type => $paths ) {
index 4c250ba..8598005 100644 (file)
@@ -1583,7 +1583,7 @@ class FileRepo {
         * This only acts on the current version of files, not any old versions.
         * May use either the database or the filesystem.
         *
-        * @param array|string $callback
+        * @param callable $callback
         * @return void
         */
        public function enumFiles( $callback ) {
@@ -1594,7 +1594,7 @@ class FileRepo {
         * Call a callback function for every public file in the repository.
         * May use either the database or the filesystem.
         *
-        * @param array|string $callback
+        * @param callable $callback
         * @return void
         */
        protected function enumFilesInStorage( $callback ) {
index 7f25a00..6924f0a 100644 (file)
@@ -575,7 +575,7 @@ class ForeignAPIRepo extends FileRepo {
        }
 
        /**
-        * @param array|string $callback
+        * @param callable $callback
         * @throws MWException
         */
        function enumFiles( $callback ) {
index 103e78e..65637df 100644 (file)
@@ -367,6 +367,9 @@ class RepoGroup {
         * @return bool
         */
        function forEachForeignRepo( $callback, $params = array() ) {
+               if ( !$this->reposInitialised ) {
+                       $this->initialiseRepos();
+               }
                foreach ( $this->foreignRepos as $repo ) {
                        $args = array_merge( array( $repo ), $params );
                        if ( call_user_func_array( $callback, $args ) ) {
@@ -382,6 +385,9 @@ class RepoGroup {
         * @return bool
         */
        function hasForeignRepos() {
+               if ( !$this->reposInitialised ) {
+                       $this->initialiseRepos();
+               }
                return (bool)$this->foreignRepos;
        }
 
index 1103e38..e970e38 100644 (file)
@@ -149,6 +149,9 @@ abstract class File {
        /** @var string Required Repository class type */
        protected $repoClass = 'FileRepo';
 
+       /** @var array Cache of tmp filepaths pointing to generated bucket thumbnails, keyed by width */
+       protected $tmpBucketedThumbCache = array();
+
        /**
         * Call this constructor from child classes.
         *
@@ -456,6 +459,50 @@ abstract class File {
                return false;
        }
 
+       /**
+        * Return the smallest bucket from $wgThumbnailBuckets which is at least
+        * $wgThumbnailMinimumBucketDistance larger than $desiredWidth. The returned bucket, if any,
+        * will always be bigger than $desiredWidth.
+        *
+        * @param int $desiredWidth
+        * @param int $page
+        * @return bool|int
+        */
+       public function getThumbnailBucket( $desiredWidth, $page = 1 ) {
+               global $wgThumbnailBuckets, $wgThumbnailMinimumBucketDistance;
+
+               $imageWidth = $this->getWidth( $page );
+
+               if ( $imageWidth === false ) {
+                       return false;
+               }
+
+               if ( $desiredWidth > $imageWidth ) {
+                       return false;
+               }
+
+               if ( !$wgThumbnailBuckets ) {
+                       return false;
+               }
+
+               $sortedBuckets = $wgThumbnailBuckets;
+
+               sort( $sortedBuckets );
+
+               foreach ( $sortedBuckets as $bucket ) {
+                       if ( $bucket > $imageWidth ) {
+                               return false;
+                       }
+
+                       if ( $bucket - $wgThumbnailMinimumBucketDistance > $desiredWidth ) {
+                               return $bucket;
+                       }
+               }
+
+               // Image is bigger than any available bucket
+               return false;
+       }
+
        /**
         * Returns ID or name of user who uploaded the file
         * STUB
@@ -877,9 +924,9 @@ abstract class File {
                        return null;
                }
                $extension = $this->getExtension();
-               list( $thumbExt, ) = $this->handler->getThumbType(
+               list( $thumbExt, ) = $this->getHandler()->getThumbType(
                        $extension, $this->getMimeType(), $params );
-               $thumbName = $this->handler->makeParamString( $params ) . '-' . $name;
+               $thumbName = $this->getHandler()->makeParamString( $params ) . '-' . $name;
                if ( $thumbExt != $extension ) {
                        $thumbName .= ".$thumbExt";
                }
@@ -947,7 +994,7 @@ abstract class File {
         * @return MediaTransformOutput|bool False on failure
         */
        function transform( $params, $flags = 0 ) {
-               global $wgUseSquid, $wgIgnoreImageErrors, $wgThumbnailEpoch;
+               global $wgThumbnailEpoch;
 
                wfProfileIn( __METHOD__ );
                do {
@@ -1004,64 +1051,221 @@ abstract class File {
                                } elseif ( $flags & self::RENDER_FORCE ) {
                                        wfDebug( __METHOD__ . " forcing rendering per flag File::RENDER_FORCE\n" );
                                }
-                       }
 
-                       // If the backend is ready-only, don't keep generating thumbnails
-                       // only to return transformation errors, just return the error now.
-                       if ( $this->repo->getReadOnlyReason() !== false ) {
-                               $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags );
-                               break;
+                               // If the backend is ready-only, don't keep generating thumbnails
+                               // only to return transformation errors, just return the error now.
+                               if ( $this->repo->getReadOnlyReason() !== false ) {
+                                       $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags );
+                                       break;
+                               }
                        }
 
-                       // Create a temp FS file with the same extension and the thumbnail
-                       $thumbExt = FileBackend::extensionFromPath( $thumbPath );
-                       $tmpFile = TempFSFile::factory( 'transform_', $thumbExt );
+                       $tmpFile = $this->makeTransformTmpFile( $thumbPath );
+
                        if ( !$tmpFile ) {
                                $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags );
-                               break;
+                       } else {
+                               $thumb = $this->generateAndSaveThumb( $tmpFile, $params, $flags );
                        }
-                       $tmpThumbPath = $tmpFile->getPath(); // path of 0-byte temp file
-
-                       // Actually render the thumbnail...
-                       wfProfileIn( __METHOD__ . '-doTransform' );
-                       $thumb = $handler->doTransform( $this, $tmpThumbPath, $thumbUrl, $params );
-                       wfProfileOut( __METHOD__ . '-doTransform' );
-                       $tmpFile->bind( $thumb ); // keep alive with $thumb
-
-                       if ( !$thumb ) { // bad params?
-                               $thumb = false;
-                       } elseif ( $thumb->isError() ) { // transform error
-                               $this->lastError = $thumb->toText();
-                               // Ignore errors if requested
-                               if ( $wgIgnoreImageErrors && !( $flags & self::RENDER_NOW ) ) {
-                                       $thumb = $handler->getTransform( $this, $tmpThumbPath, $thumbUrl, $params );
-                               }
-                       } elseif ( $this->repo && $thumb->hasFile() && !$thumb->fileIsSource() ) {
-                               // Copy the thumbnail from the file system into storage...
-                               $disposition = $this->getThumbDisposition( $thumbName );
-                               $status = $this->repo->quickImport( $tmpThumbPath, $thumbPath, $disposition );
-                               if ( $status->isOK() ) {
-                                       $thumb->setStoragePath( $thumbPath );
-                               } else {
-                                       $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags );
+               } while ( false );
+
+               wfProfileOut( __METHOD__ );
+
+               return is_object( $thumb ) ? $thumb : false;
+       }
+
+       /**
+        * Generates a thumbnail according to the given parameters and saves it to storage
+        * @param TempFSFile $tmpFile Temporary file where the rendered thumbnail will be saved
+        * @param array $transformParams
+        * @param int $flags
+        * @return bool|MediaTransformOutput
+        */
+       public function generateAndSaveThumb( $tmpFile, $transformParams, $flags ) {
+               global $wgUseSquid, $wgIgnoreImageErrors;
+
+               $handler = $this->getHandler();
+
+               $normalisedParams = $transformParams;
+               $handler->normaliseParams( $this, $normalisedParams );
+
+               $thumbName = $this->thumbName( $normalisedParams );
+               $thumbUrl = $this->getThumbUrl( $thumbName );
+               $thumbPath = $this->getThumbPath( $thumbName ); // final thumb path
+
+               $tmpThumbPath = $tmpFile->getPath();
+
+               if ( $handler->supportsBucketing() ) {
+                       $this->generateBucketsIfNeeded( $normalisedParams, $flags );
+               }
+
+               // Actually render the thumbnail...
+               wfProfileIn( __METHOD__ . '-doTransform' );
+               $thumb = $handler->doTransform( $this, $tmpThumbPath, $thumbUrl, $transformParams );
+               wfProfileOut( __METHOD__ . '-doTransform' );
+               $tmpFile->bind( $thumb ); // keep alive with $thumb
+
+               if ( !$thumb ) { // bad params?
+                       $thumb = false;
+               } elseif ( $thumb->isError() ) { // transform error
+                       $this->lastError = $thumb->toText();
+                       // Ignore errors if requested
+                       if ( $wgIgnoreImageErrors && !( $flags & self::RENDER_NOW ) ) {
+                               $thumb = $handler->getTransform( $this, $tmpThumbPath, $thumbUrl, $transformParams );
+                       }
+               } elseif ( $this->repo && $thumb->hasFile() && !$thumb->fileIsSource() ) {
+                       // Copy the thumbnail from the file system into storage...
+                       $disposition = $this->getThumbDisposition( $thumbName );
+                       $status = $this->repo->quickImport( $tmpThumbPath, $thumbPath, $disposition );
+                       if ( $status->isOK() ) {
+                               $thumb->setStoragePath( $thumbPath );
+                       } else {
+                               $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $transformParams, $flags );
+                       }
+                       // Give extensions a chance to do something with this thumbnail...
+                       wfRunHooks( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
+               }
+
+               // Purge. Useful in the event of Core -> Squid connection failure or squid
+               // purge collisions from elsewhere during failure. Don't keep triggering for
+               // "thumbs" which have the main image URL though (bug 13776)
+               if ( $wgUseSquid ) {
+                       if ( !$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL() ) {
+                               SquidUpdate::purge( array( $thumbUrl ) );
+                       }
+               }
+
+               return $thumb;
+       }
+
+       /**
+        * Generates chained bucketed thumbnails if needed
+        * @param array $params
+        * @param int $flags
+        * @return bool Whether at least one bucket was generated
+        */
+       protected function generateBucketsIfNeeded( $params, $flags = 0 ) {
+               if ( !$this->repo
+                       || !isset( $params['physicalWidth'] )
+                       || !isset( $params['physicalHeight'] )
+                       || !( $bucket = $this->getThumbnailBucket( $params['physicalWidth'] ) )
+                       || $bucket == $params['physicalWidth'] ) {
+                       return false;
+               }
+
+               $bucketPath = $this->getBucketThumbPath( $bucket );
+
+               if ( $this->repo->fileExists( $bucketPath ) ) {
+                       return false;
+               }
+
+               $params['physicalWidth'] = $bucket;
+               $params['width'] = $bucket;
+
+               $params = $this->getHandler()->sanitizeParamsForBucketing( $params );
+
+               $bucketName = $this->getBucketThumbName( $bucket );
+
+               $tmpFile = $this->makeTransformTmpFile( $bucketPath );
+
+               if ( !$tmpFile ) {
+                       return false;
+               }
+
+               $thumb = $this->generateAndSaveThumb( $tmpFile, $params, $flags );
+
+               if ( !$thumb || $thumb->isError() ) {
+                       return false;
+               }
+
+               $this->tmpBucketedThumbCache[ $bucket ] = $tmpFile->getPath();
+               // For the caching to work, we need to make the tmp file survive as long as
+               // this object exists
+               $tmpFile->bind( $this );
+
+               return true;
+       }
+
+       /**
+        * Returns the most appropriate source image for the thumbnail, given a target thumbnail size
+        * @param array $params
+        * @return array source path and width/height of the source
+        */
+       public function getThumbnailSource( $params ) {
+               if ( $this->repo
+                       && $this->getHandler()->supportsBucketing()
+                       && isset( $params['physicalWidth'] )
+                       && $bucket = $this->getThumbnailBucket( $params['physicalWidth'] )
+               ) {
+                       if ( $this->getWidth() != 0 ) {
+                               $bucketHeight = round( $this->getHeight() * ( $bucket / $this->getWidth() ) );
+                       } else {
+                               $bucketHeight = 0;
+                       }
+
+                       // Try to avoid reading from storage if the file was generated by this script
+                       if ( isset( $this->tmpBucketedThumbCache[ $bucket ] ) ) {
+                               $tmpPath = $this->tmpBucketedThumbCache[ $bucket ];
+
+                               if ( file_exists( $tmpPath ) ) {
+                                       return array(
+                                               'path' => $tmpPath,
+                                               'width' => $bucket,
+                                               'height' => $bucketHeight
+                                       );
                                }
-                               // Give extensions a chance to do something with this thumbnail...
-                               wfRunHooks( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
                        }
 
-                       // Purge. Useful in the event of Core -> Squid connection failure or squid
-                       // purge collisions from elsewhere during failure. Don't keep triggering for
-                       // "thumbs" which have the main image URL though (bug 13776)
-                       if ( $wgUseSquid ) {
-                               if ( !$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL() ) {
-                                       SquidUpdate::purge( array( $thumbUrl ) );
+                       $bucketPath = $this->getBucketThumbPath( $bucket );
+
+                       if ( $this->repo->fileExists( $bucketPath ) ) {
+                               $fsFile = $this->repo->getLocalReference( $bucketPath );
+
+                               if ( $fsFile ) {
+                                       return array(
+                                               'path' => $fsFile->getPath(),
+                                               'width' => $bucket,
+                                               'height' => $bucketHeight
+                                       );
                                }
                        }
-               } while ( false );
+               }
 
-               wfProfileOut( __METHOD__ );
+               // Original file
+               return array(
+                       'path' => $this->getLocalRefPath(),
+                       'width' => $this->getWidth(),
+                       'height' => $this->getHeight()
+               );
+       }
 
-               return is_object( $thumb ) ? $thumb : false;
+       /**
+        * Returns the repo path of the thumb for a given bucket
+        * @param int $bucket
+        * @return string
+        */
+       protected function getBucketThumbPath( $bucket ) {
+               $thumbName = $this->getBucketThumbName( $bucket );
+               return $this->getThumbPath( $thumbName );
+       }
+
+       /**
+        * Returns the name of the thumb for a given bucket
+        * @param int $bucket
+        * @return string
+        */
+       protected function getBucketThumbName( $bucket ) {
+               return $this->thumbName( array( 'physicalWidth' => $bucket ) );
+       }
+
+       /**
+        * Creates a temp FS file with the same extension and the thumbnail
+        * @param string $thumbPath Thumbnail path
+        * @returns TempFSFile
+        */
+       protected function makeTransformTmpFile( $thumbPath ) {
+               $thumbExt = FileBackend::extensionFromPath( $thumbPath );
+               return TempFSFile::factory( 'transform_', $thumbExt );
        }
 
        /**
@@ -1741,7 +1945,7 @@ abstract class File {
                        return false;
                }
 
-               return $this->handler->getImageSize( $this, $filePath );
+               return $this->getHandler()->getImageSize( $this, $filePath );
        }
 
        /**
index 300e68e..1f2defe 100644 (file)
@@ -594,6 +594,7 @@ class LocalFile extends File {
 
                # Don't destroy file info of missing files
                if ( !$this->fileExists ) {
+                       $this->unlock();
                        wfDebug( __METHOD__ . ": file does not exist, aborting\n" );
                        wfProfileOut( __METHOD__ );
 
@@ -604,6 +605,7 @@ class LocalFile extends File {
                list( $major, $minor ) = self::splitMime( $this->mime );
 
                if ( wfReadOnly() ) {
+                       $this->unlock();
                        wfProfileOut( __METHOD__ );
 
                        return;
@@ -1266,6 +1268,7 @@ class LocalFile extends File {
                # Fail now if the file isn't there
                if ( !$this->fileExists ) {
                        wfDebug( __METHOD__ . ": File " . $this->getRel() . " went missing!\n" );
+                       $dbw->rollback( __METHOD__ );
                        wfProfileOut( __METHOD__ );
 
                        return false;
@@ -2829,6 +2832,7 @@ class LocalFileMoveBatch {
                // cleanupTarget() to trigger. It would delete the C files and cause data loss.
                $statusDb = $this->doDBUpdates();
                if ( !$statusDb->isGood() ) {
+                       $destFile->unlock();
                        $this->file->unlockAndRollback();
                        $statusDb->ok = false;
 
@@ -2846,6 +2850,7 @@ class LocalFileMoveBatch {
                if ( !$statusMove->isGood() ) {
                        // Delete any files copied over (while the destination is still locked)
                        $this->cleanupTarget( $triplets );
+                       $destFile->unlock();
                        $this->file->unlockAndRollback(); // unlocks the destination
                        wfDebugLog( 'imagemove', "Error in moving files: " . $statusMove->getWikiText() );
                        $statusMove->ok = false;
index 8d2b949..837a731 100644 (file)
@@ -258,6 +258,14 @@ abstract class ImageGalleryBase extends ContextSource {
                array_unshift( $this->mImages, array( &$title, $html, $alt, $link, $handlerOpts ) );
        }
 
+       /**
+        * Returns the list of images this gallery contains
+        * @return array
+        */
+       public function getImages() {
+               return $this->mImages;
+       }
+
        /**
         * isEmpty() returns true if the gallery contains no images
         * @return bool
index 296de96..df6582c 100644 (file)
@@ -50,6 +50,7 @@
  *    'default'             -- default value when the form is displayed
  *    'id'                  -- HTML id attribute
  *    'cssclass'            -- CSS class
+ *    'csshelpclass'        -- CSS class used to style help text
  *    'options'             -- associative array mapping labels to values.
  *                             Some field types support multi-level arrays.
  *    'options-messages'    -- associative array mapping message keys to values.
@@ -171,6 +172,12 @@ class HTMLForm extends ContextSource {
 
        protected $mWrapperLegend = false;
 
+       /**
+        * Salt for the edit token.
+        * @var string|array
+        */
+       protected $mTokenSalt = '';
+
        /**
         * If true, sections that contain both fields and subsections will
         * render their subsections before their fields.
@@ -397,7 +404,7 @@ class HTMLForm extends ContextSource {
                                // Session tokens for logged-out users have no security value.
                                // However, if the user gave one, check it in order to give a nice
                                // "session expired" error instead of "permission denied" or such.
-                               $submit = $this->getUser()->matchEditToken( $editToken );
+                               $submit = $this->getUser()->matchEditToken( $editToken, $this->mTokenSalt );
                        } else {
                                $submit = true;
                        }
@@ -434,9 +441,12 @@ class HTMLForm extends ContextSource {
         * Validate all the fields, and call the submission callback
         * function if everything is kosher.
         * @throws MWException
-        * @return mixed Bool true == Successful submission, Bool false
-        *     == No submission attempted, anything else == Error to
-        *     display.
+        * @return bool|string|array|Status
+        *     - Bool true or a good Status object indicates success,
+        *     - Bool false indicates no submission was attempted,
+        *     - Anything else indicates failure. The value may be a fatal Status
+        *       object, an HTML string, or an array of arrays (message keys and
+        *       params) or strings (message keys)
         */
        function trySubmit() {
                $this->mWasSubmitted = true;
@@ -503,10 +513,9 @@ class HTMLForm extends ContextSource {
         * Set a callback to a function to do something with the form
         * once it's been successfully validated.
         *
-        * @param string $cb Function name.  The function will be passed
-        *     the output from HTMLForm::filterDataForSubmit, and must
-        *     return Bool true on success, Bool false if no submission
-        *     was attempted, or String HTML output to display on error.
+        * @param callable $cb The function will be passed the output from
+        *   HTMLForm::filterDataForSubmit and this HTMLForm object, and must
+        *   return as documented for HTMLForm::trySubmit
         *
         * @return HTMLForm $this for chaining calls (since 1.20)
         */
@@ -726,6 +735,21 @@ class HTMLForm extends ContextSource {
                return $this;
        }
 
+       /**
+        * Set the salt for the edit token.
+        *
+        * Only useful when the method is "post".
+        *
+        * @since 1.24
+        * @param string|array Salt to use
+        * @return HTMLForm $this for chaining calls
+        */
+       public function setTokenSalt( $salt ) {
+               $this->mTokenSalt = $salt;
+
+               return $this;
+       }
+
        /**
         * Display the form (sending to the context's OutputPage object), with an
         * appropriate error message or stack of messages, and any validation errors, etc.
@@ -734,7 +758,7 @@ class HTMLForm extends ContextSource {
         * Moreover, when doing method chaining this should be the very last method
         * call just after prepareForm().
         *
-        * @param mixed $submitResult Mixed output from HTMLForm::trySubmit()
+        * @param bool|string|array|Status $submitResult Output from HTMLForm::trySubmit()
         *
         * @return Nothing, should be last call
         */
@@ -745,7 +769,7 @@ class HTMLForm extends ContextSource {
        /**
         * Returns the raw HTML generated by the form
         *
-        * @param mixed $submitResult Mixed output from HTMLForm::trySubmit()
+        * @param bool|string|array|Status $submitResult Output from HTMLForm::trySubmit()
         *
         * @return string
         */
@@ -821,7 +845,7 @@ class HTMLForm extends ContextSource {
                if ( $this->getMethod() == 'post' ) {
                        $html .= Html::hidden(
                                'wpEditToken',
-                               $this->getUser()->getEditToken(),
+                               $this->getUser()->getEditToken( $this->mTokenSalt ),
                                array( 'id' => 'wpEditToken' )
                        ) . "\n";
                        $html .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n";
index 8076e8a..1fcc866 100644 (file)
@@ -13,6 +13,7 @@ abstract class HTMLFormField {
        protected $mLabel; # String label.  Set on construction
        protected $mID;
        protected $mClass = '';
+       protected $mHelpClass = false;
        protected $mDefault;
        protected $mOptions = false;
        protected $mOptionsLabelsNotFromMessage = false;
@@ -397,6 +398,10 @@ abstract class HTMLFormField {
                        $this->mClass = $params['cssclass'];
                }
 
+               if ( isset( $params['csshelpclass'] ) ) {
+                       $this->mHelpClass = $params['csshelpclass'];
+               }
+
                if ( isset( $params['validation-callback'] ) ) {
                        $this->mValidationCallback = $params['validation-callback'];
                }
@@ -562,7 +567,11 @@ abstract class HTMLFormField {
                        $rowAttributes['class'] = 'mw-htmlform-hide-if';
                }
 
-               $row = Html::rawElement( 'td', array( 'colspan' => 2, 'class' => 'htmlform-tip' ), $helptext );
+               $tdClasses = array( 'htmlform-tip' );
+               if ( $this->mHelpClass !== false ) {
+                       $tdClasses[] = $this->mHelpClass;
+               }
+               $row = Html::rawElement( 'td', array( 'colspan' => 2, 'class' => $tdClasses ), $helptext );
                $row = Html::rawElement( 'tr', $rowAttributes, $row );
 
                return $row;
index c32b445..a198037 100644 (file)
@@ -27,8 +27,10 @@ class HTMLSelectField extends HTMLFormField {
                        $select->setAttribute( 'disabled', 'disabled' );
                }
 
-               if ( isset( $this->mParams['tabindex'] ) ) {
-                       $select->setAttribute( 'tabindex', $this->mParams['tabindex'] );
+               $allowedParams = array( 'tabindex', 'size' );
+               $customParams = $this->getAttributes( $allowedParams );
+               foreach ( $customParams as $name => $value ) {
+                       $select->setAttribute( $name, $value );
                }
 
                if ( $this->mClass !== '' ) {
index 1c7762b..c6939a8 100644 (file)
@@ -179,16 +179,11 @@ class CliInstaller extends Installer {
        public function showHelpBox( $msg /*, ... */ ) {
        }
 
+       /**
+        * @param Status $status
+        */
        public function showStatusMessage( Status $status ) {
-               $warnings = array_merge( $status->getWarningsArray(),
-                       $status->getErrorsArray() );
-
-               if ( count( $warnings ) !== 0 ) {
-                       foreach ( $warnings as $w ) {
-                               call_user_func_array( array( $this, 'showMessage' ), $w );
-                       }
-               }
-
+               parent::showStatusMessage( $status );
                if ( !$status->isOk() ) {
                        echo "\n";
                        exit( 1 );
index 28dac46..b25ea09 100644 (file)
@@ -72,6 +72,7 @@ abstract class DatabaseUpdater {
                'PopulateImageSha1',
                'FixExtLinksProtocolRelative',
                'PopulateFilearchiveSha1',
+               'PopulateBacklinkNamespace'
        );
 
        /**
index 88478f4..1fdd6fb 100644 (file)
@@ -38,9 +38,6 @@
  */
 abstract class Installer {
 
-       // This is the absolute minimum PHP version we can support
-       const MINIMUM_PHP_VERSION = '5.3.2';
-
        /**
         * The oldest version of PCRE we can support.
         *
@@ -111,6 +108,10 @@ abstract class Installer {
         * These may output warnings using showMessage(), and/or abort the
         * installation process by returning false.
         *
+        * For the WebInstaller these are only called on the Welcome page,
+        * if these methods have side-effects that should affect later page loads
+        * (as well as the generated stylesheet), use envPreps instead.
+        *
         * @var array
         */
        protected $envChecks = array(
@@ -131,15 +132,26 @@ abstract class Installer {
                'envCheckGit',
                'envCheckServer',
                'envCheckPath',
-               'envCheckExtension',
                'envCheckShellLocale',
                'envCheckUploadsDirectory',
                'envCheckLibicu',
                'envCheckSuhosinMaxValueLength',
                'envCheckCtype',
+               'envCheckIconv',
                'envCheckJSON',
        );
 
+       /**
+        * A list of environment preparation methods called by doEnvironmentPreps().
+        *
+        * @var array
+        */
+       protected $envPreps = array(
+               'envPrepExtension',
+               'envPrepServer',
+               'envPrepPath',
+       );
+
        /**
         * MediaWiki configuration globals that will eventually be passed through
         * to LocalSettings.php. The names only are given here, the defaults
@@ -207,6 +219,7 @@ abstract class Installer {
                '_LicenseCode' => 'none',
                '_CCDone' => false,
                '_Extensions' => array(),
+               '_Skins' => array(),
                '_MemCachedServers' => '',
                '_UpgradeKeySupplied' => false,
                '_ExistingDBSettings' => false,
@@ -340,10 +353,17 @@ abstract class Installer {
        abstract public function showError( $msg /*, ... */ );
 
        /**
-        * Show a message to the installing user by using a Status object
+        * Shows messages to the user through a Status object
         * @param Status $status
         */
-       abstract public function showStatusMessage( Status $status );
+       public function showStatusMessage( Status $status ) {
+               $errors = array_merge( $status->getErrorsArray(), $status->getWarningsArray() );
+               if ( $errors ) {
+                       foreach ( $errors as $error ) {
+                               call_user_func( 'showMessage', $error );
+                       }
+               }
+       }
 
        /**
         * Constructor, always call this from child classes.
@@ -380,26 +400,17 @@ abstract class Installer {
                        $this->settings[$var] = $GLOBALS[$var];
                }
 
-               $compiledDBs = array();
+               $this->doEnvironmentPreps();
+
+               $this->compiledDBs = array();
                foreach ( self::getDBTypes() as $type ) {
                        $installer = $this->getDBInstaller( $type );
 
                        if ( !$installer->isCompiled() ) {
                                continue;
                        }
-                       $compiledDBs[] = $type;
-
-                       $defaults = $installer->getGlobalDefaults();
-
-                       foreach ( $installer->getGlobalNames() as $var ) {
-                               if ( isset( $defaults[$var] ) ) {
-                                       $this->settings[$var] = $defaults[$var];
-                               } else {
-                                       $this->settings[$var] = $GLOBALS[$var];
-                               }
-                       }
+                       $this->compiledDBs[] = $type;
                }
-               $this->compiledDBs = $compiledDBs;
 
                $this->parserTitle = Title::newFromText( 'Installer' );
                $this->parserOptions = new ParserOptions; // language will be wrong :(
@@ -429,25 +440,17 @@ abstract class Installer {
         * @return Status
         */
        public function doEnvironmentChecks() {
-               $phpVersion = phpversion();
-               if ( version_compare( $phpVersion, self::MINIMUM_PHP_VERSION, '>=' ) ) {
-                       $this->showMessage( 'config-env-php', $phpVersion );
-                       $good = true;
-               } else {
-                       $this->showMessage( 'config-env-php-toolow', $phpVersion, self::MINIMUM_PHP_VERSION );
-                       $good = false;
-               }
+               // Php version has already been checked by entry scripts
+               // Show message here for information purposes
+               $this->showMessage( 'config-env-php', PHP_VERSION );
 
+               $good = true;
                // Must go here because an old version of PCRE can prevent other checks from completing
-               if ( $good ) {
-                       list( $pcreVersion ) = explode( ' ', PCRE_VERSION, 2 );
-                       if ( version_compare( $pcreVersion, self::MINIMUM_PCRE_VERSION, '<' ) ) {
-                               $this->showError( 'config-pcre-old', self::MINIMUM_PCRE_VERSION, $pcreVersion );
-                               $good = false;
-                       }
-               }
-
-               if ( $good ) {
+               list( $pcreVersion ) = explode( ' ', PCRE_VERSION, 2 );
+               if ( version_compare( $pcreVersion, self::MINIMUM_PCRE_VERSION, '<' ) ) {
+                       $this->showError( 'config-pcre-old', self::MINIMUM_PCRE_VERSION, $pcreVersion );
+                       $good = false;
+               } else {
                        foreach ( $this->envChecks as $check ) {
                                $status = $this->$check();
                                if ( $status === false ) {
@@ -461,6 +464,12 @@ abstract class Installer {
                return $good ? Status::newGood() : Status::newFatal( 'config-env-bad' );
        }
 
+       public function doEnvironmentPreps() {
+               foreach ( $this->envPreps as $prep ) {
+                       $this->$prep();
+               }
+       }
+
        /**
         * Set a MW configuration variable, or internal installer configuration variable.
         *
@@ -726,11 +735,15 @@ abstract class Installer {
 
        /**
         * Environment check for register_globals.
+        * Prevent installation if enabled
         */
        protected function envCheckRegisterGlobals() {
                if ( wfIniGetBool( 'register_globals' ) ) {
-                       $this->showMessage( 'config-register-globals' );
+                       $this->showMessage( 'config-register-globals-error' );
+                       return false;
                }
+
+               return true;
        }
 
        /**
@@ -971,55 +984,29 @@ abstract class Installer {
        }
 
        /**
-        * Environment check for the server hostname.
+        * Environment check to inform user which server we've assumed.
+        *
+        * @return bool
         */
        protected function envCheckServer() {
                $server = $this->envGetDefaultServer();
                if ( $server !== null ) {
                        $this->showMessage( 'config-using-server', $server );
-                       $this->setVar( 'wgServer', $server );
                }
-
                return true;
        }
 
        /**
-        * Helper function to be called from envCheckServer()
-        * @return string
-        */
-       abstract protected function envGetDefaultServer();
-
-       /**
-        * Environment check for setting $IP and $wgScriptPath.
+        * Environment check to inform user which paths we've assumed.
+        *
         * @return bool
         */
        protected function envCheckPath() {
-               global $IP;
-               $IP = dirname( dirname( __DIR__ ) );
-               $this->setVar( 'IP', $IP );
-
                $this->showMessage(
                        'config-using-uri',
                        $this->getVar( 'wgServer' ),
                        $this->getVar( 'wgScriptPath' )
                );
-
-               return true;
-       }
-
-       /**
-        * Environment check for setting the preferred PHP file extension.
-        * @return bool
-        */
-       protected function envCheckExtension() {
-               // @todo FIXME: Detect this properly
-               if ( defined( 'MW_INSTALL_PHP5_EXT' ) ) {
-                       $ext = 'php5';
-               } else {
-                       $ext = 'php';
-               }
-               $this->setVar( 'wgScriptExtension', ".$ext" );
-
                return true;
        }
 
@@ -1221,6 +1208,19 @@ abstract class Installer {
                return true;
        }
 
+       /**
+        * @return bool
+        */
+       protected function envCheckIconv() {
+               if ( !function_exists( 'iconv' ) ) {
+                       $this->showError( 'config-iconv' );
+
+                       return false;
+               }
+
+               return true;
+       }
+
        /**
         * @return bool
         */
@@ -1234,6 +1234,44 @@ abstract class Installer {
                return true;
        }
 
+       /**
+        * Environment prep for the server hostname.
+        */
+       protected function envPrepServer() {
+               $server = $this->envGetDefaultServer();
+               if ( $server !== null ) {
+                       $this->setVar( 'wgServer', $server );
+               }
+       }
+
+       /**
+        * Helper function to be called from envPrepServer()
+        * @return string
+        */
+       abstract protected function envGetDefaultServer();
+
+       /**
+        * Environment prep for setting the preferred PHP file extension.
+        */
+       protected function envPrepExtension() {
+               // @todo FIXME: Detect this properly
+               if ( defined( 'MW_INSTALL_PHP5_EXT' ) ) {
+                       $ext = '.php5';
+               } else {
+                       $ext = '.php';
+               }
+               $this->setVar( 'wgScriptExtension', $ext );
+       }
+
+       /**
+        * Environment prep for setting $IP and $wgScriptPath.
+        */
+       protected function envPrepPath() {
+               global $IP;
+               $IP = dirname( dirname( __DIR__ ) );
+               $this->setVar( 'IP', $IP );
+       }
+
        /**
         * Get an array of likely places we can find executables. Check a bunch
         * of known Unix-like defaults, as well as the PATH environment variable
@@ -1403,17 +1441,20 @@ abstract class Installer {
        }
 
        /**
-        * Finds extensions that follow the format /extensions/Name/Name.php,
+        * Finds extensions that follow the format /$directory/Name/Name.php,
         * and returns an array containing the value for 'Name' for each found extension.
         *
+        * Reasonable values for $directory include 'extensions' (the default) and 'skins'.
+        *
+        * @param string $directory Directory to search in
         * @return array
         */
-       public function findExtensions() {
+       public function findExtensions( $directory = 'extensions' ) {
                if ( $this->getVar( 'IP' ) === null ) {
                        return array();
                }
 
-               $extDir = $this->getVar( 'IP' ) . '/extensions';
+               $extDir = $this->getVar( 'IP' ) . '/' . $directory;
                if ( !is_readable( $extDir ) || !is_dir( $extDir ) ) {
                        return array();
                }
@@ -1531,8 +1572,8 @@ abstract class Installer {
        /**
         * Actually perform the installation.
         *
-        * @param array $startCB A callback array for the beginning of each step
-        * @param array $endCB A callback array for the end of each step
+        * @param callable $startCB A callback array for the beginning of each step
+        * @param callable $endCB A callback array for the end of each step
         *
         * @return array Array of Status objects
         */
@@ -1747,7 +1788,7 @@ abstract class Installer {
        /**
         * Add an installation step following the given step.
         *
-        * @param array $callback A valid installation callback array, in this form:
+        * @param callable $callback A valid installation callback array, in this form:
         *    array( 'name' => 'some-unique-name', 'callback' => array( $obj, 'function' ) );
         * @param string $findStep The step to find. Omit to put the step at the beginning
         */
index 3c8a5b1..c0ba300 100644 (file)
@@ -49,6 +49,7 @@ class LocalSettingsGenerator {
                $this->installer = $installer;
 
                $this->extensions = $installer->getVar( '_Extensions' );
+               $this->skins = $installer->getVar( '_Skins' );
 
                $db = $installer->getDBInstaller( $installer->getVar( 'wgDBtype' ) );
 
@@ -129,13 +130,26 @@ class LocalSettingsGenerator {
 
        /**
         * Return the full text of the generated LocalSettings.php file,
-        * including the extensions
+        * including the extensions and skins.
         *
         * @return string
         */
        public function getText() {
                $localSettings = $this->getDefaultText();
 
+               if ( count( $this->skins ) ) {
+                       $localSettings .= "
+# Enabled skins.
+# The following skins were automatically enabled:\n";
+
+                       foreach ( $this->skins as $skinName ) {
+                               $encSkinName = self::escapePhpString( $skinName );
+                               $localSettings .= "require_once \"\$IP/skins/$encSkinName/$encSkinName.php\";\n";
+                       }
+
+                       $localSettings .= "\n";
+               }
+
                if ( count( $this->extensions ) ) {
                        $localSettings .= "
 # Enabled Extensions. Most extensions are enabled by including the base extension file here
@@ -146,9 +160,12 @@ class LocalSettingsGenerator {
                                $encExtName = self::escapePhpString( $extName );
                                $localSettings .= "require_once \"\$IP/extensions/$encExtName/$encExtName.php\";\n";
                        }
+
+                       $localSettings .= "\n";
                }
 
-               $localSettings .= "\n\n# End of automatically generated settings.
+               $localSettings .= "
+# End of automatically generated settings.
 # Add more configuration options below.\n\n";
 
                return $localSettings;
@@ -202,7 +219,6 @@ class LocalSettingsGenerator {
                        $locale = '';
                }
 
-               //$rightsUrl = $this->values['wgRightsUrl'] ? '' : '#'; // @todo FIXME: I'm unused!
                $hashedUploads = $this->safeMode ? '' : '#';
                $metaNamespace = '';
                if ( $this->values['wgMetaNamespace'] !== $this->values['wgSitename'] ) {
@@ -221,6 +237,8 @@ class LocalSettingsGenerator {
                                                wfBoolToStr( $perm ) . ";\n";
                                }
                        }
+                       $groupRights .= "\n";
+
                        if ( ( isset( $this->groupPermissions['*']['edit'] ) &&
                                        $this->groupPermissions['*']['edit'] === false )
                                && ( isset( $this->groupPermissions['*']['createaccount'] ) &&
@@ -228,12 +246,12 @@ class LocalSettingsGenerator {
                                && ( isset( $this->groupPermissions['*']['read'] ) &&
                                        $this->groupPermissions['*']['read'] !== false )
                        ) {
-                               $noFollow = "\n# Set \$wgNoFollowLinks to true if you open up your wiki to editing by\n"
+                               $noFollow = "# Set \$wgNoFollowLinks to true if you open up your wiki to editing by\n"
                                        . "# the general public and wish to apply nofollow to external links as a\n"
                                        . "# deterrent to spammers. Nofollow is not a comprehensive anti-spam solution\n"
                                        . "# and open wikis will generally require other anti-spam measures; for more\n"
                                        . "# information, see https://www.mediawiki.org/wiki/Manual:Combating_spam\n"
-                                       . "\$wgNoFollowLinks = false;";
+                                       . "\$wgNoFollowLinks = false;\n\n";
                        }
                }
 
@@ -353,10 +371,6 @@ ${serverSetting}
 # web installer while LocalSettings.php is in place
 \$wgUpgradeKey = \"{$this->values['wgUpgradeKey']}\";
 
-## Default skin: you can change the default skin. Use the internal symbolic
-## names, ie 'vector', 'monobook':
-\$wgDefaultSkin = \"{$this->values['wgDefaultSkin']}\";
-
 ## For attaching licensing metadata to pages, and displaying an
 ## appropriate copyright notice / icon. GNU Free Documentation
 ## License and Creative Commons licenses are supported so far.
@@ -368,6 +382,9 @@ ${serverSetting}
 # Path to the GNU diff3 utility. Used for conflict resolution.
 \$wgDiff3 = \"{$this->values['wgDiff3']}\";
 
-{$groupRights}{$noFollow}";
+{$groupRights}{$noFollow}## Default skin: you can change the default skin. Use the internal symbolic
+## names, ie 'vector', 'monobook':
+\$wgDefaultSkin = \"{$this->values['wgDefaultSkin']}\";
+";
        }
 }
index 51db148..83681b6 100644 (file)
@@ -218,6 +218,7 @@ class MssqlInstaller extends DatabaseInstaller {
                                'password' => $password,
                                'dbname' => false,
                                'flags' => 0,
+                               'schema' => $this->getVar( 'wgDBmwschema' ),
                                'tablePrefix' => $this->getVar( 'wgDBprefix' ) ) );
                        $db->prepareStatements( false );
                        $db->scrollableCursor( false );
@@ -648,6 +649,14 @@ class MssqlInstaller extends DatabaseInstaller {
                return $status;
        }
 
+       public function getGlobalDefaults() {
+               // The default $wgDBmwschema is null, which breaks Postgres and other DBMSes that require
+               // the use of a schema, so we need to set it here
+               return array(
+                       'wgDBmwschema' => 'mediawiki',
+               );
+       }
+
        /**
         * Try to see if the login exists
         * @param string $user Username to check
index d590a70..4d86d11 100644 (file)
@@ -65,6 +65,8 @@ class MssqlUpdater extends DatabaseUpdater {
         * @return bool False if patch is skipped.
         */
        protected function updateConstraints( $constraintType, $table, $field ) {
+               global $wgDBname, $wgDBmwschema;
+
                if ( !$this->doTable( $table ) ) {
                        return true;
                }
index 10f6692..b82e611 100644 (file)
@@ -120,7 +120,7 @@ class MysqlInstaller extends DatabaseInstaller {
                if ( !strlen( $newValues['_InstallUser'] ) ) {
                        $status->fatal( 'config-db-username-empty' );
                }
-               if (!strlen( $newValues['_InstallPassword'] ) ) {
+               if ( !strlen( $newValues['_InstallPassword'] ) ) {
                        $status->fatal( 'config-db-password-empty', $newValues['_InstallUser'] );
                }
                if ( !$status->isOK() ) {
index 853ee0b..dcf37b6 100644 (file)
@@ -256,6 +256,9 @@ class MysqlUpdater extends DatabaseUpdater {
                        array( 'dropField', 'recentchanges', 'rc_cur_time', 'patch-drop-rc_cur_time.sql' ),
                        array( 'addIndex', 'watchlist', 'wl_user_notificationtimestamp', 'patch-watchlist-user-notificationtimestamp-index.sql' ),
                        array( 'addField', 'page', 'page_lang', 'patch-page_lang.sql' ),
+                       array( 'addField', 'pagelinks', 'pl_from_namespace', 'patch-pl_from_namespace.sql' ),
+                       array( 'addField', 'templatelinks', 'tl_from_namespace', 'patch-tl_from_namespace.sql' ),
+                       array( 'addField', 'imagelinks', 'il_from_namespace', 'patch-il_from_namespace.sql' ),
                );
        }
 
index 9e25f47..4caf902 100644 (file)
@@ -84,7 +84,7 @@ class PostgresInstaller extends DatabaseInstaller {
        function submitConnectForm() {
                // Get variables from the request
                $newValues = $this->setVarsFromRequest( array(
-                       'wgDBserver', 'wgDBport','wgDBname', 'wgDBmwschema',
+                       'wgDBserver', 'wgDBport', 'wgDBname', 'wgDBmwschema',
                        '_InstallUser', '_InstallPassword'
                ) );
 
@@ -152,17 +152,18 @@ class PostgresInstaller extends DatabaseInstaller {
         * @param string $user User name
         * @param string $password Password
         * @param string $dbName Database name
+        * @param string $schema Database schema
         * @return Status
         */
-       protected function openConnectionWithParams( $user, $password, $dbName ) {
+       protected function openConnectionWithParams( $user, $password, $dbName, $schema ) {
                $status = Status::newGood();
                try {
-                       $db = new DatabasePostgres(
-                               $this->getVar( 'wgDBserver' ),
-                               $user,
-                               $password,
-                               $dbName
-                       );
+                       $db = Database::factory( 'postgres', array(
+                               'host' => $this->getVar( 'wgDBserver' ),
+                               'user' => $user,
+                               'password' => $password,
+                               'dbname' => $dbName,
+                               'schema' => $schema ) );
                        $status->value = $db;
                } catch ( DBConnectionError $e ) {
                        $status->fatal( 'config-connection-error', $e->getMessage() );
@@ -230,7 +231,8 @@ class PostgresInstaller extends DatabaseInstaller {
                                return $this->openConnectionWithParams(
                                        $this->getVar( '_InstallUser' ),
                                        $this->getVar( '_InstallPassword' ),
-                                       $this->getVar( 'wgDBname' ) );
+                                       $this->getVar( 'wgDBname' ),
+                                       $this->getVar( 'wgDBmwschema' ) );
                        case 'create-tables':
                                $status = $this->openPgConnection( 'create-schema' );
                                if ( $status->isOK() ) {
@@ -260,11 +262,11 @@ class PostgresInstaller extends DatabaseInstaller {
                $status = Status::newGood();
                foreach ( $dbs as $db ) {
                        try {
-                               $conn = new DatabasePostgres(
-                                       $this->getVar( 'wgDBserver' ),
+                               $conn = $this->openConnectionWithParams(
                                        $user,
                                        $password,
-                                       $db );
+                                       $db,
+                                       $this->getVar( 'wgDBmwschema' ) );
                        } catch ( DBConnectionError $error ) {
                                $conn = false;
                                $status->fatal( 'config-pg-test-error', $db,
@@ -622,6 +624,14 @@ class PostgresInstaller extends DatabaseInstaller {
                return $status;
        }
 
+       public function getGlobalDefaults() {
+               // The default $wgDBmwschema is null, which breaks Postgres and other DBMSes that require
+               // the use of a schema, so we need to set it here
+               return array(
+                       'wgDBmwschema' => 'mediawiki',
+               );
+       }
+
        public function setupPLpgSQL() {
                // Connect as the install user, since it owns the database and so is
                // the user that needs to run "CREATE LANGAUGE"
index 8404c2d..9e8ee94 100644 (file)
@@ -415,6 +415,9 @@ class PostgresUpdater extends DatabaseUpdater {
                        array( 'addPgIndex', 'page_props', 'pp_propname_sortkey_page',
                                        '( pp_propname, pp_sortkey, pp_page ) WHERE ( pp_sortkey IS NOT NULL )' ),
                        array( 'addPgField', 'page', 'page_lang', 'TEXT default NULL' ),
+                       array( 'addPgField', 'pagelinks', 'pl_from_namespace', 'INTEGER NOT NULL DEFAULT 0' ),
+                       array( 'addPgField', 'templatelinks', 'tl_from_namespace', 'INTEGER NOT NULL DEFAULT 0' ),
+                       array( 'addPgField', 'imagelinks', 'il_from_namespace', 'INTEGER NOT NULL DEFAULT 0' ),
                );
        }
 
@@ -694,7 +697,7 @@ END;
                        $this->output( "...column '$table.$field' is already of type '$newtype'\n" );
                } else {
                        $this->output( "Purging data from cache table '$table'\n" );
-                       $this->db->query("DELETE from $table" );
+                       $this->db->query( "DELETE from $table" );
                        $this->output( "Changing column type of '$table.$field' from '{$fi->type()}' to '$newtype'\n" );
                        $sql = "ALTER TABLE $table ALTER $field TYPE $newtype";
                        if ( strlen( $default ) ) {
index cf3f065..ab5ab7d 100644 (file)
@@ -134,6 +134,9 @@ class SqliteUpdater extends DatabaseUpdater {
                        array( 'dropField', 'recentchanges', 'rc_cur_time', 'patch-drop-rc_cur_time.sql' ),
                        array( 'addIndex', 'watchlist', 'wl_user_notificationtimestamp', 'patch-watchlist-user-notificationtimestamp-index.sql' ),
                        array( 'addField', 'page', 'page_lang', 'patch-page-page_lang.sql' ),
+                       array( 'addField', 'pagelinks', 'pl_from_namespace', 'patch-pl_from_namespace.sql' ),
+                       array( 'addField', 'templatelinks', 'tl_from_namespace', 'patch-tl_from_namespace.sql' ),
+                       array( 'addField', 'imagelinks', 'il_from_namespace', 'patch-il_from_namespace.sql' ),
                );
        }
 
index 46348f9..3515469 100644 (file)
@@ -729,16 +729,6 @@ class WebInstaller extends Installer {
                $this->output->addHTML( $html );
        }
 
-       /**
-        * @param Status $status
-        */
-       public function showStatusMessage( Status $status ) {
-               $errors = array_merge( $status->getErrorsArray(), $status->getWarningsArray() );
-               foreach ( $errors as $error ) {
-                       call_user_func_array( array( $this, 'showMessage' ), $error );
-               }
-       }
-
        /**
         * Label a control by wrapping a config-input div around it and putting a
         * label before it.
@@ -960,6 +950,7 @@ class WebInstaller extends Installer {
         *      var:             The variable to be configured (required)
         *      label:           The message name for the label (required)
         *      itemLabelPrefix: The message name prefix for the item labels (required)
+        *      itemLabels:      List of message names to use for the item labels instead of itemLabelPrefix, keyed by values
         *      values:          List of allowed values (required)
         *      itemAttribs:     Array of attribute arrays, outer key is the value name (optional)
         *      commonAttribs:   Attribute array applied to all items
@@ -970,23 +961,49 @@ class WebInstaller extends Installer {
         * @return string
         */
        public function getRadioSet( $params ) {
-               if ( !isset( $params['controlName'] ) ) {
-                       $params['controlName'] = 'config_' . $params['var'];
-               }
-
-               if ( !isset( $params['value'] ) ) {
-                       $params['value'] = $this->getVar( $params['var'] );
-               }
+               $items = $this->getRadioElements( $params );
 
                if ( !isset( $params['label'] ) ) {
                        $label = '';
                } else {
                        $label = $params['label'];
                }
+
+               if ( !isset( $params['controlName'] ) ) {
+                       $params['controlName'] = 'config_' . $params['var'];
+               }
+
                if ( !isset( $params['help'] ) ) {
                        $params['help'] = "";
                }
+
                $s = "<ul>\n";
+               foreach ( $items as $value => $item ) {
+                       $s .= "<li>$item</li>\n";
+               }
+               $s .= "</ul>\n";
+
+               return $this->label( $label, $params['controlName'], $s, $params['help'] );
+       }
+
+       /**
+        * Get a set of labelled radio buttons. You probably want to use getRadioSet(), not this.
+        *
+        * @see getRadioSet
+        *
+        * @return array
+        */
+       public function getRadioElements( $params ) {
+               if ( !isset( $params['controlName'] ) ) {
+                       $params['controlName'] = 'config_' . $params['var'];
+               }
+
+               if ( !isset( $params['value'] ) ) {
+                       $params['value'] = $this->getVar( $params['var'] );
+               }
+
+               $items = array();
+
                foreach ( $params['values'] as $value ) {
                        $itemAttribs = array();
 
@@ -1003,19 +1020,17 @@ class WebInstaller extends Installer {
                        $itemAttribs['id'] = $id;
                        $itemAttribs['tabindex'] = $this->nextTabIndex();
 
-                       $s .=
-                               '<li>' .
+                       $items[$value] =
                                Xml::radio( $params['controlName'], $value, $checked, $itemAttribs ) .
                                '&#160;' .
                                Xml::tags( 'label', array( 'for' => $id ), $this->parse(
-                                       wfMessage( $params['itemLabelPrefix'] . strtolower( $value ) )->plain()
-                               ) ) .
-                               "</li>\n";
+                                       isset( $params['itemLabels'] ) ?
+                                               wfMessage( $params['itemLabels'][$value] )->plain() :
+                                               wfMessage( $params['itemLabelPrefix'] . strtolower( $value ) )->plain()
+                               ) );
                }
 
-               $s .= "</ul>\n";
-
-               return $this->label( $label, $params['controlName'], $s, $params['help'] );
+               return $items;
        }
 
        /**
@@ -1051,7 +1066,11 @@ class WebInstaller extends Installer {
                $newValues = array();
 
                foreach ( $varNames as $name ) {
-                       $value = trim( $this->request->getVal( $prefix . $name ) );
+                       $value = $this->request->getVal( $prefix . $name );
+                       // bug 30524, do not trim passwords
+                       if ( stripos( $name, 'password' ) === false ) {
+                               $value = trim( $value );
+                       }
                        $newValues[$name] = $value;
 
                        if ( $value === null ) {
@@ -1135,8 +1154,18 @@ class WebInstaller extends Installer {
                        $path = $_SERVER['SCRIPT_NAME'];
                }
                if ( $path !== false ) {
-                       $uri = preg_replace( '{^(.*)/(mw-)?config.*$}', '$1', $path );
-                       $this->setVar( 'wgScriptPath', $uri );
+                       $scriptPath = preg_replace( '{^(.*)/(mw-)?config.*$}', '$1', $path );
+                       $scriptExtension = $this->getVar( 'wgScriptExtension' );
+
+                       $this->setVar( 'wgScriptPath', "$scriptPath" );
+                       // Update variables set from Setup.php that are derived from wgScriptPath
+                       $this->setVar( 'wgScript', "$scriptPath/index$scriptExtension" );
+                       $this->setVar( 'wgLoadScript', "$scriptPath/load$scriptExtension" );
+                       $this->setVar( 'wgStylePath', "$scriptPath/skins" );
+                       $this->setVar( 'wgLocalStylePath', "$scriptPath/skins" );
+                       $this->setVar( 'wgExtensionAssetsPath', "$scriptPath/extensions" );
+                       $this->setVar( 'wgUploadPath', "$scriptPath/images" );
+
                } else {
                        $this->showError( 'config-no-uri' );
 
index 97f4830..174120f 100644 (file)
@@ -126,7 +126,6 @@ class WebInstallerOutput {
        public function getCSS() {
                // Horrible, horrible hack: the installer is currently hardcoded to use the Vector skin, so load
                // it here. Include instead of require, as this will work without it, it will just look bad.
-               global $wgResourceModules;
                global $wgStyleDirectory;
                include_once "$wgStyleDirectory/Vector/Vector.php";
 
index 06b561b..c26028d 100644 (file)
@@ -145,11 +145,12 @@ abstract class WebInstallerPage {
 
        /**
         * @param string $var
+        * @param mixed $default
         *
         * @return mixed
         */
-       public function getVar( $var ) {
-               return $this->parent->getVar( $var );
+       public function getVar( $var, $default = null ) {
+               return $this->parent->getVar( $var, $default );
        }
 
        /**
@@ -948,6 +949,7 @@ class WebInstallerOptions extends WebInstallerPage {
         */
        public function execute() {
                if ( $this->getVar( '_SkipOptional' ) == 'skip' ) {
+                       $this->submitSkins();
                        return 'skip';
                }
                if ( $this->parent->request->wasPosted() ) {
@@ -1025,6 +1027,38 @@ class WebInstallerOptions extends WebInstallerPage {
                        $this->getFieldSetEnd()
                );
 
+               $skins = $this->parent->findExtensions( 'skins' );
+               $skinHtml = $this->getFieldSetStart( 'config-skins' );
+
+               if ( $skins ) {
+                       $skinNames = array_map( 'strtolower', $skins );
+
+                       $radioButtons = $this->parent->getRadioElements( array(
+                               'var' => 'wgDefaultSkin',
+                               'itemLabels' => array_fill_keys( $skinNames, 'config-skins-use-as-default' ),
+                               'values' => $skinNames,
+                               'value' => $this->getVar( 'wgDefaultSkin', $this->getDefaultSkin( $skinNames ) ),
+                       ) );
+
+                       foreach ( $skins as $skin ) {
+                               $skinHtml .=
+                                       '<div class="config-skins-item">' .
+                                       $this->parent->getCheckBox( array(
+                                               'var' => "skin-$skin",
+                                               'rawtext' => $skin,
+                                               'value' => $this->getVar( "skin-$skin", true ), // all found skins enabled by default
+                                       ) ) .
+                                       '<div class="config-skins-use-as-default">' . $radioButtons[ strtolower( $skin ) ] . '</div>' .
+                                       '</div>';
+                       }
+               } else {
+                       $skinHtml .= $this->parent->getWarningBox( wfMessage( 'config-skins-missing' )->plain() );
+               }
+
+               $skinHtml .= $this->parent->getHelpBox( 'config-skins-help' ) .
+                       $this->getFieldSetEnd();
+               $this->addHTML( $skinHtml );
+
                $extensions = $this->parent->findExtensions();
 
                if ( $extensions ) {
@@ -1220,6 +1254,40 @@ class WebInstallerOptions extends WebInstallerPage {
                $this->addHTML( $this->getCCDoneBox() );
        }
 
+       /**
+        * Returns a default value to be used for $wgDefaultSkin: the preferred skin, if available among
+        * the installed skins, or any other one otherwise.
+        *
+        * @param string[] $skinNames Names of installed skins.
+        * @return string
+        */
+       public function getDefaultSkin( array $skinNames ) {
+               $defaultSkin = $GLOBALS['wgDefaultSkin'];
+               if ( in_array( $defaultSkin, $skinNames ) ) {
+                       return $defaultSkin;
+               } else {
+                       return $skinNames[0];
+               }
+       }
+
+       /**
+        * If the user skips this installer page, we still need to set up the default skins, but ignore
+        * everything else.
+        *
+        * @return bool
+        */
+       public function submitSkins() {
+               $skins = $this->parent->findExtensions( 'skins' );
+               $this->parent->setVar( '_Skins', $skins );
+
+               if ( $skins ) {
+                       $skinNames = array_map( 'strtolower', $skins );
+                       $this->parent->setVar( 'wgDefaultSkin', $this->getDefaultSkin( $skinNames ) );
+               }
+
+               return true;
+       }
+
        /**
         * @return bool
         */
@@ -1228,7 +1296,9 @@ class WebInstallerOptions extends WebInstallerPage {
                        'wgEnableEmail', 'wgPasswordSender', 'wgEnableUploads', 'wgLogo',
                        'wgEnableUserEmail', 'wgEnotifUserTalk', 'wgEnotifWatchlist',
                        'wgEmailAuthentication', 'wgMainCacheType', '_MemCachedServers',
-                       'wgUseInstantCommons' ) );
+                       'wgUseInstantCommons', 'wgDefaultSkin' ) );
+
+               $retVal = true;
 
                if ( !array_key_exists( $this->getVar( '_RightsProfile' ), $this->parent->rightsProfiles )
                ) {
@@ -1240,8 +1310,7 @@ class WebInstallerOptions extends WebInstallerPage {
                if ( $code == 'cc-choose' ) {
                        if ( !$this->getVar( '_CCDone' ) ) {
                                $this->parent->showError( 'config-cc-not-chosen' );
-
-                               return false;
+                               $retVal = false;
                        }
                } elseif ( array_key_exists( $code, $this->parent->licenses ) ) {
                        // Messages:
@@ -1262,10 +1331,32 @@ class WebInstallerOptions extends WebInstallerPage {
                        $this->setVar( 'wgRightsIcon', '' );
                }
 
+               $skinsAvailable = $this->parent->findExtensions( 'skins' );
+               $skinsToInstall = array();
+               foreach ( $skinsAvailable as $skin ) {
+                       $this->parent->setVarsFromRequest( array( "skin-$skin" ) );
+                       if ( $this->getVar( "skin-$skin" ) ) {
+                               $skinsToInstall[] = $skin;
+                       }
+               }
+               $this->parent->setVar( '_Skins', $skinsToInstall );
+
+               if ( !$skinsToInstall && $skinsAvailable ) {
+                       $this->parent->showError( 'config-skins-must-enable-some' );
+                       $retVal = false;
+               }
+               $defaultSkin = $this->getVar( 'wgDefaultSkin' );
+               $skinsToInstallLowercase = array_map( 'strtolower', $skinsToInstall );
+               if ( $skinsToInstall && array_search( $defaultSkin, $skinsToInstallLowercase ) === false ) {
+                       $this->parent->showError( 'config-skins-must-enable-default' );
+                       $retVal = false;
+               }
+
                $extsAvailable = $this->parent->findExtensions();
                $extsToInstall = array();
                foreach ( $extsAvailable as $ext ) {
-                       if ( $this->parent->request->getCheck( 'config_ext-' . $ext ) ) {
+                       $this->parent->setVarsFromRequest( array( "ext-$ext" ) );
+                       if ( $this->getVar( "ext-$ext" ) ) {
                                $extsToInstall[] = $ext;
                        }
                }
@@ -1275,8 +1366,7 @@ class WebInstallerOptions extends WebInstallerPage {
                        $memcServers = explode( "\n", $this->getVar( '_MemCachedServers' ) );
                        if ( !$memcServers ) {
                                $this->parent->showError( 'config-memcache-needservers' );
-
-                               return false;
+                               $retVal = false;
                        }
 
                        foreach ( $memcServers as $server ) {
@@ -1286,21 +1376,18 @@ class WebInstallerOptions extends WebInstallerPage {
                                                && ( gethostbyname( $memcParts[0] ) == $memcParts[0] ) )
                                ) {
                                        $this->parent->showError( 'config-memcache-badip', $memcParts[0] );
-
-                                       return false;
+                                       $retVal = false;
                                } elseif ( !isset( $memcParts[1] ) ) {
                                        $this->parent->showError( 'config-memcache-noport', $memcParts[0] );
-
-                                       return false;
+                                       $retVal = false;
                                } elseif ( $memcParts[1] < 1 || $memcParts[1] > 65535 ) {
                                        $this->parent->showError( 'config-memcache-badport', 1, 65535 );
-
-                                       return false;
+                                       $retVal = false;
                                }
                        }
                }
 
-               return true;
+               return $retVal;
        }
 
 }
index 376a227..dc5c0b7 100644 (file)
@@ -51,7 +51,6 @@
        "config-env-good": "Асяродзьдзе было праверанае.\nВы можаце ўсталёўваць MediaWiki.",
        "config-env-bad": "Асяродзьдзе было праверанае.\nУсталяваньне MediaWiki немагчымае.",
        "config-env-php": "Усталяваны PHP $1.",
-       "config-env-php-toolow": "Усталяваны PHP $1.\nАле MediaWiki патрабуе PHP вэрсіі $2 ці навейшай.",
        "config-unicode-using-utf8": "Выкарыстоўваецца бібліятэка Unicode-нармалізацыі Браяна Вібэра",
        "config-unicode-using-intl": "Выкарыстоўваецца [http://pecl.php.net/intl intl пашырэньне з PECL] для Unicode-нармалізацыі",
        "config-unicode-pure-php-warning": "'''Папярэджаньне''': [http://pecl.php.net/intl Пашырэньне intl з PECL] — ня слушнае для Unicode-нармалізацыі, цяпер выкарыстоўваецца марудная PHP-рэалізацыя.\nКалі ў Вас сайт з высокай наведваемасьцю, раім пачытаць пра [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-нармалізацыю].",
@@ -59,7 +58,7 @@
        "config-no-db": "Немагчыма знайсьці адпаведны драйвэр базы зьвестак. Вам неабходна ўсталяваць драйвэр базы зьвестак для PHP.\nПадтрымліваюцца наступныя тыпы базаў зьвестак: $1.\n\nКалі вы скампілявалі PHP самастойна, зьмяніце канфігурацыю, каб уключыць кліента базы зьвестак, напрыклад, з дапамогай <code>./configure --with-mysqli</code>.\nКалі вы ўсталявалі PHP з пакунку Debian або Ubuntu, тады вам трэба таксама ўсталяваць, напрыклад, пакунак <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Папярэджаньне''': усталяваны SQLite $1, у той час, калі мінімальная сумяшчальная вэрсія — $2. SQLite ня будзе даступны.",
        "config-no-fts3": "'''Папярэджаньне''': SQLite створаны без модуля [//sqlite.org/fts3.html FTS3], для гэтага ўнутранага інтэрфэйсу ня будзе даступная магчымасьць пошуку.",
-       "config-register-globals": "'''Папярэджаньне: уключаная опцыя PHP <code>[http://php.net/register_globals register_globals]</code>.'''\n'''Адключыце яе, калі можаце.'''\nMediaWiki будзе працаваць, але гэта панізіць узровень бясьпекі сэрвэра.",
+       "config-register-globals-error": "<strong>Памылка: парамэтар PHP <code>[http://php.net/register_globals register_globals]</code> уключаны.\nЁн павінен быць адключаны, каб працягнуць усталяваньне.</strong>\nГлядзіце [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] дзеля дапамогі, як зрабіць гэта.",
        "config-magic-quotes-runtime": "'''Фатальная памылка: уключаная опцыя PHP [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]!'''\nГэтая опцыя псуе ўводны паток зьвестак непрадказальным чынам.\nПрацяг усталяваньня альбо выкарыстаньне MediaWiki без адключэньня гэтай опцыі немагчымыя.",
        "config-magic-quotes-sybase": "'''Фатальная памылка: рэжым [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] уключаны!'''\nГэты рэжым шкодзіць уваходныя зьвесткі непрадказальным чынам.\nПрацяг усталяваньня альбо выкарыстаньне MediaWiki немагчымыя, пакуль рэжым ня будзе выключаны.",
        "config-mbstring": "'''Фатальная памылка: рэжым [http://www.php.net/manual/en/ref.info.php#mbstring.overload mbstring.func_overload] уключаны!'''\nГэты рэжым выклікае памылкі і можа шкодзіць зьвесткі непрадказальным чынам.\nПрацяг усталяваньня альбо выкарыстаньне MediaWiki немагчымыя, пакуль рэжым ня будзе выключаны.",
@@ -70,6 +69,7 @@
        "config-memory-raised": "Абмежаваньне на даступную для PHP памяць <code>memory_limit</code> было падвышанае з $1 да $2.",
        "config-memory-bad": "'''Папярэджаньне:''' памер PHP <code>memory_limit</code> складае $1.\nВерагодна, гэта вельмі мала.\nУсталяваньне можа быць няўдалым!",
        "config-ctype": "'''Фатальная памылка''': PHP мусіць быць скампіляваны з падтрымкай [http://www.php.net/manual/en/ctype.installation.php пашырэньня Ctype].",
+       "config-iconv": "<strong>Непапраўная памылка:</strong> PHP мусіць быць скампіляваны з падтрымкай [http://www.php.net/manual/en/iconv.installation.php пашырэньня iconv].",
        "config-json": "<strong>Крытычная памылка:</strong> PHP быў скампіляваны без падтрымкі JSON.\nВы павінныя ўсталяваць або пашырэньне PHP JSON, або пашырэньне [http://pecl.php.net/package/jsonc PECL jsonc] перад усталёўкай MediaWiki.\n* Пашырэньне PHP уваходзіць у Red Hat Enterprise Linux (CentOS) 5 і 6, пры гэтым павінна быць падключана ў <code>/etc/php.ini</code> або <code>/etc/php.d/json.ini</code>.\n* Некаторыя дыстрыбутывы Linux, выдадзеныя пасьля траўня 2013 году, ня маюць пашырэньня PHP, замест яго пакуюць пашырэньне PECL як <code>php5-json</code> або <code>php-pecl-jsonc</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] усталяваны",
        "config-apc": "[http://www.php.net/apc APC] усталяваны",
        "config-license-gfdl": "GNU Free Documentation License 1.3 ці болей позьняя",
        "config-license-pd": "Грамадзкі набытак",
        "config-license-cc-choose": "Выберыце іншую ліцэнзію Creative Commons",
-       "config-license-help": "Шматлікія адкрытыя вікі публікуюць увесь унёсак у праект на ўмовах [http://freedomdefined.org/Definition вольнай ліцэнзіі].\nГэта дазваляе ствараць эфэкт супольнай уласнасьці і садзейнічае доўгатэрміноваму ўнёску.\nДля прыватных і карпаратыўных вікі гэта не зьяўляецца неабходнасьцю.\n\nКалі Вы жадаеце выкарыстоўваць тэкст зь Вікіпэдыі, і жадаеце, каб Вікіпэдыя магла прымаць тэксты, скапіяваныя з Вашай вікі, Вам неабходна выбраць ліцэнзію '''Creative Commons Attribution Share Alike'''.\n\nРаней Вікіпэдыя выкарыстоўвала ліцэнзію GNU Free Documentation.\nЯна ўсё яшчэ дзейнічае, але яна ўтрымлівае некаторыя моманты,\nякія ўскладняюць паўторнае выкарыстоўваньне і інтэрпрэтацыю матэрыялаў.",
+       "config-license-help": "Шматлікія адкрытыя вікі публікуюць увесь унёсак у праект на ўмовах [http://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 [http://www.php.net/manual/en/mail.configuration.php адпаведным чынам].\nКалі Вы не жадаеце выкарыстоўваць магчымасьці электроннай пошты, Вы можаце яе адключыць.",
diff --git a/includes/installer/i18n/bto.json b/includes/installer/i18n/bto.json
new file mode 100644 (file)
index 0000000..c1960fb
--- /dev/null
@@ -0,0 +1,17 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Filipinayzd"
+               ]
+       },
+       "config-information": "Impormasyon",
+       "config-page-welcome": "Dagos sa MediaWiki!",
+       "config-page-name": "Ngaran",
+       "config-restart": "Amo, uliton adi",
+       "config-profile-wiki": "Bukas na wiki",
+       "config-profile-private": "Pribadong wiki",
+       "config-logo": "URL ko logo:",
+       "config-cc-again": "Pumili dayday...",
+       "config-install-step-done": "tapus na",
+       "config-help": "tabang"
+}
index 8d678e0..3fa9b92 100644 (file)
@@ -4,7 +4,8 @@
                        "Pitort",
                        "පසිඳු කාවින්ද",
                        "Kippelboy",
-                       "Toniher"
+                       "Toniher",
+                       "Fitoschido"
                ]
        },
        "config-desc": "L'instal·lador del MediaWiki",
@@ -45,7 +46,6 @@
        "config-env-good": "S'ha comprovat l'entorn.\nPodeu instal·lar el MediaWiki.",
        "config-env-bad": "S'ha comprovat l'entorn.\nNo podeu instal·lar el MediaWiki.",
        "config-env-php": "El PHP $1 està instal·lat.",
-       "config-env-php-toolow": "El PHP $1 està instal·lat.\nMalauradament, el MediaWiki necessita el PHP $2 o superior.",
        "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-diff3-bad": "No s'ha trobat el GNU diff3.",
@@ -73,6 +73,7 @@
        "config-db-charset": "Joc de caràcters de la base de dades",
        "config-charset-mysql5-binary": "Binari de MySQL 4.1/5.0",
        "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
+       "config-mysql-old": "Cal el MySQL $1 o posterior. Teniu el $2.",
        "config-db-port": "Port de la base de dades:",
        "config-db-schema": "Esquema per a MediaWiki:",
        "config-db-schema-help": "Aquest esquema normalment ja serveix.\nNomés canvieu-lo si sabeu què us feu.",
        "config-type-mysql": "MySQL (o compatible)",
        "config-type-mssql": "Microsoft SQL Server",
        "config-header-mysql": "Paràmetres de MySQL",
+       "config-header-postgres": "Paràmetres del PostgreSQL",
+       "config-header-sqlite": "Paràmetres de l'SQLite",
+       "config-header-oracle": "Paràmetres de l'Oracle",
+       "config-header-mssql": "Paràmetres del Microsoft SQL Server",
        "config-invalid-db-type": "Tipus de base de dades no vàlid",
-       "config-missing-db-name": "Heu d'introduir un valor per al «nom de la base de dades»",
-       "config-missing-db-host": "Heu d'introduir un valor per al «servidor de la base de dades»",
+       "config-missing-db-name": "Heu d'introduir un valor per a «{{int:config-db-name}}».",
+       "config-missing-db-host": "Heu d'introduir un valor per a «{{int:config-db-host}}».",
+       "config-missing-db-server-oracle": "Heu d’introduir un valor per a «{{int:config-db-host-oracle}}».",
+       "config-db-sys-user-exists-oracle": "El compte d’usuari «$1» ja existeix. SYSDBA només es pot fer servir per crear comptes nous.",
        "config-sqlite-readonly": "El fitxer <code>$1</code> no es pot escriure.",
        "config-sqlite-cant-create-db": "No s'ha pogut crear el fitxer de base de dades <code>$1</code>.",
        "config-upgrade-done-no-regenerate": "S'ha completat l'actualització.\n\nJa podeu [$1 començar a utilitzar el wiki].",
        "config-install-mainpage-failed": "No s'ha pogut inserir la pàgina principal: $1",
        "config-download-localsettings": "Baixa <code>LocalSettings.php</code>",
        "config-help": "ajuda",
+       "config-help-tooltip": "feu clic per ampliar",
        "config-nofile": "No s'ha pogut trobar el fitxer «$1». S'ha suprimit?",
        "mainpagetext": "'''El MediaWiki s'ha instal·lat correctament.'''",
        "mainpagedocfooter": "Consulteu la [//meta.wikimedia.org/wiki/Help:Contents Guia d'Usuari] per a més informació sobre com utilitzar-lo.\n\n== Per a començar ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Llista de característiques configurables]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ PMF del MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Llista de correu (''listserv'') per a anuncis del MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traduïu MediaWiki en la vostra llengua]"
index 72b6f73..56b2732 100644 (file)
@@ -12,6 +12,7 @@
        "config-localsettings-key": "Карлаяккхаран догӀа:",
        "config-localsettings-badkey": "Ахьа яздина нийса доцу догӀа",
        "config-your-language": "Хьан мотт:",
+       "config-wiki-language": "Вики чохь лелор болу мотт",
        "config-back": "← Юха",
        "config-continue": "Кхин дӀа →",
        "config-page-language": "Мотт",
index dbfef20..bc274ac 100644 (file)
@@ -52,7 +52,6 @@
        "config-env-good": "Prostředí bylo zkontrolováno.\nMůžete nainstalovat MediaWiki.",
        "config-env-bad": "Prostředí bylo zkontrolováno.\nMediaWiki nelze nainstalovat.",
        "config-env-php": "Je nainstalováno PHP $1.",
-       "config-env-php-toolow": "Je nainstalováno PHP $1.\nMediaWiki ale vyžaduje PHP $2 nebo vyšší.",
        "config-unicode-using-utf8": "Pro normalizaci Unicode se používá utf8_normalize.so Briona Vibbera.",
        "config-unicode-using-intl": "Pro normalizaci Unicode se používá [http://pecl.php.net/intl PECL rozšíření intl].",
        "config-unicode-pure-php-warning": "'''Upozornění''': Není dostupné [http://pecl.php.net/intl PECL rozšíření intl] pro normalizaci Unicode, bude se využívat pomalá implementace v čistém PHP.\nPokud provozujete wiki s velkou návštěvností, měli byste si přečíst něco o [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizaci Unicode].",
@@ -60,7 +59,7 @@
        "config-no-db": "Nepodařilo se nalézt vhodný databázový ovladač! Musíte do PHP nainstalovat databázový ovladač.\nJsou podporovány následující typy databází: $1.\n\nPokud jste si PHP přeložili sami, překonfigurujte ho se zapnutým databázovým klientem, například pomocí <code>./configure --with-mysql</code>.\nPokud jste PHP nainstalovali z balíčku Debian či Ubuntu, potřebujete nainstalovat také modul php5-mysql.",
        "config-outdated-sqlite": "'''Upozornění''': Máte SQLite $1, které je starší než minimálně vyžadovaná verze $2. SQLite nebude dostupné.",
        "config-no-fts3": "'''Upozornění''': SQLite bylo přeloženo bez [//sqlite.org/fts3.html modulu FTS3], funkce pro vyhledávání zde nebudou dostupné.",
-       "config-register-globals": "'''Upozornění: Je zapnuta PHP volba <code>[http://php.net/register_globals register_globals]</code>.'''\n'''Pokud můžete, vypněte ji.'''\nMediaWiki bude fungovat, ale váš server je vystaven potenciálním bezpečnostním hrozbám.",
+       "config-register-globals-error": "<strong>Chyba: PHP nastavení <code>[http://php.net/register_globals register_globals]</code> je zapnuto. Pro pokračování v instalaci musí být vypnuto.</strong>\nRady, jak toho dosáhnout, najdete na [https://www.mediawiki.org/wiki/Register_globals https://www.mediawiki.org/wiki/register_globals].",
        "config-magic-quotes-runtime": "'''Kritická chyba: Je zapnuto [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]!'''\nToto nastavení nepředvídatelně poškozuje vstupní data.\nMediaWiki nelze nainstalovat ani používat, dokud není toto nastavení vypnuto.",
        "config-magic-quotes-sybase": "'''Kritická chyba: Je zapnuto [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]!'''\nToto nastavení nepředvídatelně poškozuje vstupní data.\nMediaWiki nelze nainstalovat ani používat, dokud není toto nastavení vypnuto.",
        "config-mbstring": "'''Kritická chyba: Je zapnuto [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]!'''\nToto nastavení způsobuje chyby a může nepředvídatelně poškozovat vstupní data.\nMediaWiki nelze nainstalovat ani používat, dokud není toto nastavení vypnuto.",
@@ -71,6 +70,7 @@
        "config-memory-raised": "<code>memory_limit</code> v PHP byl nastaven na $1, zvýšen na $2.",
        "config-memory-bad": "'''Upozornění:''' <code>memory_limit</code> je v PHP nastaven na $1.\nTo je pravděpodobně příliš málo.\nInstalace může selhat!",
        "config-ctype": "'''Kritická chyba''': PHP musí být přeloženo s podporou pro [http://www.php.net/manual/en/ctype.installation.php rozšíření Ctype].",
+       "config-iconv": "'''Kritická chyba''': PHP musí být přeloženo s podporou pro [http://www.php.net/manual/en/iconv.installation.php rozšíření iconv].",
        "config-json": "'''Kritická chyba:''' PHP bylo přeloženo bez podpory JSON.\nPřed instalací MediaWiki musíte buď nainstalovat rozšíření PHP JSON nebo rozšíření [http://pecl.php.net/package/jsonc PECL jsonc].\n* Rozšíření PHP je součástí Red Hat Enterprise Linux (CentOS) 5 a 6, avšak musí se povolit v <code>/etc/php.ini</code> nebo <code>/etc/php.d/json.ini</code>.\n* V některých linuxových distribucích vydaných po květnu 2013 může toto rozšíření PHP chybět a místo toho mohou používat rozšíření PECL jako <code>php5-json</code> nebo <code>php-pecl-jsonc</code>.",
        "config-xcache": "Je nainstalována [http://xcache.lighttpd.net/ XCache]",
        "config-apc": "Je nainstalováno [http://www.php.net/apc APC]",
        "config-license-gfdl": "GNU Free Documentation License 1.3 nebo novější",
        "config-license-pd": "Volné dílo",
        "config-license-cc-choose": "Zvolit vlastní licenci Creative Commons",
-       "config-license-help": "Mnoho veřejných wiki všechny příspěvky zveřejňuje pod některou [http://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 '''Creative Commons Uveďte autora-Zachovejte licenci'''.\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-license-help": "Mnoho veřejných wiki všechny příspěvky zveřejňuje pod některou [http://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 [http://www.php.net/manual/en/mail.configuration.php e-mailová nastavení PHP].\nPokud nechcete žádné e-mailové funkce, můžete je zde vypnout.",
        "config-memcache-badport": "Čísla portů pro Memcached by měla být mezi $1 a $2.",
        "config-extensions": "Rozšíření",
        "config-extensions-help": "Výše uvedená rozšíření byla nalezena ve vašem adresáři <code>./extensions</code>.\n\nMohou vyžadovat dodatečnou konfiguraci, ale teď je můžete povolit.",
+       "config-skins": "Vzhledy",
+       "config-skins-help": "Ve vašem adresáři <code>./skins</code> byly nalezeny výše uvedené vzhledy. Musíte nejméně jeden z nich povolit a některý vybrat jako výchozí.",
+       "config-skins-use-as-default": "Tento vzhled používat jako výchozí",
+       "config-skins-missing": "Nebyly nalezeny žádné vzhledy; MediaWiki bude používat nouzový vzhled, dokud nenainstalujete nějaké plnohodnotné.",
+       "config-skins-must-enable-some": "Musíte povolit alespoň jeden vzhled.",
+       "config-skins-must-enable-default": "Vzhled vybraný jako výchozí musí být povolen.",
        "config-install-alreadydone": "'''Upozornění:''' Vypadá to, že jste MediaWiki již nainstalovali a teď se o to pokoušíte znovu.\nPokračujte na další stránku.",
        "config-install-begin": "Stisknutím „{{int:config-continue}}“ spustíte instalaci MediaWiki.\nPokud ještě chcete udělat nějaké změny, stiskněte „{{int:config-back}}“.",
        "config-install-step-done": "hotovo",
index cd18c92..93da07d 100644 (file)
@@ -58,7 +58,6 @@
        "config-env-good": "Die Installationsumgebung wurde geprüft.\nMediaWiki kann installiert werden.",
        "config-env-bad": "Die Installationsumgebung wurde geprüft.\nMediaWiki kann nicht installiert werden.",
        "config-env-php": "Die Skriptsprache „PHP“ ($1) ist installiert.",
-       "config-env-php-toolow": "PHP $1 ist installiert.\nAllerdings benötigt MediaWiki PHP $2 oder höher.",
        "config-unicode-using-utf8": "Zur Unicode-Normalisierung wird Brion Vibbers <code>utf8_normalize.so</code> eingesetzt.",
        "config-unicode-using-intl": "Zur  Unicode-Normalisierung wird die [http://pecl.php.net/intl PECL-Erweiterung intl] eingesetzt.",
        "config-unicode-pure-php-warning": "'''Warnung:''' Die [http://pecl.php.net/intl PECL-Erweiterung intl] ist für die Unicode-Normalisierung nicht verfügbar, so dass stattdessen die langsame pure-PHP-Implementierung genutzt wird.\nSofern eine Website mit großer Benutzeranzahl betrieben wird, sollten weitere Informationen auf der Webseite [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-Normalisierung (en)] gelesen werden.",
@@ -66,7 +65,7 @@
        "config-no-db": "Es konnte kein adäquater Datenbanktreiber gefunden werden. Es muss daher ein Datenbanktreiber für PHP installiert werden.\nDie folgenden Datenbanksysteme werden unterstützt: $1\n\nWenn du PHP selbst kompiliert hast, konfiguriere es erneut mit einem aktivierten Datenbankclient, zum Beispiel durch Verwendung von <code>./configure --with-mysqli</code>.\nWenn du PHP von einem Debian- oder Ubuntu-Paket installiert hast, dann musst du auch beispielsweise das <code>php5-mysql</code>-Paket installieren.",
        "config-outdated-sqlite": "'''Warnung:''' SQLite $1 ist installiert. Allerdings benötigt MediaWiki SQLite $2 oder höher. SQLite wird daher nicht verfügbar sein.",
        "config-no-fts3": "'''Warnung:''' SQLite wurde ohne das [//sqlite.org/fts3.html FTS3-Modul] kompiliert, sodass keine Suchfunktionen für dieses Datenbanksystem zur Verfügung stehen werden.",
-       "config-register-globals": "'''Warnung: Der Parameter <code>[http://php.net/register_globals register_globals]</code> von PHP ist aktiviert.'''\n'''Sie sollte deaktiviert werden, sofern dies möglich ist.'''\nDie MediaWiki-Installation wird zwar laufen, wobei aber der Server für potentielle Sicherheitsprobleme anfällig ist.",
+       "config-register-globals-error": "<strong>Fehler: Die PHP-Option <code>[http://php.net/register_globals register_globals]</code> ist aktiviert.\nSie muss deaktiviert sein, um mit der Installation fortzufahren.</strong>\nSiehe [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] für Hilfe.",
        "config-magic-quotes-runtime": "'''Fataler Fehler: Der Parameter <code>[http://www.php.net/manual/de/function.set-magic-quotes-runtime.php set_magic_quotes_runtime]</code> von PHP ist aktiviert!'''\nDiese Einstellung führt zu unvorhersehbaren Problemen bei der Dateneingabe.\nMediaWiki kann nicht installiert werden, solange dieser Parameter nicht deaktiviert wurde.",
        "config-magic-quotes-sybase": "<strong>Fataler Fehler: Der Parameter <code>[http://www.php.net/manual/de/sybase.configuration.php#ini.magic-quotes-sybase magic_quotes_sybase]</code> von PHP ist aktiviert!</strong>\nDiese Einstellung führt zu unvorhersehbaren Problemen bei der Dateneingabe.\nMediaWiki kann nicht installiert werden, solange dieser Parameter nicht deaktiviert wurde.",
        "config-mbstring": "'''Fataler Fehler: Der Parameter <code>[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]</code> von PHP ist aktiviert!'''\nDiese Einstellung verursacht Fehler und führt zu unvorhersehbaren Problemen bei der Dateneingabe.\nMediaWiki kann nicht installiert werden, solange dieser Parameter nicht deaktiviert wurde.",
@@ -77,6 +76,7 @@
        "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-ctype": "'''Fataler Fehler:''' PHP muss mit Unterstützung für das [http://www.php.net/manual/de/ctype.installation.php Modul ctype] kompiliert werden.",
+       "config-iconv": "<strong>Fatal:</strong> PHP muss mit Support für die [http://www.php.net/manual/en/iconv.installation.php iconv-Erweiterung] kompiliert werden.",
        "config-json": "<strong>Fataler Fehler:</strong> PHP wurde ohne Unterstützung für JSON kompiliert.\nVor der Installation von MediaWiki muss entweder die PHP-JSON- oder die [http://pecl.php.net/package/jsonc PECL-jsonc]-Erweiterung installieren werden.\n* Die PHP-Erweiterung ist in Red Hat Enterprise Linux (CentOS) 5 und 6 enthalten, muss jedoch in <code>/etc/php.ini</code> oder <code>/etc/php.d/json.ini</code> aktiviert werden.\n* Einige Linux-Distributionen, die nach Mai 2013 veröffentlicht wurden, nutzen nicht mehr die PHP-Erweiterung, sondern stattdessen die PECL-Erweiterung als <code>php5-json</code> oder <code>php-pecl-jsonc</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] ist installiert",
        "config-apc": "[http://www.php.net/apc APC] ist installiert",
        "config-license-gfdl": "GNU-Lizenz für freie Dokumentation 1.3 oder höher",
        "config-license-pd": "Gemeinfreiheit",
        "config-license-cc-choose": "Eine benutzerdefinierte Creative-Commons-Lizenz auswählen",
-       "config-license-help": "Viele öffentliche Wikis publizieren alle Beiträge unter einer [http://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 ''Creative-Commons''-Lizenz „Namensnennung – Weitergabe unter gleichen Bedingungen“ 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-license-help": "Viele öffentliche Wikis publizieren alle Beiträge unter einer [http://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 [http://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-memcache-badport": "Der Ports für den Memcached Cacheserver sollten zwischen $1 und $2 liegen",
        "config-extensions": "Erweiterungen",
        "config-extensions-help": "Die obig angegebenen Erweiterungen wurden im Verzeichnis <code>./extensions</code> gefunden.\n\nEs könnten zusätzliche Konfigurierungen zu einzelnen Erweiterungen erforderlich sein, dennoch können sie aber bereits jetzt aktiviert werden.",
+       "config-skins": "Benutzeroberflächen",
+       "config-skins-help": "Die oben aufgeführten Benutzeroberflächen wurden im Verzeichnis <code>./skins</code> gefunden. Du musst mindestens eine aktivieren und als Standard auswählen.",
+       "config-skins-use-as-default": "Diese Benutzeroberfläche als Standard verwenden",
+       "config-skins-missing": "Es wurden keine Benutzeroberflächen gefunden. MediaWiki wird eine Fallback-Benutzeroberfläche verwenden, bis du andere Benutzeroberflächen installierst.",
+       "config-skins-must-enable-some": "Du musst mindestens eine zu aktivierende Benutzeroberfläche auswählen.",
+       "config-skins-must-enable-default": "Die ausgewählte Standard-Benutzeroberfläche muss aktiviert sein.",
        "config-install-alreadydone": "'''Warnung:''' Es wurde eine vorhandene MediaWiki-Installation gefunden.\nEs muss daher mit den nächsten Seite weitergemacht werden.",
        "config-install-begin": "Durch Drücken von „{{int:config-continue}}“ wird die Installation von MediaWiki gestartet.\nSofern Änderungen vorgenommen werden sollen, kann man auf „{{int:config-back}}“ klicken.",
        "config-install-step-done": "erledigt",
index b19bdc0..da8117b 100644 (file)
@@ -44,7 +44,6 @@
        "config-env-good": "The environment has been checked.\nYou can install MediaWiki.",
        "config-env-bad": "The environment has been checked.\nYou cannot install MediaWiki.",
        "config-env-php": "PHP $1 is installed.",
-       "config-env-php-toolow": "PHP $1 is installed.\nHowever, MediaWiki requires PHP $2 or higher.",
        "config-unicode-using-utf8": "Using Brion Vibber's utf8_normalize.so for Unicode normalization.",
        "config-unicode-using-intl": "Using the [http://pecl.php.net/intl intl PECL extension] for Unicode normalization.",
        "config-unicode-pure-php-warning": "<strong>Warning:</strong> The [http://pecl.php.net/intl intl PECL extension] is not available to handle Unicode normalization, falling back to slow pure-PHP implementation.\nIf you run a high-traffic site, you should read a little on [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization].",
@@ -52,7 +51,7 @@
        "config-no-db": "Could not find a suitable database driver! You need to install a database driver for PHP.\nThe following database types are supported: $1.\n\nIf you compiled PHP yourself, reconfigure it with a database client enabled, for example, using <code>./configure --with-mysqli</code>.\nIf you installed PHP from a Debian or Ubuntu package, then you also need to install, for example, the <code>php5-mysql</code> package.",
        "config-outdated-sqlite": "<strong>Warning:</strong> you have SQLite $1, which is lower than minimum required version $2. SQLite will be unavailable.",
        "config-no-fts3": "<strong>Warning:</strong> SQLite is compiled without the [//sqlite.org/fts3.html FTS3 module], search features will be unavailable on this backend.",
-       "config-register-globals": "<strong>Warning: PHP's <code>[http://php.net/register_globals register_globals]</code> option is enabled.\nDisable it if you can.</strong>\nMediaWiki will work, but your server is exposed to potential security vulnerabilities.",
+       "config-register-globals-error": "<strong>Error: PHP's <code>[http://php.net/register_globals register_globals]</code> option is enabled.\nIt must be disabled to continue with the installation.</strong>\nSee [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] for help on how to do so.",
        "config-magic-quotes-runtime": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] is active!'</strong>\nThis option corrupts data input unpredictably.\nYou cannot install or use MediaWiki unless this option is disabled.",
        "config-magic-quotes-sybase": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] is active!</strong>\nThis option corrupts data input unpredictably.\nYou cannot install or use MediaWiki unless this option is disabled.",
        "config-mbstring": "<strong>Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] is active!</strong>\nThis option causes errors and may corrupt data unpredictably.\nYou cannot install or use MediaWiki unless this option is disabled.",
@@ -63,6 +62,7 @@
        "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-ctype": "<strong>Fatal:</strong> PHP must be compiled with support for the [http://www.php.net/manual/en/ctype.installation.php Ctype extension].",
+       "config-iconv": "<strong>Fatal:</strong> PHP must be compiled with support for the [http://www.php.net/manual/en/iconv.installation.php iconv extension].",
        "config-json": "<strong>Fatal:</strong> PHP was compiled without JSON support.\nYou must install either the PHP JSON extension or the [http://pecl.php.net/package/jsonc PECL jsonc] extension before installing MediaWiki.\n* The PHP extension is included in Red Hat Enterprise Linux (CentOS) 5 and 6, though must be enabled in <code>/etc/php.ini</code> or <code>/etc/php.d/json.ini</code>.\n* Some Linux distributions released after May 2013 omit the PHP extension, instead packaging the PECL extension as <code>php5-json</code> or <code>php-pecl-jsonc</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] is installed",
        "config-apc": "[http://www.php.net/apc APC] is installed",
        "config-license-gfdl": "GNU Free Documentation License 1.3 or later",
        "config-license-pd": "Public Domain",
        "config-license-cc-choose": "Select a custom Creative Commons license",
-       "config-license-help": "Many public wikis put all contributions under a [http://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>Creative Commons Attribution Share Alike</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-license-help": "Many public wikis put all contributions under a [http://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, [http://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-memcache-badport": "Memcached port numbers should be between $1 and $2.",
        "config-extensions": "Extensions",
        "config-extensions-help": "The extensions listed above were detected in your <code>./extensions</code> directory.\n\nThey may require additional configuration, but you can enable them now.",
+       "config-skins": "Skins",
+       "config-skins-help": "The skins listed above were detected in your <code>./skins</code> directory. You must enable at least one, and choose the default.",
+       "config-skins-use-as-default": "Use this skin as default",
+       "config-skins-missing": "No skins were found; MediaWiki will use a fallback skin until you install some proper ones.",
+       "config-skins-must-enable-some": "You must choose at least one skin to enable.",
+       "config-skins-must-enable-default": "The skin chosen as default must be enabled.",
        "config-install-alreadydone": "<strong>Warning:</strong> You seem to have already installed MediaWiki and are trying to install it again.\nPlease proceed to the next page.",
        "config-install-begin": "By pressing \"{{int:config-continue}}\", you will begin the installation of MediaWiki.\nIf you still want to make changes, press \"{{int:config-back}}\".",
        "config-install-step-done": "done",
index 71da7f2..250816a 100644 (file)
        "config-env-good": "La medio estis kontrolita.\nVi povas instali MediaWiki.",
        "config-env-bad": "La medio estis kontrolita.\nNe eblas instali MediaWiki.",
        "config-env-php": "PHP $1 estas instalita.",
-       "config-env-php-toolow": "PHP $1 estas instalita.\nTamen, MediaWiki bezonas PHP $2 aŭ pli novan.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] estas instalita.",
        "config-apc": "[http://www.php.net/apc APC] estas instalita",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] estas instalita",
        "config-diff3-bad": "GNU diff3 ne estis trovita.",
        "config-db-type": "Tipo de datumbazo:",
+       "config-db-wiki-settings": "Identigu ĉi tiun vikion",
+       "config-db-name": "Nomo de datumbazo:",
        "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
        "config-type-mysql": "MySQL (aŭ kongrua)",
+       "config-admin-password": "Pasvorto:",
+       "config-admin-password-confirm": "Retajpu pasvorton:",
+       "config-admin-name-blank": "Enigu salutnomon de administranto.",
+       "config-admin-email": "Retpoŝtadreso:",
        "mainpagetext": "'''MediaWiki estis sukcese instalita.'''",
        "mainpagedocfooter": "Konsultu la [//meta.wikimedia.org/wiki/MediaWiki_User%27s_Guide Gvidilon por uzantoj de MediaWiki] por informoj pri uzado de vikia programaro.\n\n==Kiel komenci==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Listo de konfiguraĵoj] (angle)\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki Oftaj Demandoj] (angle)\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Anonco-dissendolisto pri MediaWiki] (angle)\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Preklad MediaWiki do tvojho jazyka]"
 }
index b37a1b7..b651b40 100644 (file)
@@ -22,7 +22,8 @@
                        "Ihojose",
                        "Seb35",
                        "McDutchie",
-                       "Miguel2706"
+                       "Miguel2706",
+                       "Macofe"
                ]
        },
        "config-desc": "El instalador de MediaWiki",
@@ -67,7 +68,6 @@
        "config-env-good": "El entorno ha sido comprobado.\nPuedes instalar MediaWiki.",
        "config-env-bad": "El entorno ha sido comprobado.\nNo puedes instalar MediaWiki.",
        "config-env-php": "PHP $1 está instalado.",
-       "config-env-php-toolow": "PHP $1 está instalado.\nSin embargo, MediaWiki requiere PHP $2 o superior.",
        "config-unicode-using-utf8": "Usando utf8_normalize.so de Brion Vibber para la normalización Unicode.",
        "config-unicode-using-intl": "Usando la [http://pecl.php.net/intl extensión intl PECL] para la normalización Unicode.",
        "config-unicode-pure-php-warning": "'''Advertencia''': La [http://pecl.php.net/intl extensión intl] no está disponible para efectuar la normalización Unicode. Utilizando la implementación más lenta en PHP.\nSi tu web tiene mucho tráfico, te recomendamos leer acerca de la [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalización Unicode].",
@@ -75,7 +75,6 @@
        "config-no-db": "¡No fue posible encontrar un controlador adecuado para la base de datos! Necesitas instalar un controlador de base de datos para PHP.\nLos siguientes sistemas gestores de bases de datos están soportados: $1.\n\nSi compilaste PHP tú mismo, debes reconfigurarlo habilitando un cliente de base de datos, por ejemplo, usando <code>./configure --with-mysqli</code>.\nSi instalaste PHP desde un paquete Debian o Ubuntu, entonces también necesitas instalar, por ejemplo, el paquete <code>php5-mysql</code>.",
        "config-outdated-sqlite": "''' Advertencia ''': tiene la versión SQLite $1, que es inferior a la mínima versión requerida: $2 . SQLite no estará disponible.",
        "config-no-fts3": "'''Advertencia''': SQLite está compilado sin el [//sqlite.org/fts3.html módulo FTS3]. Las funcionalidades de búsqueda no estarán disponibles en esta instalación.",
-       "config-register-globals": "'''Advertencia: La opción de <code>[http://php.net/register_globals register_globals]</code> de PHP está habilitada.'''\n'''Desactívela si puede.'''\nMediaWiki funcionará, pero tu servidor quedará expuesto a vulnerabilidades de seguridad potenciales.",
        "config-magic-quotes-runtime": "'''Fatal: ¡[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] está activada!'''\nEsta opción causa la imprevisible corrupción de la entrada de datos.\nNo puedes instalar o utilizar MediaWiki a menos que esta opción esté inhabilitada.",
        "config-magic-quotes-sybase": "'''Fatal: ¡[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está activada!'''\nEsta opción causa la imprevisible corrupción de la entrada de datos.\nNo puedes instalar o utilizar MediaWiki a menos que esta opción esté inhabilitada.",
        "config-mbstring": "'''Fatal: La opción [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está activada!'''\nEsta opción causa errores y puede corromper los datos de una forma imprevisible.\nNo se puede instalar o usar MediaWiki a menos que esta opción sea desactivada.",
        "config-license-gfdl": "Licencia de documentación libre de GNU 1.3 o posterior",
        "config-license-pd": "Dominio Público",
        "config-license-cc-choose": "Selecciona una licencia personalizada de Creative Commons",
-       "config-license-help": "Muchos wikis públicos ponen todas las contribuciones bajo una [http://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 desea poder utilizar texto de Wikipedia, y desea que Wikipedia pueda aceptar el texto copiado de tu wiki, debe elegir '''Creative Commons Reconocimiento Compartir Igual'''.\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-license-help": "Muchos wikis públicos ponen todas las contribuciones bajo una [http://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 [http://www.php.net/manual/en/mail.configuration.php configuración PHP de correo electrónico] debe ser la correcta.\nSi no quieres la funcionalidad de correo electrónico, puedes desactivarla aquí.",
        "config-nofile": "El archivo \"$1\" no se pudo encontrar. ¿Se ha eliminado?",
        "config-extension-link": "¿Sabías que tu wiki admite [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensiones]?\n\nPuedes navegar por las [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category categorías] o visitar el [//www.mediawiki.org/wiki/Extension_Matrix centro de extensiones] para ver una lista completa.",
        "mainpagetext": "'''MediaWiki ha sido instalado con éxito.'''",
-       "mainpagedocfooter": "Consulta la [//meta.wikimedia.org/wiki/Help:Contents/es Guía del usuario] para obtener información sobre el uso del software wiki.\n\n== Empezando ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista de ajustes de configuración]\n* [//www.mediawiki.org/wiki/Manual:FAQ/es FAQ de MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de correo de anuncios de distribución de MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Regionalizar MediaWiki para tu idioma]"
+       "mainpagedocfooter": "Consulta la [//meta.wikimedia.org/wiki/Help:Contents/es guía del usuario] para obtener información sobre el uso del software wiki.\n\n== Primeros pasos ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista de ajustes de configuración]\n* [//www.mediawiki.org/wiki/Manual:FAQ/es Preguntas frecuentes sobre MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de correo de anuncios de publicación de MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traducir MediaWiki en tu idioma]"
 }
index 23fe457..ccebf08 100644 (file)
@@ -51,7 +51,6 @@
        "config-env-good": "محیط بررسی شده‌است.\nشما می‌توانید مدیاویکی را نصب کنید.",
        "config-env-bad": "محیط بررسی شده‌است.\nشما نمی‌توانید مدیاویکی را نصب کنید.",
        "config-env-php": "پی‌اچ‌پی $1 نصب شده‌است.",
-       "config-env-php-toolow": "پی‌اچ‌پی $1 نصب شده است.\nدر هر صورت، مدیاویکی نیاز به پی‌اچ‌پی نسخهٔ $2 یا بالاتر دارد.",
        "config-unicode-using-utf8": "برای یونیکد عادی از Brion Vibber's utf8_normalize.so استفاده کنید.",
        "config-unicode-using-intl": "برای یونیکد عادی از [http://pecl.php.net/intl intl PECL extension] استفاده کنید.",
        "config-unicode-pure-php-warning": "'''هشدار:''' [http://pecl.php.net/intl intl PECL extension] برای کنترل یونیکد عادی در دسترس نیست،اجرای کاملاً آهسته به تعویق می‌افتد.\nاگر شما یک سایت پر‌ ترافیک را اجرا می‌کنید، باید کمی [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization] را بخوانید.",
@@ -59,7 +58,7 @@
        "config-no-db": "درایور پایگاه اطلاعاتی مناسب پیدا نشد! شما لازم دارید یک درایور پایگاه اطلاعاتی  برای پی‌اچ‌پی نصب کنید.انواع پایگاه اطلاعاتی زیر پشتیبانی شده‌اند:$1.\nاگر شما در گروه اشتراک‌گذاری هستید، از تهیه کنندهٔ گروه خود برای نصب یک درایور پایگاه اطلاعاتی مناسب سوأل کنید.\nاگر خود، پی‌اچ‌پی را تهیه کرده‌اید، با یک پردازشگر فعال دوباره پیکربندی کنید، برای مثال از <code>./configure --with-mysql</code> استفاده کنید.\nاگر پی‌اچ‌پی را از یک بستهٔ دبیان یا آبونتو نصب کرده‌اید، بنابراین لازم دارید بخش php5-mysql را نصب کنید.",
        "config-outdated-sqlite": "''' هشدار:''' شما اس‌کیولایت $1 دارید، که پایین‌تر از حداقل نسخهٔ $2 مورد نیاز است.اس‌کیولایت در دسترس نخواهد بود.",
        "config-no-fts3": "'''هشدار:''' اس‌کیولایت بدون [//sqlite.org/fts3.html FTS3 module] تهیه شده‌است ، جستجوی ویژگی‌ها در این بخش پیشین در دسترس نخواهد‌بود.",
-       "config-register-globals": "'''هشدار:''' گزینهٔ  PHP's <code>[http://php.net/register_globals register_globals]</code> فعال شده‌است.'''\n''' اگر می‌توانید غیر فعالش کنید.'''\nمدیاویکی کار خواهد‌کرد، اما سرور شما در معرض آسیب‌پذیری‌های امنیتی ممکن قرار دارد.",
+       "config-register-globals-error": "<strong>خطا:  پی‌اچ‌پی<code>[http://php.net/register_globals register_globals]</code> گزینه فعال است.\nبرای ادامه نصب باید غیر فعال باشد.</strong>\n[Https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] را برای کمک در مورد نحوه انجام این کار ببینید.",
        "config-magic-quotes-runtime": "'''مخرب: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] فعال است.\nاین گزینه اطلاعات داده شده به رایانه را به طور غیر‌قابل پیش‌بینی از بین می‌برد.\nشما نمی‌توانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیر‌فعال باشد.",
        "config-magic-quotes-sybase": "'''مخرب: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] فعال است.\nاین گزینه اطلاعات داده شده به رایانه را به طور غیر‌قابل پیش‌بینی از بین می‌برد.\nشما نمی‌توانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیر‌فعال باشد.",
        "config-mbstring": "''' مخرب:[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] فعال است.\nاین گزینه باعث ایجاد خطا می‌شود و ممکن است اطلاعات را به طور غیر‌قابل پیش‌بینی از بین ببرد.\nشما نمی‌توانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیر‌فعال باشد.",
index 3aa0e84..0835f41 100644 (file)
@@ -56,7 +56,6 @@
        "config-env-good": "Asennusympäristö on tarkastettu.\nVoit asentaa MediaWikin.",
        "config-env-bad": "Asennusympäristö on tarkastettu.\nEt voi asentaa MediaWikiä.",
        "config-env-php": "PHP $1 on asennettu.",
-       "config-env-php-toolow": "PHP $1 on asennettu.\nMediaWiki vaatii PHP:n version $2 tai uudemman.",
        "config-no-db": "Sopivaa tietokanta-ajuria ei löytynyt! Sinun täytyy asentaa tietokanta-ajurit PHP:lle.\nSeuraavat tietokantatyypit ovat tuettuja: $1.",
        "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-safe-mode": "'''Varoitus:''' PHP:n [http://www.php.net/features.safe-mode safe mode] -tila on aktiivinen.\nSe voi aiheuttaa ongelmia erityisesti tiedostojen tallentamisen ja matemaattisten kaavojen kanssa.",
        "config-cc-again": "Valitse uudelleen...",
        "config-extensions": "Laajennukset",
        "config-extensions-help": "Yllä luetellut laajennukset löytyvät <code>./extensions</code> hakemistosta.\n\nNe saattavat vaatia lisäasetuksia, mutta voit ottaa ne käyttöön nyt.",
+       "config-skins": "Ulkoasut",
+       "config-skins-must-enable-some": "Sinut täytyy valita ainakin yksi ulkoasu.",
        "config-install-alreadydone": "<strong>Varoitus:</strong> MediaWiki on jo asennettu ja yrität asentaa sitä uudestaan.\nSiirry seuraavalle sivulle.",
        "config-install-begin": "Painamalla \"{{int:config-continue}}\", aloitetaan MediaWikin asentaminen. \nJos haluat vielä tehdä muutoksia, paina \"{{int:config-back}}\".",
        "config-install-step-done": "valmis",
index d9ef1ef..cdb6c99 100644 (file)
@@ -66,7 +66,6 @@
        "config-env-good": "L’environnement a été vérifié.\nVous pouvez installer MediaWiki.",
        "config-env-bad": "L’environnement a été vérifié.\nVous ne pouvez pas installer MediaWiki.",
        "config-env-php": "PHP $1 est installé.",
-       "config-env-php-toolow": "PHP $1 est installé.\nCependant, MediaWiki requiert PHP $2 ou supérieur.",
        "config-unicode-using-utf8": "Utilisation de utf8_normalize.so par Brion Vibber pour la normalisation Unicode.",
        "config-unicode-using-intl": "Utilisation de [http://pecl.php.net/intl l'extension PECL intl] pour la normalisation Unicode.",
        "config-unicode-pure-php-warning": "<strong>Attention</strong> : L'[http://pecl.php.net/intl extension PECL intl] n'est pas disponible pour la normalisation d’Unicode, retour à la version lente implémentée en PHP.\nSi votre site web sera très fréquenté, vous devriez lire ceci : [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations ''Unicode normalization''] (en anglais).",
@@ -74,7 +73,7 @@
        "config-no-db": "Impossible de trouver un pilote de base de données approprié ! Vous devez installer un pilote de base de données pour PHP. Les types de bases de données suivants sont reconnus : $1.\n\nSi vous avez compilé PHP vous-même, reconfigurez-le avec un client de base de données activé, par exemple en utilisant <code>./configure --with-mysqli</code>. Si vous avez installé PHP depuis un paquet Debian ou Ubuntu, alors vous devrez aussi installer, par exemple, le paquet <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Attention''': vous avez SQLite $1, qui est inférieur à la version minimale requise $2. SQLite sera indisponible.",
        "config-no-fts3": "'''Attention :''' SQLite est compilé sans le module [//sqlite.org/fts3.html FTS3] ; les fonctions de recherche ne seront pas disponibles sur ce moteur.",
-       "config-register-globals": "'''Attention : l'option <code>[http://php.net/register_globals register_globals]</code> de PHP est activée.'''\n'''Désactivez-la si vous le pouvez.'''\nMediaWiki fonctionnera, mais votre serveur sera exposé à de potentielles failles de sécurité.",
+       "config-register-globals-error": "<strong>Erreur : L’option <code>[http://php.net/register_globals register_globals]</code> de PHP est activée.\nElle doit être désactivée pour poursuivre l’installation.</strong>\nVoyez [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] pour avoir de l’aide sur la manière de faire cela.",
        "config-magic-quotes-runtime": "'''Erreur fatale : [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] est activé !'''\nCette option corrompt les données de manière imprévisible.\nVous ne pouvez pas installer ou utiliser MediaWiki tant que cette option est activée.",
        "config-magic-quotes-sybase": "'''Erreur fatale : [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybasee] est activé !'''\nCette option corrompt les données de manière imprévisible.\nVous ne pouvez pas installer ou utiliser MediaWiki tant que cette option est activée.",
        "config-mbstring": "'''Erreur fatale : [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] est activé !'''\nCette option provoque des erreurs et peut corrompre les données de manière imprévisible.\nVous ne pouvez pas installer ou utiliser MediaWiki tant que cette option est activée.",
@@ -85,6 +84,7 @@
        "config-memory-raised": "Le paramètre <code>memory_limit</code> de PHP était à $1, porté à $2.",
        "config-memory-bad": "'''Attention :''' 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-ctype": "'''Fatal ''': PHP doit être compilé avec le support pour l'[http://www.php.net/manual/en/ctype.installation.php extension Ctype].",
+       "config-iconv": "<strong>Erreur critique :</strong> PHP doit être compilé avec le support de l’[http://www.php.net/manual/en/iconv.installation.php extension iconv].",
        "config-json": "'''Erreur fatale :''' PHP a été compilé sans le support de JSON.\nVous devez soit installez l’extension JSON de PHP ou l’extension [http://pecl.php.net/package/jsonc PECL jsonc] avant d’installer MediaWiki.\n* L’extension PHP est comprise dans Red Hat Enterprise Linux (CentOS) 5 et 6, mais doit être activée dans <code>/etc/php.ini</code> ou <code>/etc/php.d/json.ini</code>.\n* Certaines distributions Linux après mai 2013 ne comprennent pas l’extension PHP, mais ont mis à la place l’extension PECL sous la forme <code>php5-json</code> ou <code>php-pecl-jsonc</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] est installé",
        "config-apc": "[http://www.php.net/apc APC] est installé",
        "config-license-gfdl": "GNU Free Documentation License 1.3 ou ultérieure",
        "config-license-pd": "Domaine public",
        "config-license-cc-choose": "Sélectionner une licence Creative Commons personnalisée",
-       "config-license-help": "Beaucoup de wikis publics mettent l'ensemble des contributions sous [http://freedomdefined.org/Definition/Fr licence libre].\nCela contribue à créer un sentiment d'appartenance dans leur 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 réutilise des textes de votre wiki, vous devriez choisir la licence ''Creative Commons Attribution Share Alike''].\n\nWikipédia utilisait auparavent la ''GNU Free Documentation License'' (GFDL).\nC'est une licence valide, mais elle est difficile à comprendre. \nDe plus, elle possède des caractéristiques qui rendent difficile la réutilisation.sour GFDL des contenus.",
+       "config-license-help": "Beaucoup de wikis publics mettent l’ensemble des contributions sous une [http://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 [http://www.php.net/manual/en/mail.configuration.php configurer des paramètres PHP] (texte en anglais).\nSi vous ne voulez pas du service de courriel, vous pouvez le désactiver ici.",
        "config-memcache-badport": "Les numéros de port de Memcached sont situés entre $1 et $2.",
        "config-extensions": "Extensions",
        "config-extensions-help": "Les extensions énumérées ci-dessus ont été détectées dans votre répertoire <code>./extensions</code>.\n\nElles peuvent nécessiter une configuration supplémentaire, mais vous pouvez les activer maintenant",
+       "config-skins": "Habillages",
+       "config-skins-help": "Les habillages listés ci-dessous ont été détectés dans votre répertoire <code>./skins</code>. Vous devez en activer au moins un, et choisir celui par défaut.",
+       "config-skins-use-as-default": "Utiliser cet habillage par défaut",
+       "config-skins-missing": "Aucun habillage trouvé ; MédiaWiki utilisera un habillage de secours jusqu’à ce que vous en installiez un approprié.",
+       "config-skins-must-enable-some": "Vous devez choisir au moins un habillage à activer.",
+       "config-skins-must-enable-default": "L’habillage choisi par défaut doit être activé.",
        "config-install-alreadydone": "'''Attention''': Vous semblez avoir déjà installé MediaWiki et tentez de l'installer à nouveau.\nS'il vous plaît, allez à la page suivante.",
        "config-install-begin": "En appuyant sur {{int:config-continue}}, vous commencerez l'installation de MediaWiki.\nSi vous voulez encore apporter des modifications, appuyez sur \"{{int:config-back}}\".",
        "config-install-step-done": "fait",
index 6d5861b..b809a4c 100644 (file)
@@ -49,7 +49,6 @@
        "config-env-good": "Rematou a comprobación da contorna.\nPode instalar MediaWiki.",
        "config-env-bad": "Rematou a comprobación da contorna.\nNon pode instalar MediaWiki.",
        "config-env-php": "Está instalado o PHP $1.",
-       "config-env-php-toolow": "Está instalado o PHP $1.\nPorén, MediaWiki necesita o PHP $2 ou superior.",
        "config-unicode-using-utf8": "Usando utf8_normalize.so de Brion Vibber para a normalización Unicode.",
        "config-unicode-using-intl": "Usando a [http://pecl.php.net/intl extensión intl PECL] para a normalización Unicode.",
        "config-unicode-pure-php-warning": "'''Atención:''' A [http://pecl.php.net/intl extensión intl PECL] non está dispoñible para manexar a normalización Unicode; volvendo á implementación lenta de PHP puro.\nSe o seu sitio posúe un alto tráfico de visitantes, debería ler un chisco sobre a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalización Unicode].",
@@ -57,7 +56,7 @@
        "config-no-db": "Non se puido atopar un controlador axeitado para a base de datos! Necesita instalar un controlador de base de datos para PHP.\nOs tipos de base de datos admitidos son os seguintes: $1.\n\nSe compilou o PHP vostede mesmo, reconfigúreo activando un cliente de base de datos, por exemplo, usando <code>./configure --with-mysql</code>.\nSe instalou o PHP desde un paquete Debian ou Ubuntu, entón tamén necesita instalar, por exemplo, o módulo <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Atención:''' Ten o SQLite $1, que é inferior á versión mínima necesaria: $2. O SQLite non estará dispoñible.",
        "config-no-fts3": "'''Atención:''' O SQLite está compilado sen o [//sqlite.org/fts3.html módulo FTS3]; as características de procura non estarán dispoñibles nesta instalación.",
-       "config-register-globals": "'''Atención: A opción PHP <code>[http://php.net/register_globals register_globals]</code> está activada.'''\n'''Desactívea se pode.'''\nMediaWiki funcionará, pero o seu servidor está exposto a potenciais vulnerabilidades de seguridade.",
+       "config-register-globals-error": "<strong>Erro: A opción <code>[http://php.net/register_globals register_globals]</code> do PHP está activada.\nCómpre desactivala para continuar a instalación.</strong>\nConsulte o enderezo [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] para obter axuda sobre como facelo.",
        "config-magic-quotes-runtime": "'''Erro fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] está activado!'''\nEsta opción corrompe os datos de entrada de xeito imprevisible.\nNon pode instalar ou empregar MediaWiki a menos que esta opción estea desactivada.",
        "config-magic-quotes-sybase": "'''Erro fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está activado!'''\nEsta opción corrompe os datos de entrada de xeito imprevisible.\nNon pode instalar ou empregar MediaWiki a menos que esta opción estea desactivada.",
        "config-mbstring": "'''Erro fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está activado!'''\nEsta opción causa erros e pode corromper os datos de xeito imprevisible.\nNon pode instalar ou empregar MediaWiki a menos que esta opción estea desactivada.",
index a4cb9eb..5a7d148 100644 (file)
@@ -7,8 +7,11 @@
        "config-desc": "Ka polokalamu hoʻonoho no MekiaWiki",
        "config-title": "Ka hoʻonoho MekiaWiki $1",
        "config-information": "ʻIke",
+       "config-localsettings-upgrade": "Ua hōʻike ʻia kekahi waihona <code>LocalSettings.php</code>.\nNo ka hoʻopuka hou ʻana o kēia hoʻonohona, e ʻoluʻolu, e kikokiko i ka helu o <code>$wgUpgradeKey</code> i loko o ka pahu i lalo.\nAia ia ma <code>LocalSettings.php</code>.",
+       "config-localsettings-cli-upgrade": "Ua hōʻike ʻia kekahi waihona <code>LocalSettings.php</code>.\nNo ka hoʻopuka hou ʻana o kēia hoʻonohona, e hana iā <code>update.php</code> ke ʻoluʻolu.",
        "config-localsettings-key": "Pihi hoʻopuka hou:",
        "config-localsettings-badkey": "Hewa ka pihi.",
+       "config-upgrade-key-missing": "Loaʻa he hoʻonohona mai mua o MīkiaWiki mai mua.\nNo ka hoʻopuka hou ʻana o kēia hoʻonohona, e ʻoluʻolu, e kau i kēia laina lalo ma lalo o kāu <code>LocalSettings.php</code>:\n\n$1",
        "config-your-language": "Kāu ʻōlelo:",
        "config-your-language-help": "E koho i kekahi ʻōlelo no ka hoʻohana ʻana ma loko o ka hana hoʻonohona.",
        "config-wiki-language": "ʻŌlelo Wiki:",
index 5d4ba21..e49ee2f 100644 (file)
@@ -51,7 +51,6 @@
        "config-env-good": "הסביבה שלכם נבדקה.\nאפשר להתקין מדיה־ויקי.",
        "config-env-bad": "הסביבה שלכם נבדקה.\nאי־אפשר להתקין מדיה־ויקי.",
        "config-env-php": "מותקנת <span dir=\"ltr\">PHP $1</span>.",
-       "config-env-php-toolow": "מותקנת <span dir=\"ltr\">PHP $1</span>.\nלמדיה־ויקי נדרשת <span dir=\"ltr\">PHP $2</span> או גרסה גבוהה יותר.",
        "config-unicode-using-utf8": "משתמש ב־utf8_normalize.so של בריון ויבר לנרמול יוניקוד.",
        "config-unicode-using-intl": "משתמש ב[http://pecl.php.net/intl הרחבת intl PECL] לנרמול יוניקוד.",
        "config-unicode-pure-php-warning": "'''אזהרה''': [http://pecl.php.net/intl הרחבת intl PECL] אינה זמינה לטיפול בנרמול יוניקוד. משתמש ביישום PHP טהור ואטי יותר.\nאם זהו אתר בעל תעבורה גבוהה, כדאי לקרוא את המסמך הבא: [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization].",
@@ -59,7 +58,7 @@
        "config-no-db": "לא נמצא דרייבר מסד נתונים מתאים. יש להתקין דרייבר מסד נתונים ל־PHP.\nנתמכים הסוגים הבאים של מסדי נתונים: $1.\n\nאם קִמפלת את PHP בעצמך, יש להגדיר אותו מחדש ולהפעיל את לקוח מסד נתונים, למשל באמצעות <code dir=\"ltr\">./configure --with-mysqli</code>.\nאם התקנת את PHP מחבילה של דביאן או של אובונטו, יש להתקין, למשל, גם את המודול <code dir=\"ltr\">php5-mysql</code>.",
        "config-outdated-sqlite": "'''אזהרה''': במערכת מתוקן SQLite $1. גרסה זו לא נתמכת ולשימוש ב־SQLite נדרשת גרסה $2 לפחות. SQLlite לא יהיה זמין.",
        "config-no-fts3": "'''אזהרה''': SQLite מקומפל ללא [//sqlite.org/fts3.html מודול FTS]. יכולות חיפוש לא יהיו זמינות בהתקנה הזאת.",
-       "config-register-globals": "'''אזהרה: האפשרות <code>[http://php.net/register_globals register_globals]</code> של PHP מופעלת.'''\n'''כבו אותה אם זה אפשרי.'''\nמדיה־ויקי תעבוד, אבל השרת שלך חשוף לפגיעות אבטחה.",
+       "config-register-globals-error": "<strong>שגיאה: האפשרות <code>[http://php.net/register_globals register_globals]</code> של PHP מופעלת.\nצריך לכבות אותה כדי להמשיך בהתקנה.</strong>\nר' [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] להסבר איך לעשות את זה.",
        "config-magic-quotes-runtime": "<strong>שגיאה סופנית: האפשרות [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] פעילה!</strong>\nהאפשרות הזאת מעוותת את נתוני הקלט באופן בלתי־צפוי.\nלא ניתן להתקין את מדיה־ויקי אלא אם האפשרות הזאת תכובה.",
        "config-magic-quotes-sybase": "'''שגיאה סופנית''': האפשרות [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] פעילה!'''\nהאפשרות הזאת מעוותת את נתוני הקלט באופן בלתי־צפוי.\nלא ניתן להתקין את מדיה־ויקי או להשתמש בה אלא אם האפשרות הזאת תכובה.",
        "config-mbstring": "'''שגיאה סופנית''': האפשרות [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] פעילה!'''\nהאפשרות הזאת גורמת לשגיאות ומעוותת את נתוני הקלט באופן בלתי־צפוי.\nלא ניתן להתקין את מדיה־ויקי או להשתמש בה אלא אם האפשרות הזאת תכובה.",
@@ -70,6 +69,7 @@
        "config-memory-raised": "ערך האפשרות <code>memory_limit</code> של PHP הוא $1, הועלה ל־$2.",
        "config-memory-bad": "'''אזהרה:''' ערך האפשרות <code>memory_limit</code> של PHP הוא $1.\nזה כנראה נמוך מדי.\nההתקנה עשויה להיכשל!",
        "config-ctype": "<strong>שגיאה סופנית</strong>: נדרשת גרסת PHP שתומכת בהרחבה [http://www.php.net/manual/en/ctype.installation.php Ctype].",
+       "config-iconv": "<strong>סופני:</strong> חובה לקמפל את PHP עם תמיכה ב[הרחבה http://www.php.net/manual/en/iconv.installation.php iconv].",
        "config-json": "'''שגיאה סופנית:''' PHP קומפל ללא תמיכה ב־JSON.\nיש להתקין את ההרחהב JSON ב־PHP או את ההרחבה [http://pecl.php.net/package/jsonc PECL jsonc] לפני התקנת מדיה־ויקי.\n* ההרחבה ל־PHP כלולה ב־Red Hat Enterprise Linux (ו־CentOS), אך יש להפעיל אותה ב־<code dir=\"ltr\">/etc/php.ini</code> או ב־<code dir=\"ltr\">/etc/php.d/json.ini</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] מותקן",
        "config-apc": "[http://www.php.net/apc APC] מותקן",
        "config-license-gfdl": "רישיון חופשי למסמכים של גנו גרסה 1.3 או חדשה יותר",
        "config-license-pd": "נחלת הכלל",
        "config-license-cc-choose": "בחירת רישיון קריאייטיב קומונז מותאם אישית",
-       "config-license-help": "אתרי ויקי ציבוריים רבים מפרסמים את כל התרומות [http://freedomdefined.org/Definition ברישיון חופשי].\nזה עוזר ליצור תחושה של בעלות קהילתית ומעודד תרומה לאורך זמן.\nזה בדרך כלל לא נחוץ לאתר ויקי פרטי או אתר של חברה מסחרית.\n\nאם האפשרות להשתמש בטקסט מוויקיפדיה והאפשרות שוויקיפדיה תוכל תקבל עותקים של טקסטים מהוויקי שלך חשובות לך, כדאי לבחור ב'''רישיון קריאייטיב קומונז ייחוס–שיתוף זהה''' (CC BY-SA).\n\nויקיפדיה השתמשה בעבר ברישיון החופשי למסמכים של גנו (GNU FDL או GFDL).\nהוא עדיין רישיון תקין, אבל קשה להבנה.\nכמו־כן, קשה לעשות שימוש חוזר ביצירות שפורסמו לפי GFDL.",
+       "config-license-help": "אתרי ויקי ציבוריים רבים מפרסמים את כל התרומות [http://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": "אם אתם רוצים שדוא״ל יעבוד, [http://www.php.net/manual/en/mail.configuration.php אפשרויות הדוא״ל של PHP] צריכות להיות מוגדרות נכון.\nאם אינכם רוצים להפעיל שום אפשרויות דוא״ל, כבו אותן כאן ועכשיו.",
        "config-memcache-badport": "מספרי פתחה של Memcached צריכים להיות בין $1 ל־$2",
        "config-extensions": "הרחבות",
        "config-extensions-help": "ההרחבות ברשימה לעיל התגלו בתיקיית <span dir=\"ltr\"><code>./extensions</code></span> שלכם.\n\nייתכן שזה ידרוש הגדרות נוספות, אבל תוכלו להפעיל אותן עכשיו.",
+       "config-skins": "עיצובים",
+       "config-skins-help": "העיצובים לעיל נמצאו בתיקיית ה־<code dir=\"ltr\">./skins</code> שלך. חובה להפעיל לפחות אחת ולבחור בררת מחדל.",
+       "config-skins-use-as-default": "להשתמש בזה בתור בררת מחדל",
+       "config-skins-missing": "לא נמצאו עיצובים; מדיה־ויקי תשתמש בעיצוב גיבוי עד התקנת משהו מתאים.",
+       "config-skins-must-enable-some": "חובה לבחור לפחות עיצוב אחד שיופעל.",
+       "config-skins-must-enable-default": "העיצוב שנבחר בתור בררת מחדל חייב להיות מופעל.",
        "config-install-alreadydone": "'''אזהרה:''' נראה שכבר התקנתם את מדיה־ויקי ואתם מנסים להתקין אותה שוב.\nאנה התקדמו לדף הבא.",
        "config-install-begin": "כשתלחצו על \"{{int:config-continue}}\", תתחילו את ההתקנה של מדיה־ויקי.\nאם אתם עדיין רוצים לשנות משהו, לחצו על \"{{int:config-back}}\".",
        "config-install-step-done": "בוצע",
index 5c0e9db..62afb44 100644 (file)
@@ -47,7 +47,6 @@
        "config-env-good": "Le ambiente ha essite verificate.\nTu pote installar MediaWiki.",
        "config-env-bad": "Le ambiente ha essite verificate.\nTu non pote installar MediaWiki.",
        "config-env-php": "PHP $1 es installate.",
-       "config-env-php-toolow": "PHP $1 es installate.\nNonobstante, MediaWiki require PHP $2 o plus recente.",
        "config-unicode-using-utf8": "utf8_normalize.so per Brion Vibber es usate pro le normalisation Unicode.",
        "config-unicode-using-intl": "Le [http://pecl.php.net/intl extension PECL intl] es usate pro le normalisation Unicode.",
        "config-unicode-pure-php-warning": "'''Aviso''': Le [http://pecl.php.net/intl extension PECL intl] non es disponibile pro exequer le normalisation Unicode; le systema recurre al implementation lente in PHP pur.\nSi tu sito ha un alte volumine de traffico, tu deberea informar te un poco super le [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalisation Unicode].",
@@ -55,7 +54,7 @@
        "config-no-db": "Non poteva trovar un driver appropriate pro le base de datos! Es necessari installar un driver de base de datos pro PHP.\nLe sequente typos de base de datos es supportate: $1.\n\nSi tu compilava PHP tu mesme, reconfigura lo con un cliente de base de datos activate, per exemplo usante <code>./configure --with-mysqli</code>.\nSi tu installava PHP ex un pacchetto Debian o Ubuntu, tu debe installar equalmente, per exemplo, le modulo <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Attention''': tu ha SQLite $1, que es inferior al version minimal requirite, $2. SQLite essera indisponibile.",
        "config-no-fts3": "'''Attention''': SQLite es compilate sin [//sqlite.org/fts3.html modulo FTS3]; functionalitate de recerca non essera disponibile in iste back-end.",
-       "config-register-globals": "'''Attention: le option <code>[http://php.net/register_globals register_globals]</code> de PHP es activate.'''\n'''Disactiva lo si tu pote.'''\nMediaWiki functionara, ma tu servitor es exponite a potential vulnerabilitates de securitate.",
+       "config-register-globals-error": "<strong>Error: Le option <code>[http://php.net/register_globals register_globals]</code> de PHP es active.\nIllo debe esser disactivate pro continuar le installation.</strong>\nVide [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] pro obtener adjuta sur como facer lo.",
        "config-magic-quotes-runtime": "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] es active!'''\nIste option corrumpe le entrata de datos imprevisibilemente.\nTu non pote installar o usar MediaWiki si iste option non es disactivate.",
        "config-magic-quotes-sybase": "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] es active!'''\nIste option corrumpe le entrata de datos imprevisibilemente.\nTu non pote installar o usar MediaWiki si iste option non es disactivate.",
        "config-mbstring": "'''Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] es active!'''\nIste option causa errores e pote corrumper datos imprevisibilemente.\nTu non pote installar o usar MediaWiki si iste option non es disactivate.",
index a37ed89..c2411ef 100644 (file)
@@ -53,7 +53,6 @@
        "config-env-good": "Kondisi telah diperiksa.\nAnda dapat menginstal MediaWiki.",
        "config-env-bad": "Kondisi telah diperiksa.\nAnda tidak dapat menginstal MediaWiki.",
        "config-env-php": "PHP $1 diinstal.",
-       "config-env-php-toolow": "PHP $1 telah terinstal.\nNamun, MediaWiki memerlukan PHP $2 atau lebih tinggi.",
        "config-unicode-using-utf8": "Menggunakan utf8_normalize.so Brion Vibber untuk normalisasi Unicode.",
        "config-unicode-using-intl": "Menggunakan [http://pecl.php.net/intl ekstensi PECL intl] untuk normalisasi Unicode.",
        "config-unicode-pure-php-warning": "'''Peringatan''': [http://pecl.php.net/intl Ekstensi intl PECL] untuk menangani normalisasi Unicode tidak tersedia, kembali menggunakan implementasi murni PHP yang lambat.\nJika Anda menjalankan situs berlalu lintas tinggi, Anda harus sedikit membaca [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalisasi Unicode].",
@@ -61,7 +60,7 @@
        "config-no-db": "Pengandar basis data yang sesuai tidak ditemukan! Anda perlu menginstal pengandar basis data untuk PHP.\nJenis basis data yang didukung: $1.\n\nJika Anda mengompilasi sendiri PHP, ubahlah konfigurasinya dengan mengaktifkan klien basis data, misalnya menggunakan <code>./configure --with-mysql</code>.\nJika Anda menginstal PHP dari paket Debian atau Ubuntu, maka Anda juga perlu menginstal modul php5-mysql.",
        "config-outdated-sqlite": "<strong>Peringatan:</strong> Anda menggunakan SQLite $1, yang lebih rendah dari versi minimum yang diperlukan $2. SQLite akan tidak tersedia.",
        "config-no-fts3": "'''Peringatan''': SQLite dikompilasi tanpa [//sqlite.org/fts3.html modul FTS3], fitur pencarian tidak akan tersedia pada konfigurasi ini.",
-       "config-register-globals": "'''Peringatan: Opsi <code>[http://php.net/register_globals register_globals]</code> PHP diaktifkan.'''\n'''Nonaktifkan kalau bisa.'''\nMediaWiki akan bekerja, tetapi server Anda memiliki potensi kerentanan keamanan.",
+       "config-register-globals-error": "<strong>Kesalahan: Pilihan PHP <code>[http://php.net/register_globals register_globals]</code> diaktifkan.\nIni harus dinonaktifkan untuk melanjutkan instalasi.</strong>\nLihat [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] untuk bantuan tentang cara melakukannya.",
        "config-magic-quotes-runtime": "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] aktif!'''\nPilihan ini dapat merusak masukan data secara tidak terduga.\nAnda tidak dapat menginstal atau menggunakan MediaWiki kecuali pilihan ini dinonaktifkan.",
        "config-magic-quotes-sybase": "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic_quotes_sybase magic_quotes_sybase] aktif!'''\nPilihan ini dapat merusak masukan data secara tidak terduga.\nAnda tidak dapat menginstal atau menggunakan MediaWiki kecuali pilihan ini dinonaktifkan.",
        "config-mbstring": "'''Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] aktif!'' '\nPilihan ini dapat menyebabkan kesalahan dan kerusakan data yang tidak terduga.\nAnda tidak dapat menginstal atau menggunakan MediaWiki kecuali pilihan ini dinonaktifkan.",
@@ -72,6 +71,7 @@
        "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-ctype": "<strong>Fatal:</strong> PHP harus disusun dengan dukungan untuk [http://www.php.net/manual/en/ctype.installation.php ekstensi Ctype].",
+       "config-json": "<strong>Fatal:</strong> PHP dikompilasi tanpa dukungan JSON.\nAnda harus menginstal salah satu pengaya PHP JSON atau pengaya [http://pecl.php.net/package/jsonc PECL jsonc] sebelum menginstal MediaWiki.\n* Pengaya PHP termasuk dalam Red Hat Enterprise Linux (CentOS) 5 dan 6, meskipun harus diaktifkan pada <code>/etc/php.ini</code> atau <code>/etc/php.d/json.ini</code>.\n* Beberapa distribusi Linux dirilis setelah Mei 2013 menghilangkan pengaya PHP, bukan kemasan pengaya PECL sebagai <code>php5-json</code> atau <code>php-pecl-jsonc</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] telah diinstal",
        "config-apc": "[http://www.php.net/apc APC] telah diinstal",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] telah diinstal",
@@ -88,6 +88,7 @@
        "config-using-server": "Menggunakan nama server \"<nowiki>$1</nowiki>\".",
        "config-using-uri": "Menggunakan URL server \"<nowiki>$1$2</nowiki>\".",
        "config-uploads-not-safe": "'''Peringatan:''' Direktori bawaan pengunggahan <code>$1</code> Anda rentan terhadap eksekusi skrip yang sewenang-wenang.\nMeskipun MediaWiki memeriksa semua berkas unggahan untuk ancaman keamanan, sangat dianjurkan untuk [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security menutup kerentanan keamanan ini] sebelum mengaktifkan pengunggahan.",
+       "config-no-cli-uploads-check": "<strong>Peringatan:</strong> Direktori default Anda untuk unggahan (<code>$1</code>) tidak diperiksa untuk kerentanan terhadap\neksekusi script sewenang-wenang selama instalasi CLI.",
        "config-brokenlibxml": "Sistem Anda memiliki kombinasi versi PHP dan libxml2 yang memiliki bug dan dapat menyebabkan kerusakan data tersembunyi pada MediaWiki dan aplikasi web lain.\nMutakhirkan ke PHP 5.2.9 atau yang lebih baru dan libxml2 2.7.3 atau yang lebih baru ([https://bugs.php.net/bug.php?id=45996 arsip bug di PHP]).\nInstalasi dibatalkan.",
        "config-suhosin-max-value-length": "Suhosin terpasang dan membatasi parameter GET <code>length</code> sebesar $1 bita. Komponen ResourceLoader MediaWiki akan berjalan dalam batasan ini, tetapi penanganannya akan menurunkan kinerja. Jika memungkinkan, Anda sebaiknya menetapkan nilai <code>suhosin.get.max_value_length</code> menjadi 1024 atau lebih tinggi dalam <code>php.ini</code> dan menyetel <code>$wgResourceLoaderMaxQueryLength</code> dengan nilai yang sama dalam <code>LocalSettings.php</code>.",
        "config-db-type": "Jenis basis data:",
        "config-missing-db-name": "Anda harus memasukkan nilai untuk \"{{int:config-db-name}}\"",
        "config-missing-db-host": "Anda harus memasukkan nilai untuk \"{{int:config-db-host}}\"",
        "config-missing-db-server-oracle": "Anda harus memasukkan nilai untuk \"{{int:config-db-host-oracle}}\"",
-       "config-invalid-db-server-oracle": "TNS basis data \"$1\" tidak sah.\nGunakan hanya huruf ASCII (a-z, A-Z), angka (0-9), garis bawah (_), dan titik (.).",
+       "config-invalid-db-server-oracle": "TNS basis data \"$1\" tidak sah.\nGunakan baik \"Nama TNS\" atau string \"Easy Connect\" ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Metode Penamaan Oracle]).",
        "config-invalid-db-name": "Nama basis data \"$1\" tidak sah.\nGunakan hanya huruf ASCII (a-z, A-Z), angka (0-9), garis bawah (_), dan tanda hubung (-).",
        "config-invalid-db-prefix": "Prefiks basis data \"$1\" tidak sah.\nGunakan hanya huruf ASCII (a-z, A-Z), angka (0-9), garis bawah (_), dan tanda hubung (-).",
        "config-connection-error": "$1.\n\nPeriksa nama inang, pengguna, dan sandi di bawah ini dan coba lagi.",
index 02ff624..79aed40 100644 (file)
@@ -56,7 +56,6 @@
        "config-env-good": "環境を確認しました。\nMediaWiki をインストールできます。",
        "config-env-bad": "環境を確認しました。\nMediaWiki のインストールはできません。",
        "config-env-php": "PHP $1がインストールされています。",
-       "config-env-php-toolow": "PHP $1 がインストールされています。\nしかし、MediaWikiには PHP $2 以上が必要です。",
        "config-unicode-using-utf8": "Unicode正規化に、Brion Vibberのutf8_normalize.soを使用。",
        "config-unicode-using-intl": "Unicode正規化に[http://pecl.php.net/intl intl PECL 拡張機能]を使用。",
        "config-unicode-pure-php-warning": "<strong>警告:</strong> Unicode 正規化の処理に [http://pecl.php.net/intl intl PECL 拡張機能]を利用できないため、処理が遅いピュア PHP の実装を代わりに使用しています。\n高トラフィックのサイトを運営する場合は、[//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode 正規化]をお読みください。",
@@ -64,7 +63,6 @@
        "config-no-db": "適切なデータベース ドライバーが見つかりませんでした! PHP にデータベース ドライバーをインストールする必要があります。\n以下の種類のデータベースに対応しています: $1\n\nPHP を自分でコンパイルした場合は、例えば <code>./configure --with-mysqli</code> を実行して、データベース クライアントを使用できるように再設定してください。\nDebian または Ubuntu のパッケージから PHP をインストールした場合は、モジュール (例: <code>php5-mysql</code>) もインストールする必要があります。",
        "config-outdated-sqlite": "<strong>警告:</strong> あなたは SQLite $1 を使用していますが、最低限必要なバージョン $2 より古いバージョンです。SQLite は利用できません。",
        "config-no-fts3": "<strong>警告:</strong> SQLite は [//sqlite.org/fts3.html FTS3] モジュールなしでコンパイルされており、このバックエンドでは検索機能は利用できなくなります。",
-       "config-register-globals": "<strong>警告: PHP の <code>[http://php.net/register_globals register_globals]</code> オプションが有効になっています。\n可能なら無効化してください。</strong>\nMediaWiki は動作しますが、サーバーの潜在的なセキュリティ脆弱性が露呈されます。",
        "config-magic-quotes-runtime": "<strong>致命的エラー: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] が動作しています!</strong>\nこのオプションは、予期せずデータ入力を破壊します。\nこのオプションを無効化しない限り、MediaWiki のインストールや使用はできません。",
        "config-magic-quotes-sybase": "<strong>致命的エラー: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] が動作しています!</strong>\nこのオプションは、予期せずデータ入力を破壊します。\nこのオプションを無効化しない限り、MediaWiki のインストールや使用はできません。",
        "config-mbstring": "<strong>致命的エラー: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] が動作しています!</strong>\nこのオプションは、エラーを引き起こし、予期せずデータを破壊するおそれがあります。\nこのオプションを無効化しない限り、MediaWiki のインストールや使用はできません。",
        "config-license-gfdl": "GNU フリー文書利用許諾契約書 1.3 以降",
        "config-license-pd": "パブリック・ドメイン",
        "config-license-cc-choose": "その他のクリエイティブ・コモンズ・ライセンスを選択する",
-       "config-license-help": "多くの公開ウィキでは、すべての寄稿物が[http://freedomdefined.org/Definition フリーライセンス]のもとに置かれています。\nこうすることにより、コミュニティによる共有の感覚が生まれ、長期的な寄稿が促されます。\n私的ウィキや企業のウィキでは、通常、フリーライセンスにする必要はありません。\n\nウィキペディアにあるテキストをあなたのウィキで利用し、逆にあなたのウィキにあるテキストをウィキペディアに複製することを許可したい場合には、<strong>クリエイティブ・コモンズ 表示-継承</strong>を選択するべきです。\n\nウィキペディアは以前、GNUフリー文書利用許諾契約書(GFDL)を使用していました。\nGFDLは有効なライセンスですが、内容を理解するのは困難です。\nまた、GFDLのもとに置かれているコンテンツの再利用も困難です。",
+       "config-license-help": "多くの公開ウィキでは、すべての寄稿物が[http://freedomdefined.org/Definition フリーライセンス]のもとに置かれています。\nこうすることにより、コミュニティによる共有の感覚が生まれ、長期的な寄稿が促されます。\n私的ウィキや企業のウィキでは、通常、フリーライセンスにする必要はありません。\n\nウィキペディアにあるテキストをあなたのウィキで利用し、逆にあなたのウィキにあるテキストをウィキペディアに複製することを許可したい場合には、<strong>{{int:config-license-cc-by-sa}}</strong>を選択するべきです。\n\nウィキペディアは以前、GNUフリー文書利用許諾契約書(GFDL)を使用していました。\nGFDLは有効なライセンスですが、内容を理解するのは困難です。\nまた、GFDLのもとに置かれているコンテンツの再利用も困難です。",
        "config-email-settings": "メールの設定",
        "config-enable-email": "メール送信を有効にする",
        "config-enable-email-help": "メールを使用したい場合は、[http://www.php.net/manual/en/mail.configuration.php PHP のメール設定]が正しく設定されている必要があります。\nメールの機能を使用しない場合は、ここで無効にすることができます。",
index 0638452..72619bc 100644 (file)
@@ -50,7 +50,6 @@
        "config-env-good": "환경이 확인되었습니다.\n미디어위키를 설치할 수 있습니다.",
        "config-env-bad": "환경이 확인되었습니다.\n미디어위키를 설치할 수 없습니다.",
        "config-env-php": "PHP $1(이)가 설치되었습니다.",
-       "config-env-php-toolow": "PHP $1(이)가 설치되었습니다.\n하지만 미디어위키는 PHP $2 이상이 필요합니다.",
        "config-unicode-using-utf8": "유니코드 정규화에 Brion Vibber의 utf8_normalize.so를 사용합니다.",
        "config-unicode-using-intl": "유니코드 정규화에 [http://pecl.php.net/intl intl PECL 확장 기능]을 사용합니다.",
        "config-unicode-pure-php-warning": "'''경고''': 유니코드 정규화를 처리할 [http://pecl.php.net/intl intl PECL 확장 기능]을 사용할 수 없기 때문에 느린 pure-PHP 구현을 대신 사용합니다.\n트래픽이 높은 사이트에서 실행하시려면 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations 유니코드 정규화]를 읽어보시기 바랍니다.",
@@ -58,7 +57,7 @@
        "config-no-db": "적절한 데이터베이스 드라이버를 찾을 수 없습니다! PHP용 데이터베이스 드라이버를 설치해야 합니다.\n다음 데이터베이스 유형을 지원합니다: $1.\n\nPHP를 직접 컴파일했다면, 예를 들어 <code>./configure --with-mysql</code>을 사용하여, 데이터베이스 클라이언트를 활성화하도록 다시 설정하세요.\n데비안이나 우분투 패키지에서 PHP를 설치했다면 <code>php5-mysql</code> 모듈도 설치해야 합니다.",
        "config-outdated-sqlite": "'''경고''': 최소인 $2 버전보다 낮은 SQLite $1(이)가 있습니다. SQLite를 사용할 수 없습니다.",
        "config-no-fts3": "'''경고''': SQLite를 [//sqlite.org/fts3.html FTS3 모듈] 없이 컴파일하며, 검색 기능은 백엔드에 사용할 수 없습니다.",
-       "config-register-globals": "'''경고: PHP의 <code>[http://php.net/register_globals register_globals]</code> 옵션이 활성화되어 있습니다.'''\n'''가능하면 이를 비활성화하십시오.'''\n미디어위키는 작동하지만 서버에 잠재적인 보안 취약점이 노출됩니다.",
+       "config-register-globals-error": "<strong>오류: PHP의 <code>[http://php.net/register_globals register_globals]</code> 옵션이 활성화되어 있습니다.\n설치를 계속하려면 비활성화해야 합니다.</strong>\n어떻게 하는지에 대한 도움말에 대해서는 [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals]를 보세요.",
        "config-magic-quotes-runtime": "'''치명: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]이 활성화됩니다!'''\n이 옵션은 데이터를 입력하는 데 예기치 않는 손상이 일으킵니다.\n이 옵션을 비활성화하지 않는 한 미디어위키를 설치하고 사용할 수 없습니다.",
        "config-magic-quotes-sybase": "'''치명: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]이 활성화됩니다!'''\n이 옵션은 데이터를 입력하는 데 예기치 않는 손상을 일으킵니다.\n이 옵션을 비활성화하지 않는 한 미디어위키를 설치하고 사용할 수 없습니다.",
        "config-mbstring": "'''치명: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]이 활성화됩니다!'''\n이 옵션은 오류가 발생하고 데이터를 입력하는 데 예기치 않는 손상을 일으킬 수 있습니다.\n이 옵션을 비활성화하지 않는 한 미디어위키를 설치하고 사용할 수 없습니다.",
index 08526f4..9941442 100644 (file)
        "config-env-good": "Den Environement gouf nogekuckt.\nDir kënnt MediaWiki installéieren.",
        "config-env-bad": "Den Environnement gouf iwwerpréift.\nDir kënnt MediWiki net installéieren.",
        "config-env-php": "PHP $1 ass installéiert.",
-       "config-env-php-toolow": "PHP $1 ass installéiert.\nAwer MediaWiki brauch PHP $2 oder méi héich.",
        "config-unicode-using-utf8": "Fir d'Unicode-Normalisatioun gëtt dem Brion Vibber säin <code>utf8_normalize.so</code> benotzt.",
        "config-no-db": "Et konnt kee passenden Datebank-Driver fonnt ginn! Dir musst een Datebank-Driver fir PHP installéieren.\nDë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-mysql</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-iconv": "<strong>Fatal:</strong> PHP muss mat Support fir d'[http://www.php.net/manual/en/iconv.installation.php iconv-Erweiderung] kompiléiert ginn.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] ass installéiert",
        "config-apc": "[http://www.php.net/apc APC] ass installéiert",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp 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>.",
+       "config-git-bad": "D'Software fir d'Kontroll vun de Versiounen 'Git' gouf net fonnt.",
        "config-no-uri": "'''Feeler:''' Déi aktuell URI konnt net festgestallt ginn.\nInstallatioun ofgebrach.",
        "config-using-server": "De Servernumm \"<nowiki>$1</nowiki>\" gëtt benotzt.",
        "config-using-uri": "D'Server URL  \"<nowiki>$1$2</nowiki>\" gëtt benotzt.",
        "config-cc-again": "Nach eng kéier eraussichen...",
        "config-advanced-settings": "Erweidert Astellungen",
        "config-extensions": "Erweiderungen",
+       "config-skins": "Ausgesinn",
+       "config-skins-help": "D'Ausgesinn déi hei driwwer stinn goufen am Repertoire <code>./skins</code> fonnt. Dir musst mindestens eent aktivéieren an de Standard eraussichen.",
+       "config-skins-use-as-default": "Dëst Ausgesinn als Standard benotzen",
+       "config-skins-missing": "Et goufe keen Ausgesinn (Skin) fonnt; MediaWiki benotzt e Fallback-Ausgesinnbis Dir anerer installéiert.",
+       "config-skins-must-enable-some": "Dir musst mindestens een Ausgesinn fir z'aktivéieren eraussichen.",
+       "config-skins-must-enable-default": "Dat als Standard erausgesichten Ausgesinn muss aktivéiert sinn.",
        "config-install-step-done": "fäerdeg",
        "config-install-step-failed": "huet net funktionéiert",
        "config-install-extensions": "Mat den Ereiderungen",
index e236af5..255718f 100644 (file)
@@ -47,7 +47,6 @@
        "config-env-good": "Околината е проверена.\nМожете да го воспоставите МедијаВики.",
        "config-env-bad": "Околината е проверена.\nНе можете да го воспоставите МедијаВики.",
        "config-env-php": "PHP $1 е воспоставен.",
-       "config-env-php-toolow": "PHP $1 е воспоставен.\nМеѓутоа, МедијаВики бара PHP $2 или поново.",
        "config-unicode-using-utf8": "Со utf8_normalize.so за уникодна нормализација од Брајон Вибер (Brion Vibber).",
        "config-unicode-using-intl": "Со додатокот [http://pecl.php.net/intl intl PECL] за уникодна нормализација.",
        "config-unicode-pure-php-warning": "'''Предупредување''': Додатокот [http://pecl.php.net/intl intl PECL] не е достапен за врши уникодна нормализација, враќајќи се на бавна примена на чист PHP.\n\nАко имате високопрометно мрежно место, тогаш ќе треба да прочитате повеќе за [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations уникодната нормализација].",
@@ -55,7 +54,7 @@
        "config-no-db": "Не можев да најдам соодветен двигател за базата на податоци! Ќе треба да воспоставите двигател за PHP-база.\nПоддржани се следниве видови бази: $1.\n\nДоколку самите го срочивте овој PHP, овозможете го базниот клиент во поставките — на пр. со <code>./configure --with-mysqli</code>.\nАко овој PHP го воспоставите од пакет на Debian или Ubuntu, тогаш ќе треба исто така да го воспоставите, на пр., пакетот <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Предупредување''': имате SQLite $1. Најстарата допуштена верзија е $2. Затоа, SQLite ќе биде недостапен.",
        "config-no-fts3": "'''Предупредување''': SQLite iе составен без модулот [//sqlite.org/fts3.html FTS3] - за оваа база нема да има можност за пребарување.",
-       "config-register-globals": "'''Предупредување: Можноста <code>[http://php.net/register_globals register_globals]</code> за PHP е овозможена.'''\n'''Оневозможете ја ако е можно.'''\nМедијаВики ќе работи, но опслужувачот ви е изложен на безбедносни ризици.",
+       "config-register-globals-error": "<strong>Грешка: Вклучена е можноста <code>[http://php.net/register_globals register_globals]</code> за PHP.\nМора да се исклучи за да продолжите со воспоставката.</strong>\nКако да го направите тоа можете да прочитате на [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals].",
        "config-magic-quotes-runtime": "'''Кобно: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] е активно!'''\nОваа можност непредвидливо го расипува вносот на податоци.\nОваа можност мора да е исклучена. Во спротивно нема да можете да го воспоставите и користите МедијаВики.",
        "config-magic-quotes-sybase": "'''Кобно: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] е активно!'''\nОваа можност непредвидливо го расипува вносот на податоци.\nОваа можност мора да е исклучена. Во спротивно нема да можете да го воспоставите и користите МедијаВики.",
        "config-mbstring": "'''Кобно: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] е активно!'''\nОваа можност предизвикува грешки и може непредвидиво да го расипува вносот на податоци.\nОваа можност мора да е исклучена. Во спротивно нема да можете да го воспоставите и користите МедијаВики.",
@@ -66,6 +65,7 @@
        "config-memory-raised": "<code>memory_limit</code> за PHP изнесува $1, зголемен на $2.",
        "config-memory-bad": "'''Предупредување:''' <code>memory_limit</code> за PHP изнесува $1.\nОва е веројатно премалку.\nВоспоставката може да не успее!",
        "config-ctype": "'''Фатална грешка''': PHP мора да се состави со поддршка за [http://www.php.net/manual/en/ctype.installation.php додатокот Ctype].",
+       "config-iconv": "<strong>Кобно:</strong> PHP мора да се срочува со поддршка за [http://www.php.net/manual/en/iconv.installation.php додатокот iconv].",
        "config-json": "'''Кобно:''' PHP беше срочен без поддршка од JSON.\nЌе мора да го воспоставите додатокот за JSON во PHP, или додатокот [http://pecl.php.net/package/jsonc PECL jsonc] пред да го воспоставите МедијаВики.\n* Додатокот за PHP е вклучен во верзиите 5 и 6 на Linux (од Red Hat Enterprise) (CentOS), но мора да се активира во <code>/etc/php.ini</code> или <code>/etc/php.d/json.ini</code>.\n* Некои варијанти на Linux излезени по мај 2013 г. не го содржат додатокот за PHP, туку го пакуваат додатокот PECL како <code>php5-json</code> или <code>php-pecl-jsonc</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] е воспоставен",
        "config-apc": "[http://www.php.net/apc APC] е воспоставен",
        "config-db-account-lock": "Користи го истото корисничко име и лозинка за редовна работа",
        "config-db-wiki-account": "Корисничко име за редовна работа",
        "config-db-wiki-help": "Внесете корисничко име и лозинка што ќе се користат за поврзување со базата на податоци во текот на редовната работа со викито.\nАко сметката не постои, а инсталационата сметка има доволно привилегии, тогаш оваа корисничка сметка ќе биде создадена со минималните привилегии потребни за работа со викито.",
-       "config-db-prefix": "Ð\9fÑ\80еÑ\84икÑ\81 на табелата на базата:",
-       "config-db-prefix-help": "Ð\90ко Ñ\82Ñ\80еба Ð´Ð° Ð´ÐµÐ»Ð¸Ñ\82е ÐµÐ´Ð½Ð° Ð±Ð°Ð·Ð° Ð½Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\86и Ñ\81о Ð¿Ð¾Ð²ÐµÑ\9cе Ð²Ð¸ÐºÐ¸Ñ\98а, Ð¸Ð»Ð¸ Ñ\81о Ð\9cедиÑ\98аÐ\92ики Ð¸ Ð´Ñ\80Ñ\83г Ð¼Ñ\80ежен Ð¿Ñ\80огÑ\80ам, Ñ\82огаÑ\88 Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð´Ð¾Ð´Ð°Ð´ÐµÑ\82е Ð¿Ñ\80еÑ\84икÑ\81 на сите називи на табелите за да спречите проблематични ситуации.\nНе користете празни простори.\n\nОва поле обично се остава празно.",
+       "config-db-prefix": "Ð\9fÑ\80еÑ\82Ñ\81Ñ\82авка на табелата на базата:",
+       "config-db-prefix-help": "Ð\90ко Ñ\82Ñ\80еба Ð´Ð° Ð´ÐµÐ»Ð¸Ñ\82е ÐµÐ´Ð½Ð° Ð±Ð°Ð·Ð° Ð½Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\86и Ñ\81о Ð¿Ð¾Ð²ÐµÑ\9cе Ð²Ð¸ÐºÐ¸Ñ\98а, Ð¸Ð»Ð¸ Ñ\81о Ð\9cедиÑ\98аÐ\92ики Ð¸ Ð´Ñ\80Ñ\83г Ð¼Ñ\80ежен Ð¿Ñ\80огÑ\80ам, Ñ\82огаÑ\88 Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð´Ð¾Ð´Ð°Ð´ÐµÑ\82е Ð¿Ñ\80еÑ\82Ñ\81Ñ\82авка на сите називи на табелите за да спречите проблематични ситуации.\nНе користете празни простори.\n\nОва поле обично се остава празно.",
        "config-db-charset": "Збир знаци за базата",
        "config-charset-mysql5-binary": "Бинарен за MySQL 4.1/5.0",
        "config-charset-mysql5": "UTF-8 за MySQL 4.1/5.0",
        "config-missing-db-server-oracle": "Мора да внесете вредност за „{{int:config-db-host-oracle}}“.",
        "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": "Ð\9dеважеÑ\87ки Ð¿Ñ\80еÑ\84икÑ\81 за базата „$1“.\nКористете само ASCII-букви (a-z, A-Z), бројки (0-9), долни црти (_) и цртички (-).",
+       "config-invalid-db-prefix": "Ð\9dеважеÑ\87ка Ð¿Ñ\80еÑ\82Ñ\81Ñ\82авка за базата „$1“.\nКористете само ASCII-букви (a-z, A-Z), бројки (0-9), долни црти (_) и цртички (-).",
        "config-connection-error": "$1.\n\nПроверете го долунаведениот домаќин, корисничко име и лозинка и обидете се повторно.",
        "config-invalid-schema": "Неважечка шема за МедијаВики „$1“.\nКористете само букви, бројки и долни црти.",
        "config-db-sys-create-oracle": "Воспоставувачот поддржува само употреба на SYSDBA-сметка за создавање на нова сметка.",
        "config-license-gfdl": "ГНУ-ова лиценца за слободна документација 1.3 или понова",
        "config-license-pd": "Јавна сопственост",
        "config-license-cc-choose": "Одберете друга лиценца на Криејтив комонс по ваш избор",
-       "config-license-help": "Многу јавни викија ги ставаат сите придонеси под [http://freedomdefined.org/Definition слободна лиценца].\nСо ова се создава атмосфера на општа сопственост и поттикнува долгорочно учество.\nОва не е неопходно за викија на поединечни физички или правни лица.\n\nАко сакате да користите текст од Википедија, и сакате Википедија да прифаќа текст прекопиран од вашето вики, тогаш треба да ја одберете лиценцата '''Криејтив комонс НаведиИзвор СподелиПодИстиУслови'''.\n\nГНУ-овата лиценца за слободна документација (ГЛСД) е старата лиценца на Википедија.\nОваа лиценца сè уште важи, но е тешка за разбирање.\nИсто така треба да се има на ум дека пренамената на содржините под ГЛСД не е лесна.",
+       "config-license-help": "Многу јавни викија ги ставаат сите придонеси под [http://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": "Ако сакате да работи е-поштата, [http://www.php.net/manual/en/mail.configuration.php поштенските нагодувања на PHP] треба да се правилно наместени.\nАко воопшто не сакате никакви функции за е-пошта, тогаш можете да ги оневозможите тука.",
        "config-memcache-badport": "Бројките за портата на Memcached треба да бидат помеѓу $1 и $2",
        "config-extensions": "Додатоци",
        "config-extensions-help": "Во вашата папка <code>./extensions</code> беа востановени горенаведените додатоци.\n\nЗа ова може да треба дополнително нагодување, но можете да ги овозможите сега",
+       "config-skins": "Рува",
+       "config-skins-help": "Во вашата папка <code>./skins</code> се утврдени горенаведените рува. Ќе мора да овозможите барем едно и да го изберете основното.",
+       "config-skins-use-as-default": "Користи го како основно",
+       "config-skins-missing": "Не пронајдов ниедно руво. МедијаВики ќе користи резервно руво сè додека не воспоставите други.",
+       "config-skins-must-enable-some": "Ќе треба да изберете барем едно руво.",
+       "config-skins-must-enable-default": "Рувото што го избравте како основно мора да се овозможи.",
        "config-install-alreadydone": "'''Предупредување:''' Изгледа дека веќе го имате воспоставено МедијаВики и сега сакате да го воспоставите повторно.\nПродолжете на следната страница.",
        "config-install-begin": "Стискајќи на „{{int:config-continue}}“ ќе ја започнете воспоставката на МедијаВики.\nАко сакате да направите измени во досегашното, стиснете на „{{int:config-back}}“.",
        "config-install-step-done": "готово",
index 26f1cc7..2f2825d 100644 (file)
@@ -16,7 +16,7 @@
        "config-localsettings-badkey": "Kunci yang anda berikan tidak betul.",
        "config-upgrade-key-missing": "Pemasangan yang sedia ada MediaWiki telah dikesan.\nUntuk menaik taraf pemasangan, Sila letakkan baris berikut di bahagian bawah <code>LocalSettings.php</code> anda:\n\n$1",
        "config-localsettings-incomplete": "<code>LocalSettings.php</code> sedia ada nampaknya tidak lengkap.\nPemboleh ubah $1 tidak disetkan.\nSila tukar <code>LocalSettings.php</code> supaya pemboleh ubah ini disetkan, dan klik \"{{int:Config-terus}}\".",
-       "config-localsettings-connection-error": "Ralat berlaku semasa semasa menyambung ke dalam pangkalan data yang menggunakan seting yang dinyatakan dalam <code>LocalSettings.php</code> atau <code>AdminSettings.php</code>. Sila betulkan tetapan ini dan cuba lagi.\n\n$1",
+       "config-localsettings-connection-error": "Ralat berlaku semasa menyambung ke pangkalan data dengan menggunakan tetapan yang dinyatakan dalam <code>LocalSettings.php</code>. Sila betulkan tetapan tersebut dan cuba lagi.\n\n$1",
        "config-session-error": "Ralat ketika memulakan sesi: $1",
        "config-session-expired": "Data sesi anda seolah-olah telah tamat tempoh.\nSesi dikonfigurasi untuk seumur hidup sebanyak $1.\nAnda boleh menambah ini dengan menetapkan <code>session.gc_maxlifetime</code> di php.ini.\nMemulakan semula proses pemasangan.",
        "config-no-session": "Data sesi anda telah hilang!\nSemak php.ini anda dan pastikan <code>session.save_path</code> disetkan kepada satu direktori yang sesuai.",
        "config-env-good": "Persekitaran telah diperiksa.\nAnda boleh memasang MediaWiki.",
        "config-env-bad": "Persekitaran telah diperiksa. \nAnda tidak boleh memasang MediaWiki.",
        "config-env-php": "PHP $1 dipasang.",
-       "config-env-php-toolow": "PHP $1 dipasang.\nBagaimanapun, MediaWiki memerlukan PHP $2 ke atas.",
        "config-unicode-using-utf8": "utf8_normalize.so oleh Brion Vibber digunakan untuk penormalan Unicode.",
        "config-unicode-using-intl": "[http://pecl.php.net/intl Sambungan intl PECL] digunakan untuk penormalan Unicode.",
        "config-unicode-update-warning": "<strong>Amaran:</strong> Versi pembalut penormalan Unicode yang terpasang menggunakan perpustakaan [http://site.icu-project.org/ projek ICU] dalam versi yang lampau.\nAnda harus [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations menaik taraf] jika Unicode penting bagi anda.",
        "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-register-globals": "<strong>Amaran: Pilihan <code>[http://php.net/register_globals register_globals]</code> PHP dihidupkan.\nMatikannya jika boleh.</strong>\nMediaWiki boleh digunakan, tetapi pelayan anda akan terdedah kepada kemungkinan kerentanan keselamatan.",
        "config-mbstring": "<strong>Amaran keras: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] sedang aktif!</strong>\nOpsyen ini menyebabkan ralat dan mungkin mencemari data secara tanpa diduga.\nAnda tidak boleh memasang atau menggunakan MediaWiki melainkan opsyen ini dinyahdayakan.",
        "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 adalah $1.\nIni mungkin terlalu rendah.\nPemasangan mungkin akan gagal!",
        "config-ctype": "<strong>Amaran keras:</strong> PHP mesti disusun dengan sokongan untuk [http://www.php.net/manual/en/ctype.installation.php sambungan Ctype].",
+       "config-xcache": "[http://xcache.lighttpd.net/ XCache] dipasang",
+       "config-apc": "[http://www.php.net/apc APC] dipasang",
+       "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] dipasang",
        "config-no-cli-uri": "<strong>Amaran:</strong> Tiada <code>--scriptpath</code> dinyatakan, maka digunakannya yang asali: <code>$1</code>.",
+       "config-using-server": "Sedang menggunakan nama pelayan \"<nowiki>$1</nowiki>\".",
+       "config-using-uri": "Sedang menggunakan URL pelayan \"<nowiki>$1$2</nowiki>\".",
        "config-no-cli-uploads-check": "<strong>Amaran:</strong> Direktori asali anda untuk muat naikan (<code>$1</code>) belum diperiksa untuk kerentanan\nkepada pelaksanaan skrip yang menyeleweng sewaktu pemasangan CLI.",
        "config-db-charset": "Peranggu aksara pangkalan data",
        "config-pg-test-error": "Tidak boleh bersambung dengan pangkalan data <strong>$1</strong>: $2",
index c95e9df..93ddfa4 100644 (file)
@@ -50,7 +50,6 @@
        "config-env-good": "Miljøet har blitt sjekket.\nDu kan installere MediaWiki.",
        "config-env-bad": "Miljøet har blitt sjekket.\nDu kan installere MediaWiki.",
        "config-env-php": "PHP $1 er innstallert.",
-       "config-env-php-toolow": "PHP $1 er installert.\nMediaWiki krever imidlertid PHP $2 eller høyere.",
        "config-unicode-using-utf8": "Bruker Brion Vibbers utf8_normalize.so for Unicode-normalisering.",
        "config-unicode-using-intl": "Bruker [http://pecl.php.net/intl intl PECL-utvidelsen] for Unicode-normalisering.",
        "config-unicode-pure-php-warning": "'''Advarsel''': [http://pecl.php.net/intl intl PECL-utvidelsen] er ikke tilgjengelig for å håndtere Unicode-normaliseringen, faller tilbake til en langsommere ren-PHP-implementasjon.\nOm du kjører et nettsted med høy trafikk bør du lese litt om [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-normalisering].",
@@ -58,7 +57,7 @@
        "config-no-db": "Fant ingen passende databasedriver! Du må installere en databasedriver for PHP.\nFølgende databasetyper støttes: $1\n\nOm du kompilerte PHP selv, rekonfigurer den med en aktivert databaseklient, for eksempel ved å bruke <code>./configure --with-mysql</code>.\nOm du installerte PHP fra en Debian- eller Ubuntu-pakke, må du også installere for eksempel <code>php5-mysql</code>-pakken.",
        "config-outdated-sqlite": "'''Advarsel''': Du har SQLite $1, som er en eldre versjon enn minimumskravet SQLite $2. SQLite vil ikke være tilgjengelig.",
        "config-no-fts3": "'''Advarsel''': SQLite er kompilert uten [//sqlite.org/fts3.html FTS3-modulen], søkefunksjoner vil ikke være tilgjengelig på dette bakstykket.",
-       "config-register-globals": "'''Advarsel: PHPs <code>[http://php.net/register_globals register_globals]</code>-alternativ er aktivert.'''\n'''Deaktiver det om du kan.'''\nMediaWiki vil fungere, men tjeneren din er utsatt for potensielle sikkerhetssårbarheter.",
+       "config-register-globals-error": "<strong>Feil: PHPs <code>[http://php.net/register_globals register_globals]</code>-valg er aktivt.\nDet må deaktiveres for å kunne fortsette med installeringen.</strong>\nSe [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] for å få hjelp til å gjøre dette.",
        "config-magic-quotes-runtime": "'''Kritisk: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] er aktiv!'''\nDette alternativet ødelegger inndata på en uforutsigbar måte.\nDu kan ikke installere eller bruke MediaWiki med mindre dette alternativet deaktiveres.",
        "config-magic-quotes-sybase": "'''Kritisk: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] er aktiv!'''\nDette alternativet ødelegger inndata på en uforutsigbar måte.\nDu kan ikke installere eller bruke MediaWiki med mindre dette alternativet deaktiveres.",
        "config-mbstring": "'''Kritisk: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] er aktiv!'''\nDette alternativet fører til feil og kan ødelegge data på en uforutsigbar måte.\nDu kan ikke installere eller bruke MediaWiki med mindre dette alternativet deaktiveres.",
index 1a3e7ae..eb16d0d 100644 (file)
@@ -61,7 +61,6 @@
        "config-env-good": "Środowisko oprogramowania zostało sprawdzone.\nMożesz teraz zainstalować MediaWiki.",
        "config-env-bad": "Środowisko oprogramowania zostało sprawdzone.\nNie możesz zainstalować MediaWiki.",
        "config-env-php": "Zainstalowane jest PHP w wersji $1.",
-       "config-env-php-toolow": "Zainstalowane jest PHP $1.\nJednak MediaWiki wymaga PHP $2 lub nowszego.",
        "config-unicode-using-utf8": "Korzystanie z normalizacji Unicode utf8_normalize.so napisanej przez Brion Vibbera.",
        "config-unicode-using-intl": "Korzystanie z [http://pecl.php.net/intl rozszerzenia intl PECL] do normalizacji Unicode.",
        "config-unicode-pure-php-warning": "'''Uwaga!''' [http://pecl.php.net/intl Rozszerzenie intl PECL] do obsługi normalizacji Unicode nie jest dostępne. Użyta zostanie mało wydajna zwykła implementacja w PHP.\nJeśli prowadzisz stronę o dużym natężeniu ruchu, powinieneś zapoznać się z informacjami o [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizacji Unicode].",
@@ -69,7 +68,7 @@
        "config-no-db": "Nie można odnaleźć właściwego sterownika bazy danych! Musisz zainstalować sterownik bazy danych dla PHP.\nMożna użyć następujących typów baz danych: $1.\n\nJeśli skompilowałeś PHP samodzielnie, skonfiguruj je ponownie z włączonym klientem bazy danych, na przykład za pomocą polecenia <code>./configure --with-mysqli</code>.\nJeśli zainstalowałeś PHP jako pakiet Debiana lub Ubuntu, musisz również zainstalować np. moduł <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Ostrzeżenie''': masz SQLite  $1, która jest niższa od minimalnej wymaganej wersji  $2 . SQLite będzie niedostępne.",
        "config-no-fts3": "'''Uwaga''' – SQLite został skompilowany bez [//sqlite.org/fts3.html modułu FTS3] – funkcje wyszukiwania nie będą dostępne.",
-       "config-register-globals": "'''Uwaga –  w konfiguracji PHP włączona jest opcja <code>[http://php.net/register_globals register_globals]</code>.'''\n'''Jeśli możesz, wyłącz ją.'''\nMediaWiki będzie działać, ale Twój serwer może być narażony potencjalnymi lukami w zabezpieczeniach.",
+       "config-register-globals-error": "<strong>Błąd: dyrektywa PHP <code>[http://php.net/register_globals register_globals]</code> jest włączona.\nAby kontynuować instalację musi zostać wyłączona.</strong>\nPrzeczytaj [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals], aby dowiedzieć się, jak to zrobić.",
        "config-magic-quotes-runtime": "'''Błąd krytyczny – włączono [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]!'''\nTa opcja powoduje nieprzewidywalne uszkodzenia wprowadzanych danych.\nZainstalować lub korzystać z MediaWiki można pod warunkiem, że ta opcja jest wyłączona.",
        "config-magic-quotes-sybase": "'''Błąd krytyczny – włączono [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]!'''\nTa opcja powoduje nieprzewidywalne uszkodzenia wprowadzanych danych.\nZainstalować lub korzystać z MediaWiki można pod warunkiem, że ta opcja jest wyłączona.",
        "config-mbstring": "'''Błąd krytyczny – włączono [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]!'''\nTa opcja powoduje błędy i może wywołać nieprzewidywalne uszkodzenia wprowadzanych danych.\nZainstalować lub korzystać z MediaWiki można pod warunkiem, że ta opcja jest wyłączona.",
index 20f0b3e..68a94e8 100644 (file)
@@ -57,7 +57,6 @@
        "config-env-good": "O ambiente foi verificado.\nVocê pode instalar o MediaWiki.",
        "config-env-bad": "O ambiente foi verificado.\nVocê não pode instalar o MediaWiki.",
        "config-env-php": "O PHP $1 está instalado.",
-       "config-env-php-toolow": "PHP $1 está instalado.\nNo entanto, o MediaWiki requer PHP $2 ou superior.",
        "config-unicode-using-utf8": "Usando o utf8_normalize.so, de Brion Vibber, para a normalização Unicode.",
        "config-unicode-using-intl": "Usando a [http://pecl.php.net/intl extensão intl PECL] para a normalização Unicode.",
        "config-unicode-pure-php-warning": "<strong>Aviso</strong>: A [http://pecl.php.net/intl extensão intl PECL] não está disponível para efetuar a normalização Unicode, abortando e passando para a lenta implementação de PHP puro.\nSe o seu site tem um alto volume de tráfego, informe-se sobre a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalização Unicode].",
@@ -65,7 +64,6 @@
        "config-no-db": "Não foi possível encontrar um driver de banco de dados adequado! É necessário instalar um driver de banco de dados para o PHP.\nSão suportados os seguintes tipos de bancos de dados: $1.\n\nSe você mesmo tiver compilado o PHP, reconfigure-o com um cliente de banco de dados ativado usando, por exemplo <code>./configure --with-mysqli</code>.\nSe você instalou o PHP a partir de um pacote do Debian ou do Ubuntu, então será também necessário instalar, por exemplo, o pacote <code>php5-mysql</code>.",
        "config-outdated-sqlite": "<strong>Aviso:</strong> você tem o SQLite versão $1, que é menor do que a versão mínima necessária $2. O SQLite não estará disponível.",
        "config-no-fts3": "<strong>Aviso</strong> O SQLite foi compilado sem o [//sqlite.org/fts3.html módulo FTS3], as funcionalidades de pesquisa não estarão disponíveis nesta instalação.",
-       "config-register-globals": "<strong>Aviso: A opção <code>[http://php.net/register_globals register_globals]</code> do PHP está ativada.\nDesative-a se puder.</strong>\nO MediaWiki funcionará mesmo assim, mas o seu servidor ficará exposto a potenciais vulnerabilidades de segurança.",
        "config-magic-quotes-runtime": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] está ativada!</strong>\nEsta opção causa corrupção dos dados de entrada de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
        "config-magic-quotes-sybase": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está ativada!</strong>\nEsta opção corrompe os dados de entrada de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
        "config-mbstring": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está ativada!</strong>\nEsta opção causa erros e pode corromper os dados de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
index a547edc..114839e 100644 (file)
@@ -59,7 +59,6 @@
        "config-env-good": "O ambiente foi verificado.\nPode instalar o MediaWiki.",
        "config-env-bad": "O ambiente foi verificado.\nNão pode instalar o MediaWiki.",
        "config-env-php": "O PHP $1 está instalado.",
-       "config-env-php-toolow": "O PHP $1 está instalado.\nNo entanto, o MediaWiki requer o PHP $2 ou superior.",
        "config-unicode-using-utf8": "A usar o utf8_normalize.so, por Brion Vibber, para a normalização Unicode.",
        "config-unicode-using-intl": "A usar a [http://pecl.php.net/intl extensão intl PECL] para a normalização Unicode.",
        "config-unicode-pure-php-warning": "'''Aviso''': A [http://pecl.php.net/intl extensão intl PECL] não está disponível para efetuar a normalização Unicode. Irá recorrer-se à implementação em PHP puro, que é mais lenta.\nSe o seu site tem alto volume de tráfego, devia informar-se um pouco sobre a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/pt normalização Unicode].",
@@ -67,7 +66,6 @@
        "config-no-db": "Não foi possível encontrar um controlador ''(driver)'' apropriado da base de dados! Precisa de instalar um controlador da base de dados para o PHP. São aceites os seguintes tipos de base de dados: $1.\n\nSe fez a compilação do PHP, reconfigure-o com um cliente de base de dados ativado; por exemplo, usando <code>./configure --with-mysql</code>.\nSe instalou o PHP a partir de um pacote Debian ou Ubuntu, então precisa de instalar também, por exemplo, o pacote <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Aviso''': Tem a versão $1 do SQLite, que é anterior à versão mínima necessária, a $2. O SQLite não estará disponível.",
        "config-no-fts3": "'''Aviso''': O SQLite foi compilado sem o módulo [//sqlite.org/fts3.html FTS3]; as funcionalidades de pesquisa não estarão disponíveis nesta instalação.",
-       "config-register-globals": "'''Aviso: A opção <code>[http://php.net/register_globals register_globals]</code> do PHP está ativada.'''\n'''Desative-a, se puder.'''\nO MediaWiki funciona mesmo assim, mas o seu servidor está exposto a potenciais vulnerabilidades de segurança.",
        "config-magic-quotes-runtime": "'''Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] está ativa!'''\nEsta opção causa corrupção dos dados de entrada, de uma forma imprevisível.\nNão pode instalar ou usar o MediaWiki a menos que esta opção seja desativada.",
        "config-magic-quotes-sybase": "'''Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está ativa!'''\nEsta opção causa corrupção dos dados de entrada, de uma forma imprevisível.\nNão pode instalar ou usar o MediaWiki a menos que esta opção seja desativada.",
        "config-mbstring": "'''Erro fatal: A opção [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está ativa!'''\nEsta opção causa erros e pode corromper os dados de uma forma imprevisível.\nNão pode instalar ou usar o MediaWiki a menos que esta opção seja desativada.",
        "config-license-gfdl": "GNU Free Documentation License 1.3 ou posterior",
        "config-license-pd": "Domínio Público",
        "config-license-cc-choose": "Selecionar uma licença personalizada Creative Commons",
-       "config-license-help": "Muitas wikis de acesso público licenciam todas as colaborações com uma [http://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 Creative Commons - Atribuição - Partilha nos Mesmos Termos.\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-license-help": "Muitas wikis de acesso público licenciam todas as colaborações com uma [http://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 electrónico",
        "config-enable-email": "Ativar mensagens eletrónicas de saída",
        "config-enable-email-help": "Se quer que o correio eletrónico funcione, as [http://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-memcache-badport": "Os números das portas do Memcached devem estar entre $1 e $2.",
        "config-extensions": "Extensões",
        "config-extensions-help": "Foi detectada a existência das extensões listadas acima, no seu diretório <code>./extensions</code>.\n\nEstas talvez necessitem de configurações adicionais, mas pode ativá-las agora",
+       "config-skins": "Temas",
+       "config-skins-help": "Os temas listados abaixo foram detetados no seu diretório <code>./skins</code>. Deverá ativar pelo menos um e escolher qual o escolhido por padrão.",
+       "config-skins-use-as-default": "Usar este tema como padrão",
+       "config-skins-must-enable-some": "Deve escolher pelo menos um tema para ativar.",
+       "config-skins-must-enable-default": "O tema escolhido como padrão deve ser ativado.",
        "config-install-alreadydone": "'''Aviso:''' Parece que já instalou o MediaWiki e está a tentar instalá-lo novamente.\nPasse para a próxima página, por favor.",
        "config-install-begin": "Ao clicar \"{{int:config-continue}}\", vai iniciar a instalação do MediaWiki.\nSe quiser fazer mais alterações, clique \"{{int:config-back}}\".",
        "config-install-step-done": "terminado",
index 3a16079..1ea0e63 100644 (file)
@@ -62,7 +62,6 @@
        "config-env-good": "See also:\n* {{msg-mw|Config-env-bad}}",
        "config-env-bad": "See also:\n* {{msg-mw|Config-env-good}}",
        "config-env-php": "Parameters:\n* $1 - the version of PHP that has been installed\nSee also:\n* {{msg-mw|config-env-php-toolow}}",
-       "config-env-php-toolow": "Parameters:\n* $1 - the version of PHP that has been installed\n* $2 - minimum PHP version number\nSee also:\n* {{msg-mw|config-env-php}}",
        "config-unicode-using-utf8": "Status message in the MediaWiki installer environment checks.",
        "config-unicode-using-intl": "Status message in the MediaWiki installer environment checks.",
        "config-unicode-pure-php-warning": "PECL is the name of a group producing standard pieces of software for PHP, and intl is the name of their library handling some aspects of internationalization.",
@@ -70,7 +69,7 @@
        "config-no-db": "{{doc-important|Do not translate \"<code>./configure --with-mysqli</code>\" and \"<code>php5-mysql</code>\".}}\nParameters:\n* $1 is comma separated list of database types supported by MediaWiki.",
        "config-outdated-sqlite": "Used as warning. Parameters:\n* $1 - the version of SQLite that has been installed\n* $2 - minimum version",
        "config-no-fts3": "A \"[[:wikipedia:Front and back ends|backend]]\" is a system or component that ordinary users don't interact with directly and don't need to know about, and that is responsible for a distinct task or service - for example, a storage back-end is a generic system for storing data which other applications can use. Possible alternatives for back-end are \"system\" or \"service\", or (depending on context and language) even leave it untranslated.",
-       "config-register-globals": "Status message in the MediaWiki installer environment checks.",
+       "config-register-globals-error": "Error message in the MediaWiki installer environment checks.",
        "config-magic-quotes-runtime": "{{Related|Config-fatal}}",
        "config-magic-quotes-sybase": "{{Related|Config-fatal}}",
        "config-mbstring": "{{Related|Config-fatal}}",
@@ -81,6 +80,7 @@
        "config-memory-raised": "Parameters:\n* $1 is the configured <code>memory_limit</code>.\n* $2 is the value to which <code>memory_limit</code> was raised.",
        "config-memory-bad": "Parameters:\n* $1 is the configured <code>memory_limit</code>.",
        "config-ctype": "Message if support for [http://www.php.net/manual/en/ctype.installation.php Ctype] is missing from PHP.\n{{Related|Config-fatal}}",
+       "config-iconv": "Message if support for [http://www.php.net/manual/en/iconv.installation.php iconv] is missing from PHP.\n{{Related|Config-fatal}}",
        "config-json": "Message if support for [[wikipedia:JSON|JSON]] is missing from PHP.\n* \"[[wikipedia:Red Hat Enterprise Linux|Red Hat Enterprise Linux]]\" (RHEL) and \"[[wikipedia:CentOS|CentOS]]\" refer to two almost-identical Linux distributions. \"5 and 6\" refers to version 5 or 6 of either distribution. Because RHEL 7 likely will not include the PHP extension, do not translate as \"5 or newer\".\n* \"The [http://www.php.net/json PHP extension]\" is the JSON extension included with PHP 5.2 and newer.\n* \"The [http://pecl.php.net/package/jsonc PECL extension]\" is based on the PHP extension, though excludes code some distributions have found unacceptable (see [[bugzilla:47431]]).\n{{Related|Config-fatal}}",
        "config-xcache": "Message indicates if this program is available",
        "config-apc": "Message indicates if this program is available",
        "config-license-gfdl": "Option for the wiki content license in the MediaWiki installer.",
        "config-license-pd": "{{Identical|Public domain}}",
        "config-license-cc-choose": "Option for the wiki content license in the MediaWiki installer.",
-       "config-license-help": "Help text in MediaWiki installer for license selection.",
+       "config-license-help": "Help text in MediaWiki installer for license selection.\n\nRefers to {{msg-mw|Config-license-cc-by-sa}}.",
        "config-email-settings": "{{Identical|E-mail setting}}",
        "config-enable-email": "Checkbox label in the MediaWiki installer to allow the wiki to send email to its users.",
        "config-enable-email-help": "Help text in the MediaWiki installer to allow the wiki to send email to its users.",
        "config-memcache-badport": "Used as error message. Parameters:\n* $1 - 1 (hard-coded)\n* $2 - 65535 (hard-coded)\nSee also:\n* {{msg-mw|Config-memcache-badip}}\n* {{msg-mw|Config-memcache-noport}}",
        "config-extensions": "{{Identical|Extension}}",
        "config-extensions-help": "{{doc-important|Do not translate <code>./extensions</code>.}}\nUsed in help box.",
+       "config-skins": "{{Identical|Skin}}",
+       "config-skins-help": "{{doc-important|Do not translate <code>./skins</code>.}}\nUsed in help box.",
+       "config-skins-use-as-default": "Label shown next to skin names.",
+       "config-skins-missing": "Warning message shown when there are no skins to install.",
+       "config-skins-must-enable-some": "Error message shown when the user does silly things.",
+       "config-skins-must-enable-default": "Error message shown when the user does silly things.",
        "config-install-alreadydone": "Error message shown to users visiting the installer when the wiki appears to already be set up.",
        "config-install-begin": "Prompt at the end of the initial configuration options screen before the wiki software is installed.",
        "config-install-step-done": "{{Identical|Done}}",
index 17f5fbc..15ac805 100644 (file)
@@ -62,7 +62,6 @@
        "config-env-good": "Проверка внешней среды была успешно проведена.\nВы можете установить MediaWiki.",
        "config-env-bad": "Была проведена проверка внешней среды.\nВы не можете установить MediaWiki.",
        "config-env-php": "Установленная версия PHP: $1.",
-       "config-env-php-toolow": "Найден PHP $1, тогда как MediaWiki требуется PHP версии $2 или выше.",
        "config-unicode-using-utf8": "Использовать Brion Vibber utf8_normalize.so для нормализации Юникода.",
        "config-unicode-using-intl": "Будет использовано [http://pecl.php.net/intl расширение «intl» для PECL] для нормализации Юникода.",
        "config-unicode-pure-php-warning": "'''Внимание!''': [http://pecl.php.net/intl расширение intl из PECL] недоступно для нормализации Юникода, будет использоваться медленная реализация на чистом PHP.\nЕсли ваш сайт работает под высокой нагрузкой, вам следует больше узнать о [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормализации Юникода].",
@@ -70,7 +69,7 @@
        "config-no-db": "Не удалось найти подходящие драйвера баз данных! Вам необходимо установить драйвера базы данных для PHP.\nПоддерживаются следующие типы баз данных: $1.\nЕсли вы скомпилировали PHP сами, перенастройте его с включением клиента баз данных, например, с помощью <code>./configure --with-mysqli</code>.\nЕсли вы скомпилировали PHP сами, сконфигурируйте его снова с включенным клиентом базы данных, например, с помощью <code>./configure --with-mysql</code>.\nЕсли вы установили PHP из пакетов Debian или Ubuntu, то вам также необходимо установить, например, пакет <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Предупреждение''': у Вас установлен SQLite  $1, версия которого ниже требуемой $2 . SQLite будет недоступен.",
        "config-no-fts3": "'''Внимание''': SQLite собран без модуля [//sqlite.org/fts3.html FTS3] — поиск не будет работать для этой базы данных.",
-       "config-register-globals": "'''Внимание: PHP-опция <code>[http://php.net/register_globals register_globals]</code> включена.'''\n'''Отключите её, если это возможно.'''\nMediaWiki будет работать, но это снизит безопасность сервера и увеличит риск проникновения извне.",
+       "config-register-globals-error": "<strong>Ошибка: Параметр PHP <code>[http://php.net/register_globals register_globals]</code> включен.\nОн должен быть отключен для того, чтобы можно было продолжить установку.</strong>\nПолучить справку о том, как это сделать, можно по адресу [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals].",
        "config-magic-quotes-runtime": "'''Проблема: включена опция PHP [http://www.php.net/manual/ru/function.magic-quotes-runtime.php magic_quotes_runtime]!'''\nЭто приводит к непредсказуемой порче вводимых данных.\nУстановка и использование MediaWiki без выключения этой опции невозможно.",
        "config-magic-quotes-sybase": "'''Проблема: включена опция PHP [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]!'''\nЭто приводит к непредсказуемой порче вводимых данных.\nУстановка и использование MediaWiki без выключения этой опции невозможно.",
        "config-mbstring": "'''Проблема: включена опция PHP [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]!'''\nЭто приводит к ошибкам и непредсказуемой порче вводимых данных.\nУстановка и использование MediaWiki без выключения этой опции невозможно.",
@@ -81,6 +80,7 @@
        "config-memory-raised": "Ограничение на доступную PHP память (<code>memory_limit</code>) поднято с $1 до $2.",
        "config-memory-bad": "'''Внимание:''' размер PHP <code>memory_limit</code> составляет $1.\nВероятно, этого слишком мало.\nУстановка может потерпеть неудачу!",
        "config-ctype": "'''Фатальная ошибка:''' PHP должен быть скомпилирован с поддержкой [http://www.php.net/manual/ru/ctype.installation.php расширения Ctype].",
+       "config-iconv": "<strong>Фатальная ошибка:</strong> PHP должен быть скомпилирован с поддержкой [http://www.php.net/manual/en/iconv.installation.php расширения iconv].",
        "config-json": "'''Фатальная ошибка:''' PHP был скомпилирован без поддержка JSON.\nВам необходимо установить либо расширение PHP JSON, либо расширение [http://pecl.php.net/package/jsonc PECL jsonc] перед установкой MediaWiki.\n* PHP-расширение входит в состав Red Hat Enterprise Linux (CentOS) 5 и 6, хотя должна быть включено в <code>/etc/php.ini</code> или <code>/etc/php.d/json.ini</code>.\n* Некоторые дистрибутивы Linux, выпущенные после мая 2013 года, не включают расширение PHP, вместо того, чтобы упаковывать расширение PECL как <code>php5-json</code> или <code>php-pecl-jsonc</code>.",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] установлен",
        "config-apc": "[http://www.php.net/apc APC] установлен",
        "config-license-gfdl": "GNU Free Documentation License 1.3 или более поздняя",
        "config-license-pd": "Общественное достояние",
        "config-license-cc-choose": "Выберите одну из лицензий Creative Commons",
-       "config-license-help": "Многие общедоступные вики разрешают использовать свои материалы на условиях [http://freedomdefined.org/Definition/Ru свободных лицензий].\nЭто помогает созданию чувства общности, стимулирует долгосрочное участие.\nНо в этом нет необходимости для частных или корпоративных вики.\n\nЕсли вы хотите использовать тексты из Википедии или хотите, что в Википедию можно было копировать тексты из вашей вики, вам следует выбрать '''Creative Commons Attribution Share Alike'''.\n\nВикипедия ранее использовала лицензию GNU Free Documentation License.\nGFDL может быть использована, но она сложна для понимания и осложняет повторное использование материалов.",
+       "config-license-help": "Многие общедоступные вики разрешают использовать свои материалы на условиях [http://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": "Если вы хотите, чтобы электронная почта работала, необходимо выполнить [http://www.php.net/manual/ru/mail.configuration.php соответствующие настройки PHP].\nЕсли вы не хотите использовать возможности электронной почты в вики, вы можете её отключить.",
        "config-memcache-badport": "Номера портов Memcached должны лежать в пределах от $1 до $2.",
        "config-extensions": "Расширения",
        "config-extensions-help": "Расширения MediaWiki, перечисленные выше, были найдены в каталоге <code>./extensions</code>.\n\nОни могут потребовать дополнительные настройки, но их можно включить прямо сейчас",
+       "config-skins": "Темы оформления",
+       "config-skins-help": "Перечисленные выше темы оформления были обнаружены в вашем каталоге <code>./skins</code>. Вам необходимо включить по крайней мере один из них и выбрать тот, что будет по умолчанию.",
+       "config-skins-use-as-default": "Использовать по умолчанию эту тему оформления",
+       "config-skins-missing": "Темы оформления не найдены. MediaWiki будет использовать резервную тему до тех пор, пока вы не установите что-нибудь подходящее.",
+       "config-skins-must-enable-some": "Вы должны оставить включённой как минимум одну тему оформления.",
+       "config-skins-must-enable-default": "Тема оформления, выбранная по умолчанию, должна быть включена.",
        "config-install-alreadydone": "'''Предупреждение:''' Вы, кажется, уже устанавливали MediaWiki и пытаетесь произвести повторную установку.\nПожалуйста, перейдите на следующую страницу.",
        "config-install-begin": "Нажав «{{int:config-continue}}», вы начнёте установку MediaWiki.\nЕсли вы хотите внести изменения, нажмите «{{int:config-back}}».",
        "config-install-step-done": "выполнено",
index 456f513..4cb5442 100644 (file)
@@ -51,7 +51,6 @@
        "config-env-good": "Miljön har kontrollerats.\nDu kan installera MediaWiki.",
        "config-env-bad": "Miljön har kontrollerats.\nDu kan inte installera MediaWiki.",
        "config-env-php": "PHP $1 är installerat.",
-       "config-env-php-toolow": "PHP $1 är installerat.\nMediaWiki kräver PHP $2 eller högre.",
        "config-unicode-using-utf8": "Använder Brion Vibbers utf8_normalize.so för Unicode-normalisering.",
        "config-unicode-using-intl": "Använder [http://pecl.php.net/intl intl PECL-tillägget] för Unicode-normalisering.",
        "config-unicode-pure-php-warning": "'''Varning:''' [http://pecl.php.net/intl intl PECL-tillägget] är inte tillgängligt för att hantera Unicode-normalisering, faller tillbaka till en långsamt implementering i ren PHP.\nOm du driver en högtrafikerad webbplats bör du läsa lite om [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-normalisering].",
@@ -59,7 +58,7 @@
        "config-no-db": "Kunde inte hitta en lämplig databasdrivrutin! Du måste installera en databasdrivrutin för PHP.\nFöljande databastyper stöds: $1.\n\nI du själv kompilerat din PHP, konfigurera den med en databasklient aktiverad genom att t.ex. använda <code>./configure --with-mysqli</code>.\nOm du installerade PHP från ett Debian- eller Ubuntupaket måste du även installera, t.ex. <code>php5-mysql</code>-paketet.",
        "config-outdated-sqlite": "'''Varning:''' du har SQLite $1, vilket är lägre än minimikravet version $2. SQLite kommer inte att vara tillgänglig.",
        "config-no-fts3": "'''Varning:''' SQLite kompileras utan [//sqlite.org/fts3.html FTS3-modulen], sökfunktioner kommer att vara otillgängliga på denna backend.",
-       "config-register-globals": "'''Varning: PHP:s <code>[http://php.net/register_globals register_globals]</code>-tillval är aktiverat.'''\n'''Inaktivera den om du kan.'''\nMediaWiki kommer att fungera, men din server exponeras för potentiella säkerhetshål.",
+       "config-register-globals-error": "<strong>Fel: PHP-alternativet <code>[http://php.net/register_globals register_globals]</code> är aktiverad.\nDen måste vara inaktiverad för att fortsätta med installationen.</strong>\nSe [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] för hjälp om hur man gör så.",
        "config-magic-quotes-runtime": "'''Kritiskt: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] är aktiv!'''\nDetta alternativ korrumperar inmatad data oförutsägbart.\nDu kan inte installera eller använda MediaWiki om detta alternativ är aktiverat.",
        "config-magic-quotes-sybase": "'''Kritiskt: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] är aktiv!'''\nDetta alternativ korrumperar inmatad data oförutsägbart.\nDu kan inte installera eller använda MediaWiki om detta alternativ är aktiverat.",
        "config-mbstring": "'''Kritiskt: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] är aktiv!'''\nDetta alternativ orsakar fel och kan korrumpera data oförutsägbart.\nDu kan inte installera eller använda MediaWiki om detta alternativ är aktiverat.",
@@ -99,6 +98,7 @@
        "config-db-name": "Databasnamn:",
        "config-db-name-help": "Välj ett namn som identifierar din wiki.\nDet bör inte innehålla mellanslag.\n\nOm du använder ett delat webbhotell kan de antingen ge dig ett särskilt databasnamn att använda eller så kan de låta dig skapa en databas via kontrollpanelen.",
        "config-db-name-oracle": "Databasschema:",
+       "config-db-account-oracle-warn": "Det finns tre stödda scenarier för installationen av Oracle som en backend-databas:\n\nOm du vill skapa ett databaskonto som en del av installationen, ange ett konto med SYSDBA-roll som databaskonto under installationen och ange de önskade autentiseringsuppgifterna för kontot med webb-åtkomst, annars kan du antingen skapa ett konto med webb-åtkomst manuellt och ange enbart detta konto (om den har behörighet att skapa schema-objekt) eller ange två olika konton, en med create-behörighet och en begränsad för webb-åtkomst.\n\nSkript för att skapa ett konto med de korrekta behörigheterna kan hittas i \"maintenance/oracle/\"-katalogen för denna installation. Tänk på att användningen av ett begränsat konto inaktiverar all underhållsmöjlighet med standardkontot.",
        "config-db-install-account": "Användarkonto för installation",
        "config-db-username": "Databas-användarnamn:",
        "config-db-password": "Databas-lösenord:",
        "config-db-schema-help": "Det här schemat blir oftast bra.\nÄndra det endast om du vet att du behöver.",
        "config-pg-test-error": "Kan inte ansluta till databas '''$1''': $2",
        "config-sqlite-dir": "SQLite data-katalog:",
+       "config-sqlite-dir-help": "SQLite lagrar all data i en enda fil.\n\nDen katalog du anger måste vara skrivbar av webbservern under installationen.\n\nDet bör <strong>inte</strong> vara tillgänglig via webben; Det är därför vi inte lägger den där dina PHP-filer är.\n\nInstallationsprogrammet kommer att skriva en <code>.htaccess</code>-fil tillsammans med den, men om det misslyckas kan någon få tillgång till den råa databasen.\nVlken innehåller rå användardata (e-postadresser, hashade lösenord) samt borttagna revideringar och annan begränsad data på wiki.\n\nÖverväga att lägga databasen någon helt annanstans, till exempel i <code>/var/lib/mediawiki/yourwiki</code>.",
+       "config-oracle-def-ts": "Standardtabellutrymme (tablespace):",
+       "config-oracle-temp-ts": "Tillfälligt tabellutrymme (tablespace):",
        "config-type-mysql": "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-missing-db-name": "Du måste ange ett värde för \"{{int:config-db-name}}\".",
        "config-missing-db-host": "Du måste ange ett värde för \"{{int:config-db-host}}\".",
        "config-missing-db-server-oracle": "Du måste ange ett värde för \"{{int:config-db-host-oracle}}\".",
+       "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-postgres-old": "PostgreSQL $1 eller senare krävs, du har $2.",
        "config-mssql-old": "Microsoft SQL-server $1 eller senare krävs. Du har $2.",
        "config-sqlite-name-help": "Välja ett namn som identifierar din wiki.\nAnvänd inte mellanslag eller bindestreck.\nDetta kommer att användas för SQLite-data filnamnet.",
+       "config-sqlite-parent-unwritable-group": "Kan inte skapa datakatalogen <code><nowiki>$1</nowiki></code>, då den överordnade katalogen <code><nowiki>$2</nowiki></code> inte är skrivbar för webbservern.\n\nInstallationen har avgjort vilken användare din webbserver körs som.\nGör <code><nowiki>$3</nowiki></code>-katalogen skrivbar för den för att fortsätta.\nPå ett Unix/Linux system gör:\n\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
+       "config-sqlite-parent-unwritable-nogroup": "Kan inte skapa datakatalogen <code><nowiki>$1</nowiki></code>, då den överordnade katalogen <code><nowiki>$2</nowiki></code> inte är skrivbar för webbservern.\n\nInstallationen kunde inte avgöra vilken användare din webbserver körs som.\nGör <code><nowiki>$3</nowiki></code>-katalogen skrivbar för den (och andra!) för att fortsätta.\nPå ett Unix/Linux system gör:\n\n<pre>cd $2\nmkdir $3\nchmod g+w $3</pre>",
        "config-sqlite-mkdir-error": "Fel uppstod när datakatalogen \"$1\" skulle skapas.\nKontrollera platsen och försök igen.",
+       "config-sqlite-dir-unwritable": "Kunde inte skriva till katalogen \"$1\".\nÄndra dess behörighet så att webbservern kan skriva till den och försök igen.",
+       "config-sqlite-connection-error": "$1.\n\nKontrollera datakatalogen och databasnamnet nedan och försök igen.",
        "config-sqlite-readonly": "Filen <code>$1</code> är inte skrivbar.",
        "config-sqlite-cant-create-db": "Kunde inte skapa databasfilen <code>$1</code>.",
        "config-sqlite-fts3-downgrade": "PHP saknar stöd för FTS3, nedgraderar tabeller",
        "config-upgrade-done": "Uppgraderingen slutfördes.\n\nDu kan nu [$1 börja använda din wiki].\n\nOm du vill förnya din <code>LocalSettings.php</code>-fil, klicka på knappen nedan.\nDetta '''rekommenderas inte''' om du har problem med din wiki.",
        "config-upgrade-done-no-regenerate": "Uppgraderingen slutfördes.\n\nDu kan nu [$1 börja använda din wiki].",
        "config-regenerate": "Återskapa LocalSettings.php →",
+       "config-show-table-status": "<code>SHOW TABLE STATUS</code>-förfrågan misslyckades!",
        "config-unknown-collation": "'''Varning:''' Databasen använder en okänd sortering.",
        "config-db-web-account": "Databaskonto för webbaccess",
        "config-db-web-help": "Välj det användarnamn och lösenord som webbservern använder för att ansluta till databasservern, under ordinarie drift av wikin.",
        "config-admin-error-password": "Internt fel lösenordet för administratören \"<nowiki>$1</nowiki>\" ställdes in: <pre>$2</pre>",
        "config-admin-error-bademail": "Du har angivit en ogiltig e-postadress.",
        "config-subscribe": "Prenumerera på [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce e-postlistan för kungörelser av nya versioner].",
+       "config-subscribe-help": "Detta är en e-postlista med låg volym vilken används för meddelanden om nya versionssläpp, inklusive viktiga säkerhetsmeddelanden.\nDu bör prenumerera på den och uppdatera din MediaWiki-installation när nya versioner kommer ut.",
+       "config-subscribe-noemail": "Du försökte att prenumerera på e-postlistan för versionssläppsmeddelanden utan att tillhandahålla en e-postadress.\nAnge en e-postadress om du vill prenumerera på e-postlistan.",
        "config-almost-done": "Du är nästan färdig!\nDu kan nu hoppa över återstående konfigurationer och installera wikin direkt.",
        "config-optional-continue": "Ställ fler frågor till mig.",
        "config-optional-skip": "Jag är redan uttråkad, bara installera wiki.",
        "config-profile-no-anon": "Kontoskapande krävs",
        "config-profile-fishbowl": "Endast auktoriserade redigerare",
        "config-profile-private": "Privat wiki",
+       "config-profile-help": "Wikis fungerar bäst när du låter som många människor som möjligt redigera dem.\nI MediaWiki, är det lätt att granska de senaste ändringarna och återställa alla skador som utförs av naiva eller illvilliga användare.\n\nMen många har funnit MediaWiki användbart i en mängd olika roller, och ibland är det inte lätt att övertyga alla fördelarna med wiki-sättet.\nSå valet är ditt.\n\nModellen <strong>{{int:config-profil-wiki}}</strong> tillåter vem som helst att redigera, utan att ens behöva logga in.\nEn wiki med <strong>{{int:config-profil-ingen-anon}}</strong> ger extra ansvarskänsla, men kan avskräcka tillfälliga bidragsgivare.\n\nScenariot <strong>{{int:config-profil-fishbowl}}</strong> tillåter godkända användare att redigera, men allmänheten kan se sidorna, inklusive historik.\nA <strong>{{int:config-profil-privat}}</strong> tillåter endast godkända användare att se sidor, samma grupp får även redigera.\n\nMer komplexa användarrättighetskonfigurationer finns tillgängliga efter installationen, se [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights avsnittet i manualen].",
        "config-license": "Upphovsrätt och licens:",
        "config-license-none": "Ingen licenssidfot",
        "config-license-cc-by-sa": "Creative Commons Erkännande-DelaLika",
        "config-license-gfdl": "GNU Free Documentation License 1.3 eller senare",
        "config-license-pd": "Public Domain",
        "config-license-cc-choose": "Välj en anpassad Creative Commons-licens",
+       "config-license-help": "Många publika wikis släpper alla bidrag under en  [http://freedomdefined.org/Definition fri licens].\nDetta bidrar till en känsla av gemensamt ägandeskap och uppmuntrar till långsiktiga bidrag.\nDet är i allmänhet inte nödvändigt för en privat eller företagswiki.\n\nOm du vill kunna använda text från Wikipedia, och du vill att Wikipedia ska kunna acceptera text kopierad ifrån din wiki bör du välja <strong>Creative Commons Erkännande-DelaLika</strong>.\n\nWikipedia använde tidigare  GNU Free Documentation License.\nGFDL är en giltig licens, men svår att förstå.\nDet är även svårt att återanvända innehåll som licensierats under GFDL.",
        "config-email-settings": "E-postinställningar",
        "config-enable-email": "Aktivera utgående e-post",
        "config-enable-email-help": "Om du vill att e-post ska fungera behöver,[http://www.php.net/manual/en/mail.configuration.php PHPs e-postinställningar] vara konfigurerad på rätt sätt.\nOm du inte vill ha några e-postfunktioner, kan du inaktivera dem här.",
        "config-install-pg-plpgsql": "Kontroll för språket PL/pgSQL",
        "config-pg-no-plpgsql": "Du måste installera språket PL/pgSQL i databasen $1",
        "config-pg-no-create-privs": "Det konto som du har angett för installationen har inte tillräcklig behörighet för att skapa ett konto.",
+       "config-pg-not-in-role": "Det konto du angav för webbanvändaren finns redan.\nKontot du angav för installationen är inte en superanvändare (superuser) och är inte en medlem av webbanvändarens roll, därför kan den inte skapa objekt som ägs av webbanvändaren.\n\nMediaWiki kräver för närvarande att tabellerna ägs av webbanvändaren. Vänligen ange ett annat webbkontonamn, eller klicka \"tillbaka\" och ange en installationsanvändare med passande behörigheter.",
        "config-install-user": "Skapar databasanvändare",
        "config-install-user-alreadyexists": "Användaren \"$1\" finns redan",
        "config-install-user-create-failed": "Misslyckades att skapa användare \"$1\": $2",
        "config-install-tables-failed": "'''Fel:''' Skapandet av tabell misslyckades med följande fel: $1",
        "config-install-interwiki": "Lägger till standardtabell för interwiki",
        "config-install-interwiki-list": "Kunde inte läsa filen <code>interwiki.list</code>.",
+       "config-install-interwiki-exists": "<strong>Varning:</strong> Interwiki-tabellen verkar redan innehålla poster.\nHoppar över standardlistan.",
        "config-install-stats": "Initierar statistik",
        "config-install-keys": "Genererar hemliga nycklar",
        "config-insecure-keys": "'''Varning:''' {{PLURAL:$2|En säkerhetsnyckel|Säkerhetsnycklar}} ($1) som generades under installationen är inte helt {{PLURAL:$2|säker|säkra}} . Överväg att ändra {{PLURAL:$2|den|dem}} manuellt.",
index 6ec8860..83c51ee 100644 (file)
@@ -18,7 +18,7 @@
        "config-localsettings-badkey": "Sağladığınız anahtar doğru değil.",
        "config-upgrade-key-missing": "Mevcut bir MediaWiki kurulumu algılandı.\nBu kurulumu güncelleştirmek için, lütfen aşağıdaki satırı <code>LocalSettings.php</code> dosyanızın en altına koyun:\n\n$1",
        "config-localsettings-incomplete": "Mevcut <code>LocalSettings.php</code> eksik gibi görünüyor.\n $1  değişkeni ayarlanmamış.\nLütfen <code>LocalSettings.php</code> dosyasını değiştirin bu değişkenleri kuracak, ve tıklayın  \"{{int:Config-cuntinue}}\".",
-       "config-localsettings-connection-error": "<code>LocalSettings.php</code> ya da <code>AdminSettings.php</code> dosyasında belirtilen ayarları kullanarak veritabanına bağlanırken bir hatayla karşılaşıldı. Lütfen bu ayarları düzeltin ve yeniden deneyin.\n\n$1",
+       "config-localsettings-connection-error": "<code>LocalSettings.php</code> içinde belirtilen ayarları kullanarak veritabanına bağlanırken bir hatayla karşılaşıldı. Lütfen bu ayarları düzeltin ve yeniden deneyin.\n\n$1",
        "config-session-error": "Oturum başlatılırken hata: $1",
        "config-session-expired": "Oturum bilgilerinizin süresi bitmiş.\nOturumların süresi $1 kadardır.\nBu süreyi php.ini' deki <code>session.gc_maxlifetime</code> ayarla arttırabilirsiniz.\nKurulum işlemini yeniden başlatın.",
        "config-no-session": "Oturum bilgileriniz silinmiş.\nphp.ini dosyanızı kontrol edin ve <code>session.save_path</code> ayarının uygun bir klasöre yönlendiğinden emin olun.",
        "config-restart": "Evet, yeniden başlat",
        "config-welcome": "===Ortam Kontrolleri===\nOrtamın Mediawiki kurulumuna uygun olup olmadığını anlamak için basit kontroller yapılacak.\nKurulumu nasıl tamamlayacağınız konusunda destek isterken bu bilgileri eklemeyi unutmayın.",
        "config-copyright": "=== Telif Hakları ve Koşulları ===\n\n$1\n\nBu program ücretsiz bir yazılımdır; yeniden dağıtabilir veya Özgür Yazılım Kuruluşu tarafından yayınlanan (GNU) Genel Kamu Lisansı koşulları altında değiştirebilirsiniz; isterseniz ikinci lisans sürümünü veya (sizin seçeneğiniz) herhangi bir sonraki lisans sürümünü kullanabilirsiniz.\n\nBu program, faydalı olacağı umuduyla dağıtılmaktadır, ancak ''' herhangi bir garantisi yoktur '''; ''' uygunluk ''' veya ''' belirli bir amaca uygunluk ''' gibi dolaylı garantileri bile yoktur.\nDaha fazla ayrıntı için (GNU) Genel Kamu Lisansına bakınız.\n\nBu program ile birlikte <doclink href=\"Copying\">bir (GNU) Genel Kamu Lisansının bir kopyasını </doclink> almış olmanız gerekir; bu program (GNU) Genel Kamu Lisansı ile dağıtılmadıysa, Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, ABD adresine yazın veya [http://www.gnu.org/copyleft/gpl.html online olarak okuyun].",
+       "config-sidebar": "* [//www.mediawiki.org MediaWiki ana sayfa]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Kullanıcı Rehberi]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Yetkili Rehberi]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ SSS]\n----\n* <doclink href=Readme>Beni oku</doclink>\n* <doclink href=ReleaseNotes>Sürüm notları</doclink>\n* <doclink href=Copying>Kopyalama</doclink>\n* <doclink href=UpgradeDoc>Yükseltme</doclink>",
        "config-env-good": "Ortam kontrol edildi.\nMediaWiki'yi kurabilirsiniz.",
        "config-env-bad": "Ortam kontrol edildi.\nMediaWiki'yi kuramazsınız.",
        "config-env-php": "PHP $1 kurulu.",
-       "config-env-php-toolow": "PHP $1 kurulu.\nAncak, MediaWiki PHP $2 ya da daha yenisine ihtiyaç duyuyor.",
        "config-unicode-using-utf8": "Unikod normalleştirmesi için Brion Vibber'in utf8_normalize.so kullanılıyor.",
        "config-unicode-using-intl": "Unikod normalleştirmesi için [http://pecl.php.net/intl intl PECL uzantısı] kullanılıyor.",
        "config-xml-bad": "PHP 'nin XML modülü eksik.\nMediaWiki bu modüldeki fonksiyonlara ihtiyaç duyar ve şimdiki kurulumda çalışmayacaktır.\nMandrake kullanıyorsanız php-xml paketini yükleyin.",
        "config-install-mainpage-failed": "Ana sayfa eklenemedi:$1",
        "config-download-localsettings": "İndir <code>LocalSettings.php</code>",
        "config-help": "Yardım",
+       "config-help-tooltip": "genişletmek için tıklayın",
        "config-nofile": "\"$1\" dosyası bulunamadı. Silindi mi?",
        "config-extension-link": "Vikinizin [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions eklentileri] desteklediğini biliyor musunuz?\n\n[//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category Eklentileri kategorilerine göre] inceleyebilir ya da tüm eklentilerin listesini görmek için [//www.mediawiki.org/wiki/Extension_Matrix Eklenti Matrisine] bakabilirsiniz.",
        "mainpagetext": "'''MediaWiki başarı ile kuruldu.'''",
index 2065352..a255cc1 100644 (file)
@@ -55,7 +55,6 @@
        "config-env-good": "Перевірку середовища успішно завершено.\nВи можете встановити MediaWiki.",
        "config-env-bad": "Було проведено перевірку середовища. Ви не можете встановити MediaWiki.",
        "config-env-php": "Встановлено версію PHP: $1.",
-       "config-env-php-toolow": "Встановлено PHP $1.\nНатомість MediaWiki вимагає PHP $2 і вище.",
        "config-unicode-using-utf8": "Використовувати utf8_normalize.so Брайона Віббера для нормалізації Юнікоду.",
        "config-unicode-using-intl": "Використовувати [http://pecl.php.net/intl міжнародне розширення PECL] для нормалізації Юнікоду.",
        "config-unicode-pure-php-warning": "'''Увага''': [http://pecl.php.net/intl міжнародне розширення PECL] не може провести нормалізацію Юнікоду.\nЯкщо ваш сайт має високий трафік, вам варто почитати про [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормалізацію Юнікоду].",
@@ -63,7 +62,7 @@
        "config-no-db": "Не вдалося знайти відповідний драйвер бази даних! Вам необхідно встановити драйвер бази даних для PHP. Підтримуються такі типи баз даних: $1.\n\nЯкщо ви скомпілювали PHP самостійно, переналаштуйте його з включенням клієнта бази даних, наприклад за допомогою <code>./configure --with-mysqli</code>.\n\nЯкщо установлено PHP з пакетів Debian або Ubuntu, тоді ви також повинні встановити, наприклад, пакунок <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Увага''': у Вас встановлена версія SQLite $1, а це нижче, ніж мінімально необхідна версія $2. SQLite буде недоступним.",
        "config-no-fts3": "'''Увага''': SQLite зібраний без [//sqlite.org/fts3.html модуля FTS3], функції пошуку не будуть працювати у цій системі.",
-       "config-register-globals": "'''Увага: Опція PHP <code>[http://php.net/register_globals register_globals]</code> увімкнена.'''\n'''Вимкніть її, якщо це можливо.'''\nMediaWiki буде працювати, але Ваш сервер буде більш вразливим до потенційного проникнення зовні.",
+       "config-register-globals-error": "<strong>Помилка: Опція PHP <code>[http://php.net/register_globals register_globals]</code> увімкнена.\nЩоб продовжити це встановлення, її треба вимкнути.</strong>\nДив. довідку, як це зробити, на [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals].",
        "config-magic-quotes-runtime": "'''Проблема: Опція PHP [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] увімкнена!'''\nЦя опція призводить до непередбачуваного пошкодження даних.\nВи не можете встановити і використовувати MediaWiki, поки не буде вимкнено цю опцію.",
        "config-magic-quotes-sybase": "'''Проблема: Опція PHP [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] увімкнена!'''\nЦя опція призводить до непередбачуваного пошкодження даних.\nВи не можете встановити і використовувати MediaWiki, поки не буде вимкнено цю опцію.",
        "config-mbstring": "'''Проблема: Опція PHP [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] увімкнена!'''\nЦя опція призводить до непередбачуваного пошкодження даних.\nВи не можете встановити і використовувати MediaWiki, поки не буде вимкнено цю опцію.",
        "config-license-gfdl": "GNU Free Documentation License 1.3 або пізніша",
        "config-license-pd": "Суспільне надбання (Public Domain)",
        "config-license-cc-choose": "Виберіть одну з ліцензій Creative Commons",
-       "config-license-help": "Чимало загальнодоступних вікі публікують увесь свій вміст під [http://freedomdefined.org/Definition вільною ліцензією]. Це розвиває відчуття спільної власності і заохочує довготривалу участь. У загальному випадку для приватної чи корпоративної вікі у цьому немає необхідності.\n\nЯкщо Ви хочете мати змогу використовувати текст з Вікіпедії і дати Вікіпедії змогу використовувати текст, скопійований з Вашої вікі, вам необхідно обрати '''Creative Commons Attribution Share Alike'''.\n\nРаніше Вікіпедія використовувала GNU Free Documentation License.\nGFDL — допустима ліцензія, але у ній важко розібратися, а контент під GFDL важко використовувати повторно.",
+       "config-license-help": "Чимало загальнодоступних вікі публікують увесь свій вміст під [http://freedomdefined.org/Definition вільною ліцензією]. Це розвиває відчуття спільної власності і заохочує довготривалу участь. У загальному випадку для приватної чи корпоративної вікі у цьому немає необхідності.\n\nЯкщо Ви хочете мати змогу використовувати текст з Вікіпедії і дати Вікіпедії змогу використовувати текст, скопійований з Вашої вікі, вам необхідно обрати <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nРаніше Вікіпедія використовувала GNU Free Documentation License.\nGFDL — допустима ліцензія, але у ній важко розібратися, а контент під GFDL важко використовувати повторно.",
        "config-email-settings": "Налаштування електронної пошти",
        "config-enable-email": "Увімкнути вихідну електронну пошту",
        "config-enable-email-help": "Якщо Ви хочете, що електронна пошта працювала, необхідно виставити коректні [http://www.php.net/manual/en/mail.configuration.php налаштування пошти у PHP].\nЯкщо Вам не потрібні жодні можливості електронної пошти у вікі, можете тут їх відключити.",
index f04fd5d..47749b7 100644 (file)
@@ -8,6 +8,7 @@
        "config-desc": "דער אינסטאלירער פאר מעדיעוויקי",
        "config-title": "מעדיעוויקי $1 אינסטאלירונג",
        "config-information": "אינפֿארמאציע",
+       "config-localsettings-badkey": "דעם שליסל וואס איר האט אײַנגעגעבן איז פאלש.",
        "config-session-error": "פֿעלער ביים אנהייבן סעסיע:$1",
        "config-your-language": "אײַער שפראך:",
        "config-your-language-help": "קלויבט א שפראך צו ניצן ביים אינסטאלירונג פראצעס.",
@@ -29,6 +30,9 @@
        "config-page-releasenotes": "ווערסיע־הערות",
        "config-page-copying": "קאפיע",
        "config-page-upgradedoc": "ראנג־העכערן",
+       "config-page-existingwiki": "עקזיסטירנדע וויקי",
+       "config-help-restart": "צי ווילט איר אפראמען די גארע געשפייכלערטע דאטן וואס איר האט אײַנגעגעבן און ווידער אנהייבן דעם אינסטאלאציע־פראצעס?",
+       "config-restart": "יא, ווידעראמאל אנהייבן",
        "config-env-php": "PHP $1 איז אינצטאלירט.",
        "config-apc": "[http://www.php.net/apc APC] איז אינסטאלירט",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] איז אינסטאלירט",
index fcb7a3e..f9a5fd7 100644 (file)
@@ -19,7 +19,9 @@
                        "Qiyue2001",
                        "Kuailong",
                        "Zjzengdongyang",
-                       "Mywood"
+                       "Mywood",
+                       "Impersonator 1",
+                       "Fengchao"
                ]
        },
        "config-desc": "MediaWiki安装程序",
@@ -64,7 +66,6 @@
        "config-env-good": "环境检查已经完成。您可以安装MediaWiki。",
        "config-env-bad": "环境检查已经完成。您不能安装MediaWiki。",
        "config-env-php": "PHP $1已安装。",
-       "config-env-php-toolow": "已安装PHP $1;但是,MediaWiki需要PHP $2或更高版本。",
        "config-unicode-using-utf8": "使用Brion Vibber的utf8_normalize.so实现Unicode正常化。",
        "config-unicode-using-intl": "使用[http://pecl.php.net/intl intl PECL扩展程序]标准化Unicode。",
        "config-unicode-pure-php-warning": "<strong>警告:</strong>因为尚未安装 [http://pecl.php.net/intl intl PECL 扩展]以处理 Unicode 正常化,故只能退而采用运行较慢的纯 PHP 实现的方法。\n如果您运行着一个高流量的站点,请参阅 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode 正常化]一文。",
@@ -72,7 +73,6 @@
        "config-no-db": "找不到合适的数据库驱动!您需要为PHP安装数据库驱动。目前支持以下数据库:$1。如果您是自己编译的PHP,请重新配置他与数据库客户端将其启用,诸如,使用<code>./configure --with-mysqli</code>。如果您从Debian或Ubuntu包安装了PHP,之后您仍需要安装诸如<code>php5-mysql</code>包。",
        "config-outdated-sqlite": "'''警告''':您已安装SQLite $1,但是它的版本低于最低要求版本$2。因此您无法选择SQLite。",
        "config-no-fts3": "'''警告''':已编译的SQLite不包含[//sqlite.org/fts3.html FTS3模块],后台搜索功能将不可用。",
-       "config-register-globals": "'''警告:PHP的<code>[http://php.net/register_globals register_globals]</code>选项被启用。请尽量禁用该功能,'''虽然不会影响MediaWiki的运行,但您的服务器会被暴露给潜在的安全漏洞。",
        "config-magic-quotes-runtime": "'''毁灭性错误:[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]已启用!'''\n此选项会无法预测地破坏输入的数据,请将其禁用,否则您将不能安装或使用MediaWiki。",
        "config-magic-quotes-sybase": "'''毁灭性错误:[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_sybase]已启用!'''\n此选项会无法预测地破坏输入的数据,请将其禁用,否则您将不能安装或使用MediaWiki。",
        "config-mbstring": "'''毁灭性错误:[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]已启用!'''\n此选项会导致错误并不可预测地破坏数据,请将其禁用,否则您将不能安装或使用MediaWiki。",
        "config-profile-help": "如果您允许尽量多的人编写wiki,网站上的内容会更加丰富。在MediaWiki中,您可以轻松地审查最近更改,并轻易回退掉新手或破坏者造成的损害。\n\n然而,许多人觉得让MediaWiki存在多种角色将更加好用;同时,要说服所有人都愿以wiki的方式作贡献并非一件易事。因此,您可以有以下选择:\n\n'''{{int:config-profile-wiki}}'''允许包括未登录用户在内的所有人编辑。'''{{int:config-profile-no-anon}}'''的wiki需要额外的注册流程,这有可能会阻碍随意贡献者。\n\n'''{{int:config-profile-fishbowl}}'''模式只允许获批准的用户编辑,但对公众开放页面浏览(包括历史记录)。'''{{int:config-profile-private}}'''则只允许获批准的用户浏览、编辑页面。\n\n安装完成后,您还可以对用户权限进行更多、更复杂的配置,参见[//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights 相关的使用手册]。",
        "config-license": "版权和许可证:",
        "config-license-none": "页脚无许可证",
-       "config-license-cc-by-sa": "ç\9f¥è¯\86å\85±äº«ç½²å\90\8d\9b¸å\90\8cæ\96¹å¼\8få\88\86享",
+       "config-license-cc-by-sa": "ç\9f¥è¯\86å\85±äº«ç½²å\90\8d\9b¸å\90\8cæ\96¹å¼\8få\85±享",
        "config-license-cc-by": "知识共享署名",
        "config-license-cc-by-nc-sa": "知识共享署名-非商业性使用-相同方式共享",
        "config-license-cc-0": "知识共享Zero(公有领域)",
        "config-license-gfdl": "GNU自由文档许可证1.3或更高版本",
        "config-license-pd": "公有领域",
        "config-license-cc-choose": "选择自定义的知识共享许可证",
-       "config-license-help": "许多公共wiki会以[http://freedomdefined.org/Definition 自由许可证]的方式释放出编者的所有贡献。这有助于构建社区的主人翁意识,并能鼓励长期贡献。对于非公共wiki或公司wiki,这并非必要条件。\n\n如果您希望使用来自维基百科的内容,并希望维基百科能接受复制自您的wiki的内容,请选择'''知识共享署名-相同方式共享'''。\n\nGNU自由文档许可证是维基百科曾经使用过的许可证,并迄今有效。然而,该许可证难以理解,并会增加重用内容的难度。",
+       "config-license-help": "许多公共wiki将所有用户贡献置于[http://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": "如果您希望使用电子邮件功能,请正确配置[http://www.php.net/manual/en/mail.configuration.php PHP的邮件设定]。如果您不需要任何电子邮件功能,请在此处禁用它。",
        "config-memcache-badport": "Memcached的端口号应该在$1到$2之间。",
        "config-extensions": "扩展程序",
        "config-extensions-help": "已在您的<code>./extensions</code>目录中发现下列扩展。\n\n您可能要对它们进行额外的配置,但您现在可以启用它们。",
+       "config-skins": "皮肤",
        "config-install-alreadydone": "'''警告:'''您似乎已经安装了MediaWiki,并试图重新安装它。请前往下一个页面。",
        "config-install-begin": "点击“{{int:config-continue}}”后,您将开始安装MediaWiki。如果您还想对配置作一些修改,请点击“{{int:config-back}}”。",
        "config-install-step-done": "完成",
index a6e87cf..8342653 100644 (file)
@@ -55,7 +55,6 @@
        "config-env-good": "環境檢查已完成。\n您可以安裝 MediaWiki。",
        "config-env-bad": "環境檢查已完成。\n您無法安裝 MediaWiki。",
        "config-env-php": "PHP $1 已安裝。",
-       "config-env-php-toolow": "已安裝 PHP $1。\n但 MediaWiki 需要 PHP $2 或更新的版本。",
        "config-unicode-using-utf8": "使用 Brion Vibber 的 utf8_normalize.so 做 Unicode 正規化。",
        "config-unicode-using-intl": "使用 [http://pecl.php.net/intl intl PECL 擴充套件] 做 Unicode 正規化。",
        "config-unicode-pure-php-warning": "<strong>警告:</strong> 無法使用 [http://pecl.php.net/intl intl PECL 擴充套件] 處理 Unicode 正規化,故回退使用純 PHP 實作的正規化程式,此方式處理速度較緩慢。\n\n如果您的網站瀏覽人次很高,您應先閱讀 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/zh Unicode 正規化]。",
@@ -63,7 +62,7 @@
        "config-no-db": "找不到合適的資料庫驅動程式!您需要安裝 PHP 資料庫驅動程式。\n目前支援以下類型的資料庫: $1 。\n\n如果您是自行編譯 PHP,您必須重新設定並開啟資料庫客戶端,例:使用 <code>./configure --with-mysqli</code> 指令參數。\n如果您是使用 Debian 或 Ubuntu 的套件安裝,您則需要額外安裝,例:<code>php5-mysql</code> 套件。",
        "config-outdated-sqlite": "<strong>警告:</strong>您已安裝 SQLite $1,但是它的版本低於最低需求版本 $2。 因此您無法使用 SQLite。",
        "config-no-fts3": "<strong>警告:</strong> SQLite 編譯時未包含 [//sqlite.org/fts3.html FTS3 模組],後台搜尋功能將無法使用。",
-       "config-register-globals": "<strong>警告:PHP 的<code>[http://php.net/register_globals register_globals]</code>選項已開啟,如果可以請關閉該選項。</strong>\nMediaWiki 仍可正常執行,但您的伺服器將會有潛藏的安全性問題。",
+       "config-register-globals-error": "<strong>錯誤:PHP 的 <code>[http://php.net/register_globals register_globals]</code> 選項已開啟。\n要繼續安裝程序必須關閉該選項。</strong>\n請參考 [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] 以取得操作說明。",
        "config-magic-quotes-runtime": "<strong>嚴重:[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] 選項被開啟!</strong>\n此選項會導致資料在無法預測的情況下損壞。\n您必須將開選項關閉方可繼續安裝 MediaWiki。",
        "config-magic-quotes-sybase": "<strong>嚴重:[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] 選項被開啟!</strong>\n此選項會導致資料在無法預測的情況下損壞。\n您必須將開選項關閉方可繼續安裝 MediaWiki。",
        "config-mbstring": "<strong>嚴重:[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] 選項被開啟!</strong>\n此選項會導致資料在無法預測的情況下損壞。\n您必須將開選項關閉方可繼續安裝 MediaWiki。",
        "config-license-gfdl": "GNU 自由文件授權條款 1.3 或更高版本",
        "config-license-pd": "公共領域",
        "config-license-cc-choose": "請選擇一個自訂的創作共用授權條款",
-       "config-license-help": "許多開放式 Wiki 會以 [http://freedomdefined.org/Definition 自由授權條款] 的方式釋放出編者的所有貢獻,這有助於構建社群的所有權,並且能鼓勵長期貢獻。對於封閉式的 Wiki 或公司 Wiki,則是非必要的。\n\n如果您希望使用來自維基百科(Wikipedia)的內容,並希望維基百科能接受您的 Wiki 內容,請應選擇 <strong>創作共用 Attribution Share Alike</strong> 授權條款。\n\n維基百科̽(Wikipedia)先前是使用 GNU 自由文件授權條款,\n但該授權條款的內容較難理解,因此較難再利用在該條款底下的內容。",
+       "config-license-help": "許多開放式 Wiki 會以 [http://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": "如果您要使用電子郵件功能,請正確設定 [http://www.php.net/manual/en/mail.configuration.php PHP 的郵件設定]。\n如果您不需要使用電子郵件功能,請在此處關閉。",
index 35b4f13..c11df93 100644 (file)
@@ -291,7 +291,7 @@ abstract class Job implements IJobSpecification {
         * @return string
         */
        public function toString() {
-               $truncFunc = function( $value ) {
+               $truncFunc = function ( $value ) {
                        $value = (string)$value;
                        if ( mb_strlen( $value ) > 1024 ) {
                                $value = "string(" . mb_strlen( $value ) . ")";
index 6739a84..522bae1 100644 (file)
@@ -62,9 +62,10 @@ class JobQueueRedis extends JobQueue {
 
        /** @var string Server address */
        protected $server;
-
        /** @var string Compression method to use */
        protected $compression;
+       /** @var bool */
+       protected $daemonized;
 
        const MAX_AGE_PRUNE = 604800; // integer; seconds a job can live once claimed (7 days)
 
@@ -79,6 +80,9 @@ class JobQueueRedis extends JobQueue {
         *                   If a hostname is specified but no port, the standard port number
         *                   6379 will be used. Required.
         *   - compression : The type of compression to use; one of (none,gzip).
+        *   - daemonized  : Set to true if the redisJobRunnerService runs in the background.
+        *                   This will disable job recycling/undelaying from the MediaWiki side
+        *                   to avoid redundance and out-of-sync configuration.
         * @param array $params
         */
        public function __construct( array $params ) {
@@ -87,6 +91,7 @@ class JobQueueRedis extends JobQueue {
                $this->server = $params['redisServer'];
                $this->compression = isset( $params['compression'] ) ? $params['compression'] : 'none';
                $this->redisPool = RedisConnectionPool::singleton( $params['redisConfig'] );
+               $this->daemonized = !empty( $params['daemonized'] );
        }
 
        protected function supportedOrders() {
@@ -313,7 +318,7 @@ LUA;
                                } else {
                                        $blob = $this->popAndDeleteBlob( $conn );
                                }
-                               if ( $blob === false ) {
+                               if ( !is_string( $blob ) ) {
                                        break; // no jobs; nothing to do
                                }
 
@@ -703,6 +708,7 @@ LUA;
                                $count += $released + $pruned + $undelayed;
                                JobQueue::incrStats( 'job-recycle', $this->type, $released, $this->wiki );
                                JobQueue::incrStats( 'job-abandon', $this->type, $abandoned, $this->wiki );
+                               JobQueue::incrStats( 'job-undelay', $this->type, $undelayed, $this->wiki );
                        }
                } catch ( RedisException $e ) {
                        $this->throwRedisException( $conn, $e );
@@ -715,6 +721,9 @@ LUA;
         * @return array
         */
        protected function doGetPeriodicTasks() {
+               if ( $this->daemonized ) {
+                       return array(); // managed in the runner loop
+               }
                $periods = array( 3600 ); // standard cleanup (useful on config change)
                if ( $this->claimTTL > 0 ) {
                        $periods[] = ceil( $this->claimTTL / 2 ); // avoid bad timing
index df9ae39..e8e8e30 100644 (file)
@@ -50,6 +50,7 @@ class JobQueueAggregatorRedis extends JobQueueAggregator {
                $this->servers = isset( $params['redisServers'] )
                        ? $params['redisServers']
                        : array( $params['redisServer'] ); // b/c
+               $params['redisConfig']['serializer'] = 'none';
                $this->redisPool = RedisConnectionPool::singleton( $params['redisConfig'] );
        }
 
@@ -94,18 +95,16 @@ class JobQueueAggregatorRedis extends JobQueueAggregator {
                        return array();
                }
                try {
-                       $conn->multi( Redis::PIPELINE );
-                       $conn->exists( $this->getReadyQueueKey() );
-                       $conn->hGetAll( $this->getReadyQueueKey() );
-                       list( $exists, $map ) = $conn->exec();
+                       $map = $conn->hGetAll( $this->getReadyQueueKey() );
 
-                       if ( $exists ) { // cache hit
+                       if ( is_array( $map ) && isset( $map['_epoch'] ) ) {
+                               unset( $map['_epoch'] ); // ignore
                                $pendingDBs = array(); // (type => list of wikis)
                                foreach ( $map as $key => $time ) {
                                        list( $type, $wiki ) = $this->dencQueueName( $key );
                                        $pendingDBs[$type][] = $wiki;
                                }
-                       } else { // cache miss
+                       } else {
                                // Avoid duplicated effort
                                $rand = wfRandomString( 32 );
                                $conn->multi( Redis::MULTI );
@@ -120,7 +119,7 @@ class JobQueueAggregatorRedis extends JobQueueAggregator {
 
                                $conn->multi( Redis::PIPELINE );
                                $now = time();
-                               $map = array();
+                               $map = array( '_epoch' => time() ); // dummy key for empty Redis collections
                                foreach ( $pendingDBs as $type => $wikis ) {
                                        $conn->hSetNx( $this->getQueueTypesKey(), $type, 'enabled' );
                                        foreach ( $wikis as $wiki ) {
@@ -189,14 +188,14 @@ class JobQueueAggregatorRedis extends JobQueueAggregator {
         * @return string
         */
        private function getReadyQueueKey() {
-               return "jobqueue:aggregator:h-ready-queues:v1"; // global
+               return "jobqueue:aggregator:h-ready-queues:v2"; // global
        }
 
        /**
         * @return string
         */
        private function getQueueTypesKey() {
-               return "jobqueue:aggregator:h-queue-types:v1"; // global
+               return "jobqueue:aggregator:h-queue-types:v2"; // global
        }
 
        /**
index 6b10ae4..4885ae6 100644 (file)
@@ -163,6 +163,8 @@ class CSSMin {
         * Build a CSS 'url()' value for the given URL, quoting parentheses (and other funny characters)
         * and escaping quotes as necessary.
         *
+        * See http://www.w3.org/TR/css-syntax-3/#consume-a-url-token
+        *
         * @param string $url URL to process
         * @return string 'url()' value, usually just `"url($url)"`, quoted/escaped if necessary
         */
index df99098..2022b22 100644 (file)
@@ -198,7 +198,7 @@ class HashRing {
                        }
                }
                if ( !$this->liveRing ) {
-                       throw UnexpectedValueException( "The live ring is currently empty." );
+                       throw new UnexpectedValueException( "The live ring is currently empty." );
                }
 
                return $this->liveRing;
index d72ffca..809bfdf 100644 (file)
@@ -28,8 +28,6 @@ class HttpStatus {
        /**
         * Get the message associated with HTTP response code $code
         *
-        * Replace OutputPage::getStatusMessage( $code )
-        *
         * @param $code Integer: status code
         * @return String or null: message or null if $code is not in the list of
         *         messages
index 4ce8070..4dc25ef 100644 (file)
@@ -355,9 +355,13 @@ class LogEventsList extends ContextSource {
                // Don't show useless checkbox to people who cannot hide log entries
                if ( $user->isAllowed( 'deletedhistory' ) ) {
                        $canHide = $user->isAllowed( 'deletelogentry' );
+                       $canViewSuppressedOnly = $user->isAllowed( 'viewsuppressed' ) &&
+                               !$user->isAllowed( 'suppressrevision' );
+                       $entryIsSuppressed = self::isDeleted( $row, LogPage::DELETED_RESTRICTED );
+                       $canViewThisSuppressedEntry = $canViewSuppressedOnly && $entryIsSuppressed;
                        if ( $row->log_deleted || $canHide ) {
                                // Show checkboxes instead of links.
-                               if ( $canHide && $this->flags & self::USE_REVDEL_CHECKBOXES ) {
+                               if ( $canHide && $this->flags & self::USE_REVDEL_CHECKBOXES && !$canViewThisSuppressedEntry ) {
                                        // If event was hidden from sysops
                                        if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) {
                                                $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) );
@@ -380,8 +384,8 @@ class LogEventsList extends ContextSource {
                                                );
                                                $del = Linker::revDeleteLink(
                                                        $query,
-                                                       self::isDeleted( $row, LogPage::DELETED_RESTRICTED ),
-                                                       $canHide
+                                                       $entryIsSuppressed,
+                                                       $canHide && !$canViewThisSuppressedEntry
                                                );
                                        }
                                }
@@ -437,20 +441,19 @@ class LogEventsList extends ContextSource {
         */
        public static function userCanBitfield( $bitfield, $field, User $user = null ) {
                if ( $bitfield & $field ) {
-                       if ( $bitfield & LogPage::DELETED_RESTRICTED ) {
-                               $permission = 'suppressrevision';
-                       } else {
-                               $permission = 'deletedhistory';
-                       }
-                       wfDebug( "Checking for $permission due to $field match on $bitfield\n" );
                        if ( $user === null ) {
                                global $wgUser;
                                $user = $wgUser;
                        }
-
-                       return $user->isAllowed( $permission );
+                       if ( $bitfield & LogPage::DELETED_RESTRICTED ) {
+                               $permissions = array( 'suppressrevision', 'viewsuppressed' );
+                       } else {
+                               $permissions = array( 'deletedhistory' );
+                       }
+                       $permissionlist = implode( ', ', $permissions );
+                       wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" );
+                       return call_user_func_array( array( $user, 'isAllowedAny' ), $permissions );
                }
-
                return true;
        }
 
index 399c799..256934e 100644 (file)
@@ -175,7 +175,7 @@ class LogPager extends ReverseChronologicalPager {
                $user = $this->getUser();
                if ( !$user->isAllowed( 'deletedhistory' ) ) {
                        $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::DELETED_USER ) . ' = 0';
-               } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                        $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::SUPPRESSED_USER ) .
                                ' != ' . LogPage::SUPPRESSED_USER;
                }
@@ -207,6 +207,18 @@ class LogPager extends ReverseChronologicalPager {
                $ns = $title->getNamespace();
                $db = $this->mDb;
 
+               $doUserRightsLogLike = false;
+               if ( $this->types == array( 'rights' ) ) {
+                       global $wgUserrightsInterwikiDelimiter;
+                       $parts = explode( $wgUserrightsInterwikiDelimiter, $title->getDBKey() );
+                       if ( count( $parts ) == 2 ) {
+                               list( $name, $database ) = array_map( 'trim', $parts );
+                               if ( strstr( $database, '*' ) ) { // Search for wildcard in database name
+                                       $doUserRightsLogLike = true;
+                               }
+                       }
+               }
+
                # Using the (log_namespace, log_title, log_timestamp) index with a
                # range scan (LIKE) on the first two parts, instead of simple equality,
                # makes it unusable for sorting.  Sorted retrieval using another index
@@ -218,12 +230,19 @@ class LogPager extends ReverseChronologicalPager {
                # use the page_time index.  That should have no more than a few hundred
                # log entries for even the busiest pages, so it can be safely scanned
                # in full to satisfy an impossible condition on user or similar.
-               if ( $pattern && !$wgMiserMode ) {
-                       $this->mConds['log_namespace'] = $ns;
-                       $this->mConds[] = 'log_title ' . $db->buildLike( $title->getDBkey(), $db->anyString() );
+               $this->mConds['log_namespace'] = $ns;
+               if ( $doUserRightsLogLike ) {
+                       $params = array( $name . $wgUserrightsInterwikiDelimiter );
+                       foreach ( explode( '*', $database ) as $databasepart ) {
+                               $params[] = $databasepart;
+                               $params[] = $db->anyString();
+                       }
+                       array_pop( $params ); // Get rid of the last % we added.
+                       $this->mConds[] = 'log_title' . $db->buildLike( $params );
+               } elseif ( $pattern && !$wgMiserMode ) {
+                       $this->mConds[] = 'log_title' . $db->buildLike( $title->getDBkey(), $db->anyString() );
                        $this->pattern = $pattern;
                } else {
-                       $this->mConds['log_namespace'] = $ns;
                        $this->mConds['log_title'] = $title->getDBkey();
                }
                // Paranoia: avoid brute force searches (bug 17342)
index bcef433..4f2a565 100644 (file)
@@ -30,7 +30,7 @@ class PatrolLog {
        /**
         * Record a log event for a change being patrolled
         *
-        * @param mixed $rc Change identifier or RecentChange object
+        * @param int|RecentChange $rc Change identifier or RecentChange object
         * @param bool $auto Was this patrol event automatic?
         * @param User $user User performing the action or null to use $wgUser
         *
index 44be178..c0d9b71 100644 (file)
@@ -117,6 +117,7 @@ class BitmapHandler extends ImageHandler {
                if ( !$this->normaliseParams( $image, $params ) ) {
                        return new TransformParameterError( $params );
                }
+
                # Create a parameter array to pass to the scaler
                $scalerParams = array(
                        # The size to which the image will be resized
@@ -187,7 +188,12 @@ class BitmapHandler extends ImageHandler {
                }
 
                # Transform functions and binaries need a FS source file
-               $scalerParams['srcPath'] = $image->getLocalRefPath();
+               $thumbnailSource = $image->getThumbnailSource( $params );
+
+               $scalerParams['srcPath'] = $thumbnailSource['path'];
+               $scalerParams['srcWidth'] = $thumbnailSource['width'];
+               $scalerParams['srcHeight'] = $thumbnailSource['height'];
+
                if ( $scalerParams['srcPath'] === false ) { // Failed to get local copy
                        wfDebugLog( 'thumbnail',
                                sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"',
@@ -354,7 +360,30 @@ class BitmapHandler extends ImageHandler {
                                }
                        }
                } elseif ( $params['mimeType'] == 'image/x-xcf' ) {
-                       $animation_post = array( '-layers', 'merge' );
+                       // Before merging layers, we need to set the background
+                       // to be transparent to preserve alpha, as -layers merge
+                       // merges all layers on to a canvas filled with the
+                       // background colour. After merging we reset the background
+                       // to be white for the default background colour setting
+                       // in the PNG image (which is used in old IE)
+                       $animation_pre = array(
+                               '-background', 'transparent',
+                               '-layers', 'merge',
+                               '-background', 'white',
+                       );
+                       wfSuppressWarnings();
+                       $xcfMeta = unserialize( $image->getMetadata() );
+                       wfRestoreWarnings();
+                       if ( $xcfMeta
+                               && isset( $xcfMeta['colorType'] )
+                               && $xcfMeta['colorType'] === 'greyscale-alpha'
+                               && version_compare( $this->getMagickVersion(), "6.8.9-3" ) < 0
+                       ) {
+                               // bug 66323 - Greyscale images not rendered properly.
+                               // So only take the "red" channel.
+                               $channelOnly = array( '-channel', 'R', '-separate' );
+                               $animation_pre = array_merge( $animation_pre, $channelOnly );
+                       }
                }
 
                // Use one thread only, to avoid deadlock bugs on OOM
@@ -845,7 +874,7 @@ class BitmapHandler extends ImageHandler {
        }
 
        /**
-        * Rerurns whether the file needs to be rendered. Returns true if the
+        * Returns whether the file needs to be rendered. Returns true if the
         * file requires rotation and we are able to rotate it.
         *
         * @param File $file
index 200d526..299252b 100644 (file)
@@ -188,7 +188,7 @@ class DjVuHandler extends ImageHandler {
                if ( $image->getSize() >= 1e7 ) { // 10MB
                        $work = new PoolCounterWorkViaCallback( 'GetLocalFileCopy', sha1( $image->getName() ),
                                array(
-                                       'doWork' => function() use ( $image ) {
+                                       'doWork' => function () use ( $image ) {
                                                return $image->getLocalRefPath();
                                        }
                                )
index b39e042..d630136 100644 (file)
@@ -470,8 +470,6 @@ class Exif {
                                        $charset = "";
                                        break;
                        }
-                       // This could possibly check to see if iconv is really installed
-                       // or if we're using the compatibility wrapper in globalFunctions.php
                        if ( $charset ) {
                                wfSuppressWarnings();
                                $val = iconv( $charset, 'UTF-8//IGNORE', $val );
index fca1c6d..4200541 100644 (file)
@@ -1302,7 +1302,6 @@ class FormatMetadata extends ContextSource {
         * @param int $a Numerator
         * @param int $b Denominator
         * @return int
-        * @private
         */
        private function gcd( $a, $b ) {
                /*
@@ -1871,29 +1870,3 @@ class FormatMetadata extends ContextSource {
                return $priorityLanguages;
        }
 }
-
-/** For compatability with old FormatExif class
- * which some extensions use.
- *
- * @deprecated since 1.18
- *
- */
-class FormatExif {
-       /** @var array */
-       private $meta;
-
-       /**
-        * @param array $meta
-        */
-       function __construct( $meta ) {
-               wfDeprecated( __METHOD__, '1.18' );
-               $this->meta = $meta;
-       }
-
-       /**
-        * @return array
-        */
-       function getFormattedData() {
-               return FormatMetadata::getFormattedData( $this->meta );
-       }
-}
index 8a12e7e..6dd0453 100644 (file)
@@ -269,4 +269,20 @@ abstract class ImageHandler extends MediaHandler {
                                ->numParams( $file->getWidth(), $file->getHeight() )->text();
                }
        }
+
+       public function sanitizeParamsForBucketing( $params ) {
+               $params = parent::sanitizeParamsForBucketing( $params );
+
+               // We unset the height parameters in order to let normaliseParams recalculate them
+               // Otherwise there might be a height discrepancy
+               if ( isset( $params['height'] ) ) {
+                       unset( $params['height'] );
+               }
+
+               if ( isset( $params['physicalHeight'] ) ) {
+                       unset( $params['physicalHeight'] );
+               }
+
+               return $params;
+       }
 }
index a0f7acb..918d4ae 100644 (file)
@@ -158,4 +158,19 @@ class JpegHandler extends ExifBitmapHandler {
                        return parent::rotate( $file, $params );
                }
        }
+
+       public function supportsBucketing() {
+               return true;
+       }
+
+       public function sanitizeParamsForBucketing( $params ) {
+               $params = parent::sanitizeParamsForBucketing( $params );
+
+               // Quality needs to be cleared for bucketing. Buckets need to be default quality
+               if ( isset( $params['quality'] ) ) {
+                       unset( $params['quality'] );
+               }
+
+               return $params;
+       }
 }
index f6717cd..2612685 100644 (file)
@@ -56,6 +56,7 @@ abstract class MediaHandler {
                if ( !isset( self::$handlers[$class] ) ) {
                        self::$handlers[$class] = new $class;
                        if ( !self::$handlers[$class]->isEnabled() ) {
+                               wfDebug( __METHOD__ . ": $class is not enabled\n" );
                                self::$handlers[$class] = false;
                        }
                }
@@ -63,6 +64,13 @@ abstract class MediaHandler {
                return self::$handlers[$class];
        }
 
+       /**
+        * Resets all static caches
+        */
+       public static function resetCache() {
+               self::$handlers = array();
+       }
+
        /**
         * Get an associative array mapping magic word IDs to parameter names.
         * Will be used by the parser to identify parameters.
@@ -831,4 +839,24 @@ abstract class MediaHandler {
        public function isExpensiveToThumbnail( $file ) {
                return false;
        }
+
+       /**
+        * Returns whether or not this handler supports the chained generation of thumbnails according
+        * to buckets
+        * @return boolean
+        * @since  1.24
+        */
+       public function supportsBucketing() {
+               return false;
+       }
+
+       /**
+        * Returns a normalised params array for which parameters have been cleaned up for bucketing
+        * purposes
+        * @param array $params
+        * @return array
+        */
+       public function sanitizeParamsForBucketing( $params ) {
+               return $params;
+       }
 }
index 968db10..d879c12 100644 (file)
@@ -173,4 +173,8 @@ class PNGHandler extends BitmapHandler {
 
                return $wgLang->commaList( $info );
        }
+
+       public function supportsBucketing() {
+               return true;
+       }
 }
index 41e6f03..9e69137 100644 (file)
@@ -61,7 +61,28 @@ class XCFHandler extends BitmapHandler {
         * @return array
         */
        function getImageSize( $image, $filename ) {
-               return self::getXCFMetaData( $filename );
+               $header = self::getXCFMetaData( $filename );
+               if ( !$header ) {
+                       return false;
+               }
+
+               # Forge a return array containing metadata information just like getimagesize()
+               # See PHP documentation at: http://www.php.net/getimagesize
+               $metadata = array();
+               $metadata[0] = $header['width'];
+               $metadata[1] = $header['height'];
+               $metadata[2] = null; # IMAGETYPE constant, none exist for XCF.
+               $metadata[3] = sprintf(
+                       'height="%s" width="%s"', $header['height'], $header['width']
+               );
+               $metadata['mime'] = 'image/x-xcf';
+               $metadata['channels'] = null;
+               $metadata['bits'] = 8; # Always 8-bits per color
+
+               assert( '7 == count($metadata); ' .
+                       '# return array must contains 7 elements just like getimagesize() return' );
+
+               return $metadata;
        }
 
        /**
@@ -124,23 +145,61 @@ class XCFHandler extends BitmapHandler {
                wfDebug( __METHOD__ .
                        ": canvas size of '$filename' is {$header['width']} x {$header['height']} px\n" );
 
-               # Forge a return array containing metadata information just like getimagesize()
-               # See PHP documentation at: http://www.php.net/getimagesize
+               return $header;
+       }
+
+       /**
+        * Store the channel type
+        *
+        * Greyscale files need different command line options.
+        *
+        * @param File $file The image object, or false if there isn't one.
+        *   Warning, FSFile::getPropsFromPath might pass an (object)array() instead (!)
+        * @param string $path The filename
+        * @return string
+        */
+       public function getMetadata( $file, $filename ) {
+               $header = self::getXCFMetadata( $filename );
                $metadata = array();
-               $metadata[0] = $header['width'];
-               $metadata[1] = $header['height'];
-               $metadata[2] = null; # IMAGETYPE constant, none exist for XCF.
-               $metadata[3] = sprintf(
-                       'height="%s" width="%s"', $header['height'], $header['width']
-               );
-               $metadata['mime'] = 'image/x-xcf';
-               $metadata['channels'] = null;
-               $metadata['bits'] = 8; # Always 8-bits per color
+               if ( $header ) {
+                       // Try to be consistent with the names used by PNG files.
+                       // Unclear from base media type if it has an alpha layer,
+                       // so just assume that it does since it "potentially" could.
+                       switch ( $header['base_type'] ) {
+                       case 0:
+                               $metadata['colorType'] = 'truecolour-alpha';
+                               break;
+                       case 1:
+                               $metadata['colorType'] = 'greyscale-alpha';
+                               break;
+                       case 2:
+                               $metadata['colorType'] = 'index-coloured';
+                               break;
+                       default:
+                               $metadata['colorType'] = 'unknown';
 
-               assert( '7 == count($metadata); ' .
-                       '# return array must contains 7 elements just like getimagesize() return' );
+                       }
+               } else {
+                       // Marker to prevent repeated attempted extraction
+                       $metadata['error'] = true;
+               }
+               return serialize( $metadata );
+       }
 
-               return $metadata;
+       /**
+        * Should we refresh the metadata
+        *
+        * @param File $file The file object for the file in question
+        * @param string $metadata Serialized metadata
+        * @return bool One of the self::METADATA_(BAD|GOOD|COMPATIBLE) constants
+        */
+       public function isMetadataValid( $file, $metadata ) {
+               if ( !$metadata ) {
+                       // Old metadata when we just put an empty string in there
+                       return self::METADATA_BAD;
+               } else {
+                       return self::METADATA_GOOD;
+               }
        }
 
        /**
@@ -153,4 +212,20 @@ class XCFHandler extends BitmapHandler {
        protected static function getScalerType( $dstPath, $checkDstPath = true ) {
                return "im";
        }
+
+       /**
+        * Can we render this file?
+        *
+        * Image magick doesn't support indexed xcf files as of current
+        * writing (as of 6.8.9-3)
+        */
+       public function canRender( $file ) {
+               wfSuppressWarnings();
+               $xcfMeta = unserialize( $file->getMetadata() );
+               wfRestoreWarnings();
+               if ( isset( $xcfMeta['colorType'] ) && $xcfMeta['colorType'] === 'index-coloured' ) {
+                       return false;
+               }
+               return parent::canRender( $file );
+       }
 }
index 55d5319..a74b701 100644 (file)
@@ -23,7 +23,7 @@
 
 /**
  * Class for reading xmp data containing properties relevant to
- * images, and spitting out an array that FormatExif accepts.
+ * images, and spitting out an array that FormatMetadata accepts.
  *
  * Note, this is not meant to recognize every possible thing you can
  * encode in XMP. It should recognize all the properties we want.
index c798187..7a4de3b 100644 (file)
@@ -65,6 +65,9 @@ text/plain    [TEXT]
 text/html application/xhtml+xml        [TEXT]
 application/xml text/xml       [TEXT]
 text   [TEXT]
+application/json       [TEXT]
+text/csv       [TEXT]
+text/tab-separated-values      [TEXT]
 
 application/zip application/x-zip      [ARCHIVE]
 application/x-gzip     [ARCHIVE]
@@ -108,3 +111,8 @@ application/vnd.ms-excel.template.macroEnabled.12                           [OFFICE]
 application/vnd.ms-excel.addin.macroEnabled.12                                 [OFFICE]
 application/vnd.ms-excel.sheet.binary.macroEnabled.12                          [OFFICE]
 application/acad application/x-acad application/autocad_dwg image/x-dwg application/dwg application/x-dwg application/x-autocad image/vnd.dwg drawing/dwg [DRAWING]
+chemical/x-mdl-molfile     [DRAWING]
+chemical/x-mdl-sdfile      [DRAWING]
+chemical/x-mdl-rxnfile     [DRAWING]
+chemical/x-mdl-rdfile      [DRAWING]
+chemical/x-mdl-rgfile      [DRAWING]
index 61f7ff5..ae6ca4d 100644 (file)
@@ -35,6 +35,7 @@ application/x-gzip gz
 application/x-hdf hdf
 application/x-jar jar
 application/x-javascript js
+application/json json
 application/x-koan skp skd skt skm
 application/x-latex latex
 application/x-netcdf nc cdf
@@ -109,6 +110,7 @@ model/mesh msh mesh silo
 model/vrml wrl vrml
 text/calendar ics ifb
 text/css css
+text/csv csv
 text/html html htm
 text/plain txt
 text/richtext rtx
@@ -169,3 +171,8 @@ application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb
 model/vnd.dwfx+xps dwfx
 application/vnd.ms-xpsdocument xps
 application/x-opc+zip docx dotx docm dotm potx ppsx pptx ppam pptm potm ppsm xlsx xltx xlsm xltm xlam xlsb dwfx xps
+chemical/x-mdl-molfile mol
+chemical/x-mdl-sdfile sdf
+chemical/x-mdl-rxnfile rxn
+chemical/x-mdl-rdfile rd
+chemical/x-mdl-rgfile rg
index bd4cf05..bd2bc4e 100644 (file)
@@ -81,20 +81,14 @@ function benchmarkTest( &$u, $filename, $desc ) {
        }
 }
 
-function benchTime() {
-       $st = explode( ' ', microtime() );
-
-       return (float)$st[0] + (float)$st[1];
-}
-
 function benchmarkForm( &$u, &$data, $form ) {
-       #$start = benchTime();
+       #$start = microtime( true );
        for ( $i = 0; $i < BENCH_CYCLES; $i++ ) {
-               $start = benchTime();
+               $start = microtime( true );
                $out = $u->$form( $data, UtfNormal::$utfCanonicalDecomp );
-               $deltas[] = ( benchTime() - $start );
+               $deltas[] = ( microtime( true ) - $start );
        }
-       #$delta = (benchTime() - $start) / BENCH_CYCLES;
+       #$delta = (microtime( true ) - $start) / BENCH_CYCLES;
        sort( $deltas );
        $delta = $deltas[0]; # Take shortest time
 
index 14abf93..f133e4d 100644 (file)
@@ -83,20 +83,14 @@ function benchmarkTest( &$u, $filename, $desc ) {
        }
 }
 
-function benchTime() {
-       $st = explode( ' ', microtime() );
-
-       return (float)$st[0] + (float)$st[1];
-}
-
 function benchmarkForm( &$u, &$data, $form ) {
-       #$start = benchTime();
+       #$start = microtime( true );
        for ( $i = 0; $i < BENCH_CYCLES; $i++ ) {
-               $start = benchTime();
+               $start = microtime( true );
                $out = $u->$form( $data, UtfNormal::$utfCanonicalDecomp );
-               $deltas[] = ( benchTime() - $start );
+               $deltas[] = ( microtime( true ) - $start );
        }
-       #$delta = (benchTime() - $start) / BENCH_CYCLES;
+       #$delta = (microtime( true ) - $start) / BENCH_CYCLES;
        sort( $deltas );
        $delta = $deltas[0]; # Take shortest time
 
index dca5f32..de3efd1 100644 (file)
@@ -46,10 +46,10 @@ abstract class BagOStuff {
        protected $lastError = self::ERR_NONE;
 
        /** Possible values for getLastError() */
-       const ERR_NONE        = 0; // no error
+       const ERR_NONE = 0; // no error
        const ERR_NO_RESPONSE = 1; // no response
        const ERR_UNREACHABLE = 2; // can't connect
-       const ERR_UNEXPECTED  = 3; // response gave some error
+       const ERR_UNEXPECTED = 3; // response gave some error
 
        /**
         * @param bool $bool
index f7dfe46..8700c8c 100644 (file)
@@ -269,10 +269,4 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
                wfProfileOut( __METHOD__ );
                return $this->checkResult( false, $result );
        }
-
-
-       /* NOTE: there is no cas() method here because it is currently not supported
-        * by the BagOStuff interface and other BagOStuff subclasses, such as
-        * SqlBagOStuff.
-        */
 }
index 0009999..633b34a 100644 (file)
@@ -119,11 +119,15 @@ class ObjectCache {
        /**
         * Factory function referenced from DefaultSettings.php for CACHE_ACCEL.
         *
+        * This will look for any APC style server-local cache.
+        * A fallback cache can be specified if none is found.
+        *
         * @param array $params
+        * @param int|string $fallback Fallback cache, e.g. (CACHE_NONE, "hash") (since 1.24)
         * @throws MWException
         * @return BagOStuff
         */
-       static function newAccelerator( $params ) {
+       static function newAccelerator( $params, $fallback = null ) {
                if ( function_exists( 'apc_fetch' ) ) {
                        $id = 'apc';
                } elseif ( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) {
@@ -131,6 +135,9 @@ class ObjectCache {
                } elseif ( function_exists( 'wincache_ucache_get' ) ) {
                        $id = 'wincache';
                } else {
+                       if ( $fallback ) {
+                               return self::newFromId( $fallback );
+                       }
                        throw new MWException( "CACHE_ACCEL requested but no suitable object " .
                                "cache is present. You may want to install APC." );
                }
index 483f8b9..7328b74 100644 (file)
@@ -27,9 +27,6 @@
  * @ingroup Cache
  */
 class SqlBagOStuff extends BagOStuff {
-       /** @var LoadBalancer */
-       protected $lb;
-
        protected $serverInfos;
 
        /** @var array */
@@ -146,14 +143,12 @@ class SqlBagOStuff extends BagOStuff {
                                $db = DatabaseBase::factory( $type, $info );
                                $db->clearFlag( DBO_TRX );
                        } else {
-                               /*
-                                * We must keep a separate connection to MySQL in order to avoid deadlocks
-                                * However, SQLite has an opposite behavior. And PostgreSQL needs to know
-                                * if we are in transaction or no
-                                */
+                               // We must keep a separate connection to MySQL in order to avoid deadlocks
+                               // However, SQLite has an opposite behavior.
+                               // @todo get this trick to work on PostgreSQL too
                                if ( wfGetDB( DB_MASTER )->getType() == 'mysql' ) {
-                                       $this->lb = wfGetLBFactory()->newMainLB();
-                                       $db = $this->lb->getConnection( DB_MASTER );
+                                       $lb = wfGetLBFactory()->newMainLB();
+                                       $db = $lb->getConnection( DB_MASTER );
                                        $db->clearFlag( DBO_TRX ); // auto-commit mode
                                } else {
                                        $db = wfGetDB( DB_MASTER );
@@ -243,7 +238,12 @@ class SqlBagOStuff extends BagOStuff {
                                        $res = $db->select( $tableName,
                                                array( 'keyname', 'value', 'exptime' ),
                                                array( 'keyname' => $tableKeys ),
-                                               __METHOD__ );
+                                               __METHOD__,
+                                               // Approximate write-on-the-fly BagOStuff API via blocking.
+                                               // This approximation fails if a ROLLBACK happens (which is rare).
+                                               // We do not want to flush the TRX as that can break callers.
+                                               $db->trxLevel() ? array( 'LOCK IN SHARE MODE' ) : array()
+                                       );
                                        foreach ( $res as $row ) {
                                                $row->serverIndex = $serverIndex;
                                                $row->tableName = $tableName;
@@ -263,13 +263,11 @@ class SqlBagOStuff extends BagOStuff {
                                        $db = $this->getDB( $row->serverIndex );
                                        if ( $this->isExpired( $db, $row->exptime ) ) { // MISS
                                                $this->debug( "get: key has expired, deleting" );
-                                               $db->commit( __METHOD__, 'flush' );
                                                # Put the expiry time in the WHERE condition to avoid deleting a
                                                # newly-inserted value
                                                $db->delete( $row->tableName,
                                                        array( 'keyname' => $key, 'exptime' => $row->exptime ),
                                                        __METHOD__ );
-                                               $db->commit( __METHOD__, 'flush' );
                                        } else { // HIT
                                                $values[$key] = $this->unserialize( $db->decodeBlob( $row->value ) );
                                        }
@@ -332,14 +330,12 @@ class SqlBagOStuff extends BagOStuff {
                                }
 
                                try {
-                                       $db->commit( __METHOD__, 'flush' );
                                        $db->replace(
                                                $tableName,
                                                array( 'keyname' ),
                                                $rows,
                                                __METHOD__
                                        );
-                                       $db->commit( __METHOD__, 'flush' );
                                } catch ( DBError $e ) {
                                        $this->handleWriteError( $e, $serverIndex );
                                        $result = false;
@@ -379,7 +375,6 @@ class SqlBagOStuff extends BagOStuff {
 
                                $encExpiry = $db->timestamp( $exptime );
                        }
-                       $db->commit( __METHOD__, 'flush' );
                        // (bug 24425) use a replace if the db supports it instead of
                        // delete/insert to avoid clashes with conflicting keynames
                        $db->replace(
@@ -390,7 +385,6 @@ class SqlBagOStuff extends BagOStuff {
                                        'value' => $db->encodeBlob( $this->serialize( $value ) ),
                                        'exptime' => $encExpiry
                                ), __METHOD__ );
-                       $db->commit( __METHOD__, 'flush' );
                } catch ( DBError $e ) {
                        $this->handleWriteError( $e, $serverIndex );
                        return false;
@@ -424,7 +418,6 @@ class SqlBagOStuff extends BagOStuff {
                                }
                                $encExpiry = $db->timestamp( $exptime );
                        }
-                       $db->commit( __METHOD__, 'flush' );
                        // (bug 24425) use a replace if the db supports it instead of
                        // delete/insert to avoid clashes with conflicting keynames
                        $db->update(
@@ -440,7 +433,6 @@ class SqlBagOStuff extends BagOStuff {
                                ),
                                __METHOD__
                        );
-                       $db->commit( __METHOD__, 'flush' );
                } catch ( DBQueryError $e ) {
                        $this->handleWriteError( $e, $serverIndex );
 
@@ -459,12 +451,10 @@ class SqlBagOStuff extends BagOStuff {
                list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
                try {
                        $db = $this->getDB( $serverIndex );
-                       $db->commit( __METHOD__, 'flush' );
                        $db->delete(
                                $tableName,
                                array( 'keyname' => $key ),
                                __METHOD__ );
-                       $db->commit( __METHOD__, 'flush' );
                } catch ( DBError $e ) {
                        $this->handleWriteError( $e, $serverIndex );
                        return false;
@@ -483,7 +473,6 @@ class SqlBagOStuff extends BagOStuff {
                try {
                        $db = $this->getDB( $serverIndex );
                        $step = intval( $step );
-                       $db->commit( __METHOD__, 'flush' );
                        $row = $db->selectRow(
                                $tableName,
                                array( 'value', 'exptime' ),
@@ -492,14 +481,12 @@ class SqlBagOStuff extends BagOStuff {
                                array( 'FOR UPDATE' ) );
                        if ( $row === false ) {
                                // Missing
-                               $db->commit( __METHOD__, 'flush' );
 
                                return null;
                        }
                        $db->delete( $tableName, array( 'keyname' => $key ), __METHOD__ );
                        if ( $this->isExpired( $db, $row->exptime ) ) {
                                // Expired, do not reinsert
-                               $db->commit( __METHOD__, 'flush' );
 
                                return null;
                        }
@@ -517,7 +504,6 @@ class SqlBagOStuff extends BagOStuff {
                                // Race condition. See bug 28611
                                $newValue = null;
                        }
-                       $db->commit( __METHOD__, 'flush' );
                } catch ( DBError $e ) {
                        $this->handleWriteError( $e, $serverIndex );
                        return null;
@@ -608,7 +594,6 @@ class SqlBagOStuff extends BagOStuff {
                                                        $maxExpTime = $row->exptime;
                                                }
 
-                                               $db->commit( __METHOD__, 'flush' );
                                                $db->delete(
                                                        $this->getTableNameByShard( $i ),
                                                        array(
@@ -617,7 +602,6 @@ class SqlBagOStuff extends BagOStuff {
                                                                'keyname' => $keys
                                                        ),
                                                        __METHOD__ );
-                                               $db->commit( __METHOD__, 'flush' );
 
                                                if ( $progressCallback ) {
                                                        if ( intval( $totalSeconds ) === 0 ) {
@@ -650,9 +634,7 @@ class SqlBagOStuff extends BagOStuff {
                        try {
                                $db = $this->getDB( $serverIndex );
                                for ( $i = 0; $i < $this->shards; $i++ ) {
-                                       $db->commit( __METHOD__, 'flush' );
                                        $db->delete( $this->getTableNameByShard( $i ), '*', __METHOD__ );
-                                       $db->commit( __METHOD__, 'flush' );
                                }
                        } catch ( DBError $e ) {
                                $this->handleWriteError( $e, $serverIndex );
@@ -780,12 +762,10 @@ class SqlBagOStuff extends BagOStuff {
                        }
 
                        for ( $i = 0; $i < $this->shards; $i++ ) {
-                               $db->commit( __METHOD__, 'flush' );
                                $db->query(
                                        'CREATE TABLE ' . $db->tableName( $this->getTableNameByShard( $i ) ) .
                                        ' LIKE ' . $db->tableName( 'objectcache' ),
                                        __METHOD__ );
-                               $db->commit( __METHOD__, 'flush' );
                        }
                }
        }
index 0e989d3..2f27826 100644 (file)
@@ -480,7 +480,7 @@ class Article implements Page {
         * page of the given title.
         */
        public function view() {
-               global $wgUseFileCache, $wgUseETag, $wgDebugToolbar;
+               global $wgUseFileCache, $wgUseETag, $wgDebugToolbar, $wgMaxRedirects;
 
                wfProfileIn( __METHOD__ );
 
@@ -542,8 +542,31 @@ class Article implements Page {
                                $outputPage->setETag( $parserCache->getETag( $this, $parserOptions ) );
                        }
 
+                       # Use the greatest of the page's timestamp or the timestamp of any
+                       # redirect in the chain (bug 67849)
+                       $timestamp = $this->mPage->getTouched();
+                       if ( isset( $this->mRedirectedFrom ) ) {
+                               $timestamp = max( $timestamp, $this->mRedirectedFrom->getTouched() );
+
+                               # If there can be more than one redirect in the chain, we have
+                               # to go through the whole chain too in case an intermediate
+                               # redirect was changed.
+                               if ( $wgMaxRedirects > 1 ) {
+                                       $titles = Revision::newFromTitle( $this->mRedirectedFrom )
+                                               ->getContent( Revision::FOR_THIS_USER, $user )
+                                               ->getRedirectChain();
+                                       $thisTitle = $this->getTitle();
+                                       foreach ( $titles as $title ) {
+                                               if ( Title::compare( $title, $thisTitle ) === 0 ) {
+                                                       break;
+                                               }
+                                               $timestamp = max( $timestamp, $title->getTouched() );
+                                       }
+                               }
+                       }
+
                        # Is it client cached?
-                       if ( $outputPage->checkLastModified( $this->mPage->getTouched() ) ) {
+                       if ( $outputPage->checkLastModified( $timestamp ) ) {
                                wfDebug( __METHOD__ . ": done 304\n" );
                                wfProfileOut( __METHOD__ );
 
index 60db202..9aff6ef 100644 (file)
@@ -296,7 +296,7 @@ class ImagePage extends Article {
        }
 
        protected function openShowImage() {
-               global $wgImageLimits, $wgEnableUploads, $wgSend404Code;
+               global $wgEnableUploads, $wgSend404Code;
 
                $this->loadFile();
                $out = $this->getContext()->getOutput();
@@ -341,49 +341,17 @@ class ImagePage extends Article {
 
                        if ( $this->displayImg->allowInlineDisplay() ) {
                                # image
-
                                # "Download high res version" link below the image
                                # $msgsize = wfMessage( 'file-info-size', $width_orig, $height_orig,
                                #   Linker::formatSize( $this->displayImg->getSize() ), $mime )->escaped();
                                # We'll show a thumbnail of this image
-                               if ( $width > $maxWidth || $height > $maxHeight ) {
-                                       # Calculate the thumbnail size.
-                                       # First case, the limiting factor is the width, not the height.
-                                       /** @todo // FIXME: Possible division by 0. bug 36911 */
-                                       if ( $width / $height >= $maxWidth / $maxHeight ) {
-                                               /** @todo // FIXME: Possible division by 0. bug 36911 */
-                                               $height = round( $height * $maxWidth / $width );
-                                               $width = $maxWidth;
-                                               # Note that $height <= $maxHeight now.
-                                       } else {
-                                               /** @todo // FIXME: Possible division by 0. bug 36911 */
-                                               $newwidth = floor( $width * $maxHeight / $height );
-                                               /** @todo // FIXME: Possible division by 0. bug 36911 */
-                                               $height = round( $height * $newwidth / $width );
-                                               $width = $newwidth;
-                                               # Note that $height <= $maxHeight now, but might not be identical
-                                               # because of rounding.
-                                       }
+                               if ( $width > $maxWidth || $height > $maxHeight || $this->displayImg->isVectorized() ) {
+                                       list( $width, $height ) = $this->getDisplayWidthHeight(
+                                               $maxWidth, $maxHeight, $width, $height
+                                       );
                                        $linktext = wfMessage( 'show-big-image' )->escaped();
-                                       if ( $this->displayImg->getRepo()->canTransformVia404() ) {
-                                               $thumbSizes = $wgImageLimits;
-                                               // Also include the full sized resolution in the list, so
-                                               // that users know they can get it. This will link to the
-                                               // original file asset if mustRender() === false. In the case
-                                               // that we mustRender, some users have indicated that they would
-                                               // find it useful to have the full size image in the rendered
-                                               // image format.
-                                               $thumbSizes[] = array( $width_orig, $height_orig );
-                                       } else {
-                                               # Creating thumb links triggers thumbnail generation.
-                                               # Just generate the thumb for the current users prefs.
-                                               $thumbSizes = array( $this->getImageLimitsFromOption( $user, 'thumbsize' ) );
-                                               if ( !$this->displayImg->mustRender() ) {
-                                                       // We can safely include a link to the "full-size" preview,
-                                                       // without actually rendering.
-                                                       $thumbSizes[] = array( $width_orig, $height_orig );
-                                               }
-                                       }
+
+                                       $thumbSizes = $this->getThumbSizes( $width, $height, $width_orig, $height_orig );
                                        # Generate thumbnails or thumbnail links as needed...
                                        $otherSizes = array();
                                        foreach ( $thumbSizes as $size ) {
@@ -393,7 +361,10 @@ class ImagePage extends Article {
                                                // the current thumbnail's size ($width/$height)
                                                // since that is added to the message separately, so
                                                // it can be denoted as the current size being shown.
-                                               if ( $size[0] <= $width_orig && $size[1] <= $height_orig
+                                               // Vectorized images are "infinitely" big, so all thumb
+                                               // sizes are shown.
+                                               if ( ( ( $size[0] <= $width_orig && $size[1] <= $height_orig )
+                                                               || $this->displayImg->isVectorized() )
                                                        && $size[0] != $width && $size[1] != $height
                                                ) {
                                                        $sizeLink = $this->makeSizeLink( $params, $size[0], $size[1] );
@@ -403,6 +374,7 @@ class ImagePage extends Article {
                                                }
                                        }
                                        $otherSizes = array_unique( $otherSizes );
+
                                        $msgsmall = '';
                                        $sizeLinkBigImagePreview = $this->makeSizeLink( $params, $width, $height );
                                        if ( $sizeLinkBigImagePreview ) {
@@ -421,9 +393,6 @@ class ImagePage extends Article {
                                        # Some sort of audio file that doesn't have dimensions
                                        # Don't output a no hi res message for such a file
                                        $msgsmall = '';
-                               } elseif ( $this->displayImg->isVectorized() ) {
-                                       # For vectorized images, full size is just the frame size
-                                       $msgsmall = '';
                                } else {
                                        # Image is small enough to show full size on image page
                                        $msgsmall = wfMessage( 'file-nohires' )->parse();
@@ -1084,6 +1053,81 @@ EOT
                );
                return $langSelectLine;
        }
+
+       /**
+        * Get the width and height to display image at.
+        *
+        * @note This method assumes that it is only called if one
+        *  of the dimensions are bigger than the max, or if the
+        *  image is vectorized.
+        *
+        * @param $maxWidth integer Max width to display at
+        * @param $maxHeight integer Max height to display at
+        * @param $width integer Actual width of the image
+        * @param $height integer Actual height of the image
+        * @throws MWException
+        * @return Array (width, height)
+        */
+       protected function getDisplayWidthHeight( $maxWidth, $maxHeight, $width, $height ) {
+               if ( !$maxWidth || !$maxHeight ) {
+                       // should never happen
+                       throw new MWException( 'Using a choice from $wgImageLimits that is 0x0' );
+               }
+
+               if ( !$width || !$height ) {
+                       return array( 0, 0 );
+               }
+
+               # Calculate the thumbnail size.
+               if ( $width <= $maxWidth && $height <= $maxHeight ) {
+                       // Vectorized image, do nothing.
+               } elseif ( $width / $height >= $maxWidth / $maxHeight ) {
+                       # The limiting factor is the width, not the height.
+                       $height = round( $height * $maxWidth / $width );
+                       $width = $maxWidth;
+                       # Note that $height <= $maxHeight now.
+               } else {
+                       $newwidth = floor( $width * $maxHeight / $height );
+                       $height = round( $height * $newwidth / $width );
+                       $width = $newwidth;
+                       # Note that $height <= $maxHeight now, but might not be identical
+                       # because of rounding.
+               }
+               return array( $width, $height );
+       }
+
+       /**
+        * Get alternative thumbnail sizes.
+        *
+        * @note This will only list several alternatives if thumbnails are rendered on 404
+        * @param $origWidth Actual width of image
+        * @param $origHeight Actual height of image
+        * @return Array An array of [width, height] pairs.
+        */
+       protected function getThumbSizes( $origWidth, $origHeight ) {
+               global $wgImageLimits;
+               if ( $this->displayImg->getRepo()->canTransformVia404() ) {
+                       $thumbSizes = $wgImageLimits;
+                       // Also include the full sized resolution in the list, so
+                       // that users know they can get it. This will link to the
+                       // original file asset if mustRender() === false. In the case
+                       // that we mustRender, some users have indicated that they would
+                       // find it useful to have the full size image in the rendered
+                       // image format.
+                       $thumbSizes[] = array( $origWidth, $origHeight );
+               } else {
+                       # Creating thumb links triggers thumbnail generation.
+                       # Just generate the thumb for the current users prefs.
+                       $thumbSizes = array( $this->getImageLimitsFromOption( $this->getContext()->getUser(), 'thumbsize' ) );
+                       if ( !$this->displayImg->mustRender() ) {
+                               // We can safely include a link to the "full-size" preview,
+                               // without actually rendering.
+                               $thumbSizes[] = array( $origWidth, $origHeight );
+                       }
+               }
+               return $thumbSizes;
+       }
+
 }
 
 /**
index 34f15c3..87cc7ba 100644 (file)
@@ -40,12 +40,6 @@ class WikiFilePage extends WikiPage {
                $this->mRepo = null;
        }
 
-       public function getActionOverrides() {
-               $overrides = parent::getActionOverrides();
-               $overrides['revert'] = 'RevertFileAction';
-               return $overrides;
-       }
-
        /**
         * @param File $file
         */
index 7c412ea..fc269d8 100644 (file)
@@ -2047,7 +2047,9 @@ class WikiPage implements Page, IDBAccessObject {
                wfRunHooks( 'PageContentSaveComplete', $hook_args );
 
                // Promote user to any groups they meet the criteria for
-               $user->addAutopromoteOnceGroups( 'onEdit' );
+               $dbw->onTransactionIdle( function () use ( $user ) {
+                       $user->addAutopromoteOnceGroups( 'onEdit' );
+               } );
 
                wfProfileOut( __METHOD__ );
                return $status;
@@ -2885,7 +2887,7 @@ class WikiPage implements Page, IDBAccessObject {
                $logEntry->setComment( $reason );
                $logid = $logEntry->insert();
 
-               $dbw->onTransactionPreCommitOrIdle( function() use ( $dbw, $logEntry, $logid ) {
+               $dbw->onTransactionPreCommitOrIdle( function () use ( $dbw, $logEntry, $logid ) {
                        // Bug 56776: avoid deadlocks (especially from FileDeleteForm)
                        $logEntry->publish( $logid );
                } );
@@ -3345,7 +3347,7 @@ class WikiPage implements Page, IDBAccessObject {
 
                // Do this at the end of the commit to reduce lock wait timeouts
                $dbw->onTransactionPreCommitOrIdle(
-                       function() use ( $dbw, $that, $method, $added, $deleted ) {
+                       function () use ( $dbw, $that, $method, $added, $deleted ) {
                                $ns = $that->getTitle()->getNamespace();
 
                                $addFields = array( 'cat_pages = cat_pages + 1' );
@@ -3503,17 +3505,6 @@ class WikiPage implements Page, IDBAccessObject {
                return $wgParser->preSaveTransform( $text, $this->mTitle, $user, $popts );
        }
 
-       /**
-        * Check whether the number of revisions of this page surpasses $wgDeleteRevisionsLimit
-        *
-        * @deprecated since 1.19; use Title::isBigDeletion() instead.
-        * @return bool
-        */
-       public function isBigDeletion() {
-               wfDeprecated( __METHOD__, '1.19' );
-               return $this->mTitle->isBigDeletion();
-       }
-
        /**
         * Get the  approximate revision count of this page.
         *
index cde7a2d..faff0e7 100644 (file)
@@ -365,9 +365,15 @@ class CoreParserFunctions {
         * @param string $text Desired title text
         * @return string
         */
-       static function displaytitle( $parser, $text = '' ) {
+       static function displaytitle( $parser, $text = '', $uarg = '' ) {
                global $wgRestrictDisplayTitle;
 
+               static $magicWords = null;
+               if ( is_null( $magicWords ) ) {
+                       $magicWords = new MagicWordArray( array( 'displaytitle_noerror', 'displaytitle_noreplace' ) );
+               }
+               $arg = $magicWords->matchStartToEnd( $uarg );
+
                // parse a limited subset of wiki markup (just the single quote items)
                $text = $parser->doQuotes( $text );
 
@@ -378,7 +384,7 @@ class CoreParserFunctions {
                // list of disallowed tags for DISPLAYTITLE
                // these will be escaped even though they are allowed in normal wiki text
                $bad = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr',
-                       'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rp', 'br' );
+                       'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rtc', 'rp', 'br' );
 
                // disallow some styles that could be used to bypass $wgRestrictDisplayTitle
                if ( $wgRestrictDisplayTitle ) {
@@ -413,13 +419,25 @@ class CoreParserFunctions {
                ) );
                $title = Title::newFromText( Sanitizer::stripAllTags( $text ) );
 
-               if ( !$wgRestrictDisplayTitle ) {
-                       $parser->mOutput->setDisplayTitle( $text );
-               } elseif ( $title instanceof Title
+               if ( !$wgRestrictDisplayTitle ||
+                       ( $title instanceof Title
                        && !$title->hasFragment()
-                       && $title->equals( $parser->mTitle )
+                       && $title->equals( $parser->mTitle ) )
                ) {
-                       $parser->mOutput->setDisplayTitle( $text );
+                       $old = $parser->mOutput->getProperty( 'displaytitle' );
+                       if ( $old === false || $arg !== 'displaytitle_noreplace' ) {
+                               $parser->mOutput->setDisplayTitle( $text );
+                       }
+                       if ( $old !== false && $old !== $text && !$arg ) {
+                               $converter = $parser->getConverterLanguage()->getConverter();
+                               return '<span class="error">' .
+                                       wfMessage( 'duplicate-displaytitle',
+                                               // Message should be parsed, but these params should only be escaped.
+                                               $converter->markNoConversion( wfEscapeWikiText( $old ) ),
+                                               $converter->markNoConversion( wfEscapeWikiText( $text ) )
+                                       )->inContentLanguage()->text() .
+                                       '</span>';
+                       }
                }
 
                return '';
index 0cbf5e8..648667b 100644 (file)
@@ -341,7 +341,7 @@ class LinkHolderArray {
                                $where[] = $dbr->makeList(
                                        array(
                                                'page_namespace' => $ns,
-                                               'page_title' => $pages,
+                                               'page_title' => array_unique( $pages ),
                                        ),
                                        LIST_AND
                                );
diff --git a/includes/parser/MWTidy.php b/includes/parser/MWTidy.php
new file mode 100644 (file)
index 0000000..f7fe5a8
--- /dev/null
@@ -0,0 +1,289 @@
+<?php
+/**
+ * HTML validation and correction
+ *
+ * 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
+ */
+
+/**
+ * Class used to hide mw:editsection tokens from Tidy so that it doesn't break them
+ * or break on them. This is a bit of a hack for now, but hopefully in the future
+ * we may create a real postprocessor or something that will replace this.
+ * It's called wrapper because for now it basically takes over MWTidy::tidy's task
+ * of wrapping the text in a xhtml block
+ *
+ * This re-uses some of the parser's UNIQ tricks, though some of it is private so it's
+ * duplicated. Perhaps we should create an abstract marker hiding class.
+ *
+ * @ingroup Parser
+ */
+class MWTidyWrapper {
+
+       /**
+        * @var ReplacementArray
+        */
+       protected $mTokens;
+
+       protected $mUniqPrefix;
+
+       protected $mMarkerIndex;
+
+       public function __construct() {
+               $this->mTokens = null;
+               $this->mUniqPrefix = null;
+       }
+
+       /**
+        * @param string $text
+        * @return string
+        */
+       public function getWrapped( $text ) {
+               $this->mTokens = new ReplacementArray;
+               $this->mUniqPrefix = "\x7fUNIQ" .
+                       dechex( mt_rand( 0, 0x7fffffff ) ) . dechex( mt_rand( 0, 0x7fffffff ) );
+               $this->mMarkerIndex = 0;
+
+               // Replace <mw:editsection> elements with placeholders
+               $wrappedtext = preg_replace_callback( ParserOutput::EDITSECTION_REGEX,
+                       array( &$this, 'replaceCallback' ), $text );
+               // ...and <mw:toc> markers
+               $wrappedtext = preg_replace_callback( '/\<\\/?mw:toc\>/',
+                       array( &$this, 'replaceCallback' ), $wrappedtext );
+
+               // Modify inline Microdata <link> and <meta> elements so they say <html-link> and <html-meta> so
+               // we can trick Tidy into not stripping them out by including them in tidy's new-empty-tags config
+               $wrappedtext = preg_replace( '!<(link|meta)([^>]*?)(/{0,1}>)!', '<html-$1$2$3', $wrappedtext );
+
+               // Wrap the whole thing in a doctype and body for Tidy.
+               $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' .
+                       ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>' .
+                       '<head><title>test</title></head><body>' . $wrappedtext . '</body></html>';
+
+               return $wrappedtext;
+       }
+
+       /**
+        * @param array $m
+        *
+        * @return string
+        */
+       function replaceCallback( $m ) {
+               $marker = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
+               $this->mMarkerIndex++;
+               $this->mTokens->setPair( $marker, $m[0] );
+               return $marker;
+       }
+
+       /**
+        * @param string $text
+        * @return string
+        */
+       public function postprocess( $text ) {
+               // Revert <html-{link,meta}> back to <{link,meta}>
+               $text = preg_replace( '!<html-(link|meta)([^>]*?)(/{0,1}>)!', '<$1$2$3', $text );
+
+               // Restore the contents of placeholder tokens
+               $text = $this->mTokens->replace( $text );
+
+               return $text;
+       }
+
+}
+
+/**
+ * Class to interact with HTML tidy
+ *
+ * Either the external tidy program or the in-process tidy extension
+ * will be used depending on availability. Override the default
+ * $wgTidyInternal setting to disable the internal if it's not working.
+ *
+ * @ingroup Parser
+ */
+class MWTidy {
+       /**
+        * Interface with html tidy, used if $wgUseTidy = true.
+        * If tidy isn't able to correct the markup, the original will be
+        * returned in all its glory with a warning comment appended.
+        *
+        * @param string $text Hideous HTML input
+        * @return string Corrected HTML output
+        */
+       public static function tidy( $text ) {
+               global $wgTidyInternal;
+
+               $wrapper = new MWTidyWrapper;
+               $wrappedtext = $wrapper->getWrapped( $text );
+
+               $retVal = null;
+               if ( $wgTidyInternal ) {
+                       $correctedtext = self::execInternalTidy( $wrappedtext, false, $retVal );
+               } else {
+                       $correctedtext = self::execExternalTidy( $wrappedtext, false, $retVal );
+               }
+
+               if ( $retVal < 0 ) {
+                       wfDebug( "Possible tidy configuration error!\n" );
+                       return $text . "\n<!-- Tidy was unable to run -->\n";
+               } elseif ( is_null( $correctedtext ) ) {
+                       wfDebug( "Tidy error detected!\n" );
+                       return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
+               }
+
+               $correctedtext = $wrapper->postprocess( $correctedtext ); // restore any hidden tokens
+
+               return $correctedtext;
+       }
+
+       /**
+        * Check HTML for errors, used if $wgValidateAllHtml = true.
+        *
+        * @param string $text
+        * @param string &$errorStr Return the error string
+        * @return bool Whether the HTML is valid
+        */
+       public static function checkErrors( $text, &$errorStr = null ) {
+               global $wgTidyInternal;
+
+               $retval = 0;
+               if ( $wgTidyInternal ) {
+                       $errorStr = self::execInternalTidy( $text, true, $retval );
+               } else {
+                       $errorStr = self::execExternalTidy( $text, true, $retval );
+               }
+
+               return ( $retval < 0 && $errorStr == '' ) || $retval == 0;
+       }
+
+       /**
+        * Spawn an external HTML tidy process and get corrected markup back from it.
+        * Also called in OutputHandler.php for full page validation
+        *
+        * @param string $text HTML to check
+        * @param bool $stderr Whether to read result from STDERR rather than STDOUT
+        * @param int &$retval Exit code (-1 on internal error)
+        * @return string|null
+        */
+       private static function execExternalTidy( $text, $stderr = false, &$retval = null ) {
+               global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
+               wfProfileIn( __METHOD__ );
+
+               $cleansource = '';
+               $opts = ' -utf8';
+
+               if ( $stderr ) {
+                       $descriptorspec = array(
+                               0 => array( 'pipe', 'r' ),
+                               1 => array( 'file', wfGetNull(), 'a' ),
+                               2 => array( 'pipe', 'w' )
+                       );
+               } else {
+                       $descriptorspec = array(
+                               0 => array( 'pipe', 'r' ),
+                               1 => array( 'pipe', 'w' ),
+                               2 => array( 'file', wfGetNull(), 'a' )
+                       );
+               }
+
+               $readpipe = $stderr ? 2 : 1;
+               $pipes = array();
+
+               $process = proc_open(
+                       "$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes );
+
+               //NOTE: At least on linux, the process will be created even if tidy is not installed.
+               //      This means that missing tidy will be treated as a validation failure.
+
+               if ( is_resource( $process ) ) {
+                       // Theoretically, this style of communication could cause a deadlock
+                       // here. If the stdout buffer fills up, then writes to stdin could
+                       // block. This doesn't appear to happen with tidy, because tidy only
+                       // writes to stdout after it's finished reading from stdin. Search
+                       // for tidyParseStdin and tidySaveStdout in console/tidy.c
+                       fwrite( $pipes[0], $text );
+                       fclose( $pipes[0] );
+                       while ( !feof( $pipes[$readpipe] ) ) {
+                               $cleansource .= fgets( $pipes[$readpipe], 1024 );
+                       }
+                       fclose( $pipes[$readpipe] );
+                       $retval = proc_close( $process );
+               } else {
+                       wfWarn( "Unable to start external tidy process" );
+                       $retval = -1;
+               }
+
+               if ( !$stderr && $cleansource == '' && $text != '' ) {
+                       // Some kind of error happened, so we couldn't get the corrected text.
+                       // Just give up; we'll use the source text and append a warning.
+                       $cleansource = null;
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $cleansource;
+       }
+
+       /**
+        * Use the HTML tidy extension to use the tidy library in-process,
+        * saving the overhead of spawning a new process.
+        *
+        * @param string $text HTML to check
+        * @param bool $stderr Whether to read result from error status instead of output
+        * @param int &$retval Exit code (-1 on internal error)
+        * @return string|null
+        */
+       private static function execInternalTidy( $text, $stderr = false, &$retval = null ) {
+               global $wgTidyConf, $wgDebugTidy;
+               wfProfileIn( __METHOD__ );
+
+               if ( !class_exists( 'tidy' ) ) {
+                       wfWarn( "Unable to load internal tidy class." );
+                       $retval = -1;
+
+                       wfProfileOut( __METHOD__ );
+                       return null;
+               }
+
+               $tidy = new tidy;
+               $tidy->parseString( $text, $wgTidyConf, 'utf8' );
+
+               if ( $stderr ) {
+                       $retval = $tidy->getStatus();
+
+                       wfProfileOut( __METHOD__ );
+                       return $tidy->errorBuffer;
+               }
+
+               $tidy->cleanRepair();
+               $retval = $tidy->getStatus();
+               if ( $retval == 2 ) {
+                       // 2 is magic number for fatal error
+                       // http://www.php.net/manual/en/function.tidy-get-status.php
+                       $cleansource = null;
+               } else {
+                       $cleansource = tidy_get_output( $tidy );
+                       if ( $wgDebugTidy && $retval > 0 ) {
+                               $cleansource .= "<!--\nTidy reports:\n" .
+                                       str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
+                                       "\n-->";
+                       }
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $cleansource;
+       }
+}
index eb7bd1b..b37e977 100644 (file)
@@ -2002,10 +2002,12 @@ class Parser {
                        wfProfileOut( __METHOD__ . "-e1" );
                        wfProfileIn( __METHOD__ . "-misc" );
 
+                       $origLink = $m[1];
+
                        # Don't allow internal links to pages containing
                        # PROTO: where PROTO is a valid URL protocol; these
                        # should be external links.
-                       if ( preg_match( '/^(?i:' . $this->mUrlProtocols . ')/', $m[1] ) ) {
+                       if ( preg_match( '/^(?i:' . $this->mUrlProtocols . ')/', $origLink ) ) {
                                $s .= $prefix . '[[' . $line;
                                wfProfileOut( __METHOD__ . "-misc" );
                                continue;
@@ -2013,12 +2015,12 @@ class Parser {
 
                        # Make subpage if necessary
                        if ( $useSubpages ) {
-                               $link = $this->maybeDoSubpageLink( $m[1], $text );
+                               $link = $this->maybeDoSubpageLink( $origLink, $text );
                        } else {
-                               $link = $m[1];
+                               $link = $origLink;
                        }
 
-                       $noforce = ( substr( $m[1], 0, 1 ) !== ':' );
+                       $noforce = ( substr( $origLink, 0, 1 ) !== ':' );
                        if ( !$noforce ) {
                                # Strip off leading ':'
                                $link = substr( $link, 1 );
@@ -2097,11 +2099,13 @@ class Parser {
                        if ( $noforce ) {
                                # Interwikis
                                wfProfileIn( __METHOD__ . "-interwiki" );
+                               # The final condition here is due to bug 68085
                                if (
                                        $iw && $this->mOptions->getInterwikiMagic() && $nottalk && (
                                                Language::fetchLanguageName( $iw, null, 'mw' ) ||
                                                in_array( $iw, $wgExtraInterlanguageLinkPrefixes )
-                                       )
+                                       ) && substr_compare( $this->getTargetLanguage()->lc( ltrim( $origLink ) ),
+                                               $iw, 0, strlen( $iw ) ) === 0
                                ) {
                                        # Bug 24502: filter duplicates
                                        if ( !isset( $this->mLangLinkLanguages[$iw] ) ) {
@@ -5013,9 +5017,9 @@ class Parser {
         * private variables.**
         *
         * @param string $tag The tag to use, e.g. 'hook' for "<hook>"
-        * @param mixed $callback The callback function (and object) to use for the tag
+        * @param callable $callback The callback function (and object) to use for the tag
         * @throws MWException
-        * @return mixed|null The old value of the mTagHooks array associated with the hook
+        * @return callable|null The old value of the mTagHooks array associated with the hook
         */
        public function setHook( $tag, $callback ) {
                $tag = strtolower( $tag );
@@ -5044,9 +5048,9 @@ class Parser {
         * @todo better document or deprecate this
         *
         * @param string $tag The tag to use, e.g. 'hook' for "<hook>"
-        * @param mixed $callback The callback function (and object) to use for the tag
+        * @param callable $callback The callback function (and object) to use for the tag
         * @throws MWException
-        * @return mixed|null The old value of the mTagHooks array associated with the hook
+        * @return callable|null The old value of the mTagHooks array associated with the hook
         */
        function setTransparentTagHook( $tag, $callback ) {
                $tag = strtolower( $tag );
@@ -5085,7 +5089,7 @@ class Parser {
         *   isHTML                    The returned text is HTML, armour it against wikitext transformation
         *
         * @param string $id The magic word ID
-        * @param mixed $callback The callback function (and object) to use
+        * @param callable $callback The callback function (and object) to use
         * @param int $flags A combination of the following flags:
         *     SFH_NO_HASH   No leading hash, i.e. {{plural:...}} instead of {{#if:...}}
         *
@@ -5369,6 +5373,7 @@ class Parser {
                        $ig->add( $title, $label, $alt, $link, $handlerOptions );
                }
                $html = $ig->toHTML();
+               wfRunHooks( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
                wfProfileOut( __METHOD__ );
                return $html;
        }
index 90617b3..2cd208c 100644 (file)
@@ -422,11 +422,6 @@ class ParserOptions {
                return wfSetVar( $this->mTidy, $x );
        }
 
-       /** @deprecated since 1.19 */
-       function setSkin( $x ) {
-               wfDeprecated( __METHOD__, '1.19' );
-       }
-
        function setInterfaceMessage( $x ) {
                return wfSetVar( $this->mInterfaceMessage, $x );
        }
diff --git a/includes/parser/Tidy.php b/includes/parser/Tidy.php
deleted file mode 100644 (file)
index f7fe5a8..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-<?php
-/**
- * HTML validation and correction
- *
- * 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
- */
-
-/**
- * Class used to hide mw:editsection tokens from Tidy so that it doesn't break them
- * or break on them. This is a bit of a hack for now, but hopefully in the future
- * we may create a real postprocessor or something that will replace this.
- * It's called wrapper because for now it basically takes over MWTidy::tidy's task
- * of wrapping the text in a xhtml block
- *
- * This re-uses some of the parser's UNIQ tricks, though some of it is private so it's
- * duplicated. Perhaps we should create an abstract marker hiding class.
- *
- * @ingroup Parser
- */
-class MWTidyWrapper {
-
-       /**
-        * @var ReplacementArray
-        */
-       protected $mTokens;
-
-       protected $mUniqPrefix;
-
-       protected $mMarkerIndex;
-
-       public function __construct() {
-               $this->mTokens = null;
-               $this->mUniqPrefix = null;
-       }
-
-       /**
-        * @param string $text
-        * @return string
-        */
-       public function getWrapped( $text ) {
-               $this->mTokens = new ReplacementArray;
-               $this->mUniqPrefix = "\x7fUNIQ" .
-                       dechex( mt_rand( 0, 0x7fffffff ) ) . dechex( mt_rand( 0, 0x7fffffff ) );
-               $this->mMarkerIndex = 0;
-
-               // Replace <mw:editsection> elements with placeholders
-               $wrappedtext = preg_replace_callback( ParserOutput::EDITSECTION_REGEX,
-                       array( &$this, 'replaceCallback' ), $text );
-               // ...and <mw:toc> markers
-               $wrappedtext = preg_replace_callback( '/\<\\/?mw:toc\>/',
-                       array( &$this, 'replaceCallback' ), $wrappedtext );
-
-               // Modify inline Microdata <link> and <meta> elements so they say <html-link> and <html-meta> so
-               // we can trick Tidy into not stripping them out by including them in tidy's new-empty-tags config
-               $wrappedtext = preg_replace( '!<(link|meta)([^>]*?)(/{0,1}>)!', '<html-$1$2$3', $wrappedtext );
-
-               // Wrap the whole thing in a doctype and body for Tidy.
-               $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' .
-                       ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>' .
-                       '<head><title>test</title></head><body>' . $wrappedtext . '</body></html>';
-
-               return $wrappedtext;
-       }
-
-       /**
-        * @param array $m
-        *
-        * @return string
-        */
-       function replaceCallback( $m ) {
-               $marker = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
-               $this->mMarkerIndex++;
-               $this->mTokens->setPair( $marker, $m[0] );
-               return $marker;
-       }
-
-       /**
-        * @param string $text
-        * @return string
-        */
-       public function postprocess( $text ) {
-               // Revert <html-{link,meta}> back to <{link,meta}>
-               $text = preg_replace( '!<html-(link|meta)([^>]*?)(/{0,1}>)!', '<$1$2$3', $text );
-
-               // Restore the contents of placeholder tokens
-               $text = $this->mTokens->replace( $text );
-
-               return $text;
-       }
-
-}
-
-/**
- * Class to interact with HTML tidy
- *
- * Either the external tidy program or the in-process tidy extension
- * will be used depending on availability. Override the default
- * $wgTidyInternal setting to disable the internal if it's not working.
- *
- * @ingroup Parser
- */
-class MWTidy {
-       /**
-        * Interface with html tidy, used if $wgUseTidy = true.
-        * If tidy isn't able to correct the markup, the original will be
-        * returned in all its glory with a warning comment appended.
-        *
-        * @param string $text Hideous HTML input
-        * @return string Corrected HTML output
-        */
-       public static function tidy( $text ) {
-               global $wgTidyInternal;
-
-               $wrapper = new MWTidyWrapper;
-               $wrappedtext = $wrapper->getWrapped( $text );
-
-               $retVal = null;
-               if ( $wgTidyInternal ) {
-                       $correctedtext = self::execInternalTidy( $wrappedtext, false, $retVal );
-               } else {
-                       $correctedtext = self::execExternalTidy( $wrappedtext, false, $retVal );
-               }
-
-               if ( $retVal < 0 ) {
-                       wfDebug( "Possible tidy configuration error!\n" );
-                       return $text . "\n<!-- Tidy was unable to run -->\n";
-               } elseif ( is_null( $correctedtext ) ) {
-                       wfDebug( "Tidy error detected!\n" );
-                       return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
-               }
-
-               $correctedtext = $wrapper->postprocess( $correctedtext ); // restore any hidden tokens
-
-               return $correctedtext;
-       }
-
-       /**
-        * Check HTML for errors, used if $wgValidateAllHtml = true.
-        *
-        * @param string $text
-        * @param string &$errorStr Return the error string
-        * @return bool Whether the HTML is valid
-        */
-       public static function checkErrors( $text, &$errorStr = null ) {
-               global $wgTidyInternal;
-
-               $retval = 0;
-               if ( $wgTidyInternal ) {
-                       $errorStr = self::execInternalTidy( $text, true, $retval );
-               } else {
-                       $errorStr = self::execExternalTidy( $text, true, $retval );
-               }
-
-               return ( $retval < 0 && $errorStr == '' ) || $retval == 0;
-       }
-
-       /**
-        * Spawn an external HTML tidy process and get corrected markup back from it.
-        * Also called in OutputHandler.php for full page validation
-        *
-        * @param string $text HTML to check
-        * @param bool $stderr Whether to read result from STDERR rather than STDOUT
-        * @param int &$retval Exit code (-1 on internal error)
-        * @return string|null
-        */
-       private static function execExternalTidy( $text, $stderr = false, &$retval = null ) {
-               global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
-               wfProfileIn( __METHOD__ );
-
-               $cleansource = '';
-               $opts = ' -utf8';
-
-               if ( $stderr ) {
-                       $descriptorspec = array(
-                               0 => array( 'pipe', 'r' ),
-                               1 => array( 'file', wfGetNull(), 'a' ),
-                               2 => array( 'pipe', 'w' )
-                       );
-               } else {
-                       $descriptorspec = array(
-                               0 => array( 'pipe', 'r' ),
-                               1 => array( 'pipe', 'w' ),
-                               2 => array( 'file', wfGetNull(), 'a' )
-                       );
-               }
-
-               $readpipe = $stderr ? 2 : 1;
-               $pipes = array();
-
-               $process = proc_open(
-                       "$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes );
-
-               //NOTE: At least on linux, the process will be created even if tidy is not installed.
-               //      This means that missing tidy will be treated as a validation failure.
-
-               if ( is_resource( $process ) ) {
-                       // Theoretically, this style of communication could cause a deadlock
-                       // here. If the stdout buffer fills up, then writes to stdin could
-                       // block. This doesn't appear to happen with tidy, because tidy only
-                       // writes to stdout after it's finished reading from stdin. Search
-                       // for tidyParseStdin and tidySaveStdout in console/tidy.c
-                       fwrite( $pipes[0], $text );
-                       fclose( $pipes[0] );
-                       while ( !feof( $pipes[$readpipe] ) ) {
-                               $cleansource .= fgets( $pipes[$readpipe], 1024 );
-                       }
-                       fclose( $pipes[$readpipe] );
-                       $retval = proc_close( $process );
-               } else {
-                       wfWarn( "Unable to start external tidy process" );
-                       $retval = -1;
-               }
-
-               if ( !$stderr && $cleansource == '' && $text != '' ) {
-                       // Some kind of error happened, so we couldn't get the corrected text.
-                       // Just give up; we'll use the source text and append a warning.
-                       $cleansource = null;
-               }
-
-               wfProfileOut( __METHOD__ );
-               return $cleansource;
-       }
-
-       /**
-        * Use the HTML tidy extension to use the tidy library in-process,
-        * saving the overhead of spawning a new process.
-        *
-        * @param string $text HTML to check
-        * @param bool $stderr Whether to read result from error status instead of output
-        * @param int &$retval Exit code (-1 on internal error)
-        * @return string|null
-        */
-       private static function execInternalTidy( $text, $stderr = false, &$retval = null ) {
-               global $wgTidyConf, $wgDebugTidy;
-               wfProfileIn( __METHOD__ );
-
-               if ( !class_exists( 'tidy' ) ) {
-                       wfWarn( "Unable to load internal tidy class." );
-                       $retval = -1;
-
-                       wfProfileOut( __METHOD__ );
-                       return null;
-               }
-
-               $tidy = new tidy;
-               $tidy->parseString( $text, $wgTidyConf, 'utf8' );
-
-               if ( $stderr ) {
-                       $retval = $tidy->getStatus();
-
-                       wfProfileOut( __METHOD__ );
-                       return $tidy->errorBuffer;
-               }
-
-               $tidy->cleanRepair();
-               $retval = $tidy->getStatus();
-               if ( $retval == 2 ) {
-                       // 2 is magic number for fatal error
-                       // http://www.php.net/manual/en/function.tidy-get-status.php
-                       $cleansource = null;
-               } else {
-                       $cleansource = tidy_get_output( $tidy );
-                       if ( $wgDebugTidy && $retval > 0 ) {
-                               $cleansource .= "<!--\nTidy reports:\n" .
-                                       str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
-                                       "\n-->";
-                       }
-               }
-
-               wfProfileOut( __METHOD__ );
-               return $cleansource;
-       }
-}
index 093fe49..d609f61 100644 (file)
@@ -90,7 +90,7 @@ class PoolCounterRedis extends PoolCounter {
 
                $this->keySha1 = sha1( $this->key );
                $met = ini_get( 'max_execution_time' ); // usually 0 in CLI mode
-               $this->lockTTL = $met ? 2*$met : 3600;
+               $this->lockTTL = $met ? 2 * $met : 3600;
 
                if ( self::$active === null ) {
                        self::$active = array();
@@ -154,8 +154,12 @@ class PoolCounterRedis extends PoolCounter {
                if rSlot ~= 'w' and redis.call('exists',kSlotsNextRelease) == 1 then
                        if 1*redis.call('zScore',kSlotsNextRelease,rSlot) ~= (rSlotTime + rExpiry) then
                                -- Slot lock expired and was released already
-                       elseif redis.call('lLen',kSlots) >= (1*rMaxWorkers - 1) then
-                               -- Clear list to save space; it will re-init as needed
+                       elseif redis.call('lLen',kSlots) >= 1*rMaxWorkers then
+                               -- Slots somehow got out of sync; reset the list for sanity
+                               redis.call('del',kSlots,kSlotsNextRelease)
+                       elseif redis.call('lLen',kSlots) == (1*rMaxWorkers - 1) and redis.call('zCard',kWaiting) == 0 then
+                               -- Slot list will be made full; clear it to save space (it re-inits as needed)
+                               -- since nothing is waiting on being unblocked by a push to the list
                                redis.call('del',kSlots,kSlotsNextRelease)
                        else
                                -- Add slot back to pool and update the "next release" time
index 75f6966..cd1e859 100644 (file)
@@ -126,7 +126,7 @@ abstract class Profiler {
                        if ( is_array( $wgProfiler ) ) {
                                if ( !isset( $wgProfiler['class'] ) ) {
                                        $class = 'ProfilerStub';
-                               } elseif ( $wgProfiler['class'] === 'Profiler'  ) {
+                               } elseif ( $wgProfiler['class'] === 'Profiler' ) {
                                        $class = 'ProfilerStub'; // b/c; don't explode
                                } else {
                                        $class = $wgProfiler['class'];
@@ -397,7 +397,7 @@ class TransactionProfiler {
        public function recordFunctionCompletion( $method, $realtime ) {
                if ( !$this->mDBTrxHoldingLocks ) {
                        return; // short-circuit
-               // @TODO: hardcoded check is a tad janky (what about FOR UPDATE?)
+               // @todo hardcoded check is a tad janky (what about FOR UPDATE?)
                } elseif ( !preg_match( '/^query-m: (?!SELECT)/', $method )
                        && $realtime < $this->mDBLockThreshold
                ) {
diff --git a/includes/resourceloader/DerivativeResourceLoaderContext.php b/includes/resourceloader/DerivativeResourceLoaderContext.php
new file mode 100644 (file)
index 0000000..d114d7e
--- /dev/null
@@ -0,0 +1,202 @@
+<?php
+/**
+ * Derivative context for resource loader modules.
+ *
+ * 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 Kunal Mehta
+ */
+
+/**
+ * Allows changing specific properties of a context object,
+ * without changing the main one. Inspired by DerivativeContext.
+ *
+ * @since 1.24
+ */
+class DerivativeResourceLoaderContext extends ResourceLoaderContext {
+
+       /**
+        * @var ResourceLoaderContext
+        */
+       private $context;
+       protected $modules;
+       protected $language;
+       protected $direction;
+       protected $skin;
+       protected $user;
+       protected $debug;
+       protected $only;
+       protected $version;
+       protected $hash;
+       protected $raw;
+
+       public function __construct( ResourceLoaderContext $context ) {
+               $this->context = $context;
+       }
+
+       public function getModules() {
+               if ( !is_null( $this->modules ) ) {
+                       return $this->modules;
+               } else {
+                       return $this->context->getModules();
+               }
+       }
+
+       /**
+        * @param string[] $modules
+        */
+       public function setModules( array $modules ) {
+               $this->modules = $modules;
+       }
+
+       public function getLanguage() {
+               if ( !is_null( $this->language ) ) {
+                       return $this->language;
+               } else {
+                       return $this->context->getLanguage();
+               }
+       }
+
+       /**
+        * @param string $language
+        */
+       public function setLanguage( $language ) {
+               $this->language = $language;
+               $this->direction = null; // Invalidate direction since it might be based on language
+               $this->hash = null;
+       }
+
+       public function getDirection() {
+               if ( !is_null( $this->direction ) ) {
+                       return $this->direction;
+               } else {
+                       return $this->context->getDirection();
+               }
+       }
+
+       /**
+        * @param string $direction
+        */
+       public function setDirection( $direction ) {
+               $this->direction = $direction;
+               $this->hash = null;
+       }
+
+       public function getSkin() {
+               if ( !is_null( $this->skin ) ) {
+                       return $this->skin;
+               } else {
+                       return $this->context->getSkin();
+               }
+       }
+
+       /**
+        * @param string $skin
+        */
+       public function setSkin( $skin ) {
+               $this->skin = $skin;
+               $this->hash = null;
+       }
+
+       public function getUser() {
+               if ( !is_null( $this->user ) ) {
+                       return $this->user;
+               } else {
+                       return $this->context->getUser();
+               }
+       }
+
+       /**
+        * @param string $user
+        */
+       public function setUser( $user ) {
+               $this->user = $user;
+               $this->hash = null;
+       }
+
+       public function getDebug() {
+               if ( !is_null( $this->debug ) ) {
+                       return $this->debug;
+               } else {
+                       return $this->context->getDebug();
+               }
+       }
+
+       /**
+        * @param bool $debug
+        */
+       public function setDebug( $debug ) {
+               $this->debug = $debug;
+               $this->hash = null;
+       }
+
+       public function getOnly() {
+               if ( !is_null( $this->only ) ) {
+                       return $this->only;
+               } else {
+                       return $this->context->getOnly();
+               }
+       }
+
+       /**
+        * @param string $only
+        */
+       public function setOnly( $only ) {
+               $this->only = $only;
+               $this->hash = null;
+       }
+
+       public function getVersion() {
+               if ( !is_null( $this->version ) ) {
+                       return $this->version;
+               } else {
+                       return $this->context->getVersion();
+               }
+       }
+
+       /**
+        * @param string $version
+        */
+       public function setVersion( $version ) {
+               $this->version = $version;
+               $this->hash = null;
+       }
+
+       public function getRaw() {
+               if ( !is_null( $this->raw ) ) {
+                       return $this->raw;
+               } else {
+                       return $this->context->getRaw();
+               }
+       }
+
+       /**
+        * @param bool $raw
+        */
+       public function setRaw( $raw ) {
+               $this->raw = $raw;
+       }
+
+       public function getRequest() {
+               return $this->context->getRequest();
+       }
+
+       public function getResourceLoader() {
+               return $this->context->getResourceLoader();
+       }
+
+}
index 5ac874d..36e3a1b 100644 (file)
@@ -457,6 +457,22 @@ class ResourceLoader {
                return $this->sources;
        }
 
+       /**
+        * Get the URL to the load.php endpoint for the given
+        * ResourceLoader source
+        *
+        * @since 1.24
+        * @param string $source
+        * @throws MWException on an invalid $source name
+        * @return string
+        */
+       public function getLoadScript( $source ) {
+               if ( !isset( $this->sources[$source] ) ) {
+                       throw new MWException( "The $source source was never registered in ResourceLoader." );
+               }
+               return $this->sources[$source]['loadScript'];
+       }
+
        /**
         * Output a response to a load request, including the content-type header.
         *
@@ -1232,6 +1248,27 @@ class ResourceLoader {
 
        /**
         * Build a load.php URL
+        *
+        * @since 1.24
+        * @param string $source name of the ResourceLoader source
+        * @param ResourceLoaderContext $context
+        * @param array $extraQuery
+        * @return string URL to load.php. May be protocol-relative (if $wgLoadScript is procol-relative)
+        */
+       public function createLoaderURL( $source, ResourceLoaderContext $context,
+               $extraQuery = array()
+       ) {
+               $query = self::createLoaderQuery( $context, $extraQuery );
+               $script = $this->getLoadScript( $source );
+
+               // Prevent the IE6 extension check from being triggered (bug 28840)
+               // by appending a character that's invalid in Windows extensions ('*')
+               return wfExpandUrl( wfAppendQuery( $script, $query ) . '&*', PROTO_RELATIVE );
+       }
+
+       /**
+        * Build a load.php URL
+        * @deprecated since 1.24, use createLoaderURL instead
         * @param array $modules Array of module names (strings)
         * @param string $lang Language code
         * @param string $skin Skin name
@@ -1259,6 +1296,30 @@ class ResourceLoader {
                return wfExpandUrl( wfAppendQuery( $wgLoadScript, $query ) . '&*', PROTO_RELATIVE );
        }
 
+       /**
+        * Helper for createLoaderURL()
+        *
+        * @since 1.24
+        * @see makeLoaderQuery
+        * @param ResourceLoaderContext $context
+        * @param array $extraQuery
+        * @return array
+        */
+       public static function createLoaderQuery( ResourceLoaderContext $context, $extraQuery = array() ) {
+               return self::makeLoaderQuery(
+                       $context->getModules(),
+                       $context->getLanguage(),
+                       $context->getSkin(),
+                       $context->getUser(),
+                       $context->getVersion(),
+                       $context->getDebug(),
+                       $context->getOnly(),
+                       $context->getRequest()->getBool( 'printable' ),
+                       $context->getRequest()->getBool( 'handheld' ),
+                       $extraQuery
+               );
+       }
+
        /**
         * Build a query array (array representation of query string) for load.php. Helper
         * function for makeLoaderURL().
index 9013e2b..8994c0e 100644 (file)
@@ -208,21 +208,21 @@ class ResourceLoaderContext {
         * @return bool
         */
        public function shouldIncludeScripts() {
-               return is_null( $this->only ) || $this->only === 'scripts';
+               return is_null( $this->getOnly() ) || $this->getOnly() === 'scripts';
        }
 
        /**
         * @return bool
         */
        public function shouldIncludeStyles() {
-               return is_null( $this->only ) || $this->only === 'styles';
+               return is_null( $this->getOnly() ) || $this->getOnly() === 'styles';
        }
 
        /**
         * @return bool
         */
        public function shouldIncludeMessages() {
-               return is_null( $this->only ) || $this->only === 'messages';
+               return is_null( $this->getOnly() ) || $this->getOnly() === 'messages';
        }
 
        /**
@@ -231,8 +231,8 @@ class ResourceLoaderContext {
        public function getHash() {
                if ( !isset( $this->hash ) ) {
                        $this->hash = implode( '|', array(
-                               $this->getLanguage(), $this->getDirection(), $this->skin, $this->user,
-                               $this->debug, $this->only, $this->version
+                               $this->getLanguage(), $this->getDirection(), $this->getSkin(), $this->getUser(),
+                               $this->getDebug(), $this->getOnly(), $this->getVersion()
                        ) );
                }
                return $this->hash;
index f636105..00d245c 100644 (file)
@@ -144,17 +144,17 @@ abstract class ResourceLoaderModule {
         * @return array Array of URLs
         */
        public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
-               $url = ResourceLoader::makeLoaderURL(
-                       array( $this->getName() ),
-                       $context->getLanguage(),
-                       $context->getSkin(),
-                       $context->getUser(),
-                       $context->getVersion(),
-                       true, // debug
-                       'scripts', // only
-                       $context->getRequest()->getBool( 'printable' ),
-                       $context->getRequest()->getBool( 'handheld' )
+               $resourceLoader = $context->getResourceLoader();
+               $derivative = new DerivativeResourceLoaderContext( $context );
+               $derivative->setModules( array( $this->getName() ) );
+               $derivative->setOnly( 'scripts' );
+               $derivative->setDebug( true );
+
+               $url = $resourceLoader->createLoaderURL(
+                       $this->getSource(),
+                       $derivative
                );
+
                return array( $url );
        }
 
@@ -191,17 +191,17 @@ abstract class ResourceLoaderModule {
         * @return array array( mediaType => array( URL1, URL2, ... ), ... )
         */
        public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
-               $url = ResourceLoader::makeLoaderURL(
-                       array( $this->getName() ),
-                       $context->getLanguage(),
-                       $context->getSkin(),
-                       $context->getUser(),
-                       $context->getVersion(),
-                       true, // debug
-                       'styles', // only
-                       $context->getRequest()->getBool( 'printable' ),
-                       $context->getRequest()->getBool( 'handheld' )
+               $resourceLoader = $context->getResourceLoader();
+               $derivative = new DerivativeResourceLoaderContext( $context );
+               $derivative->setModules( array( $this->getName() ) );
+               $derivative->setOnly( 'styles' );
+               $derivative->setDebug( true );
+
+               $url = $resourceLoader->createLoaderURL(
+                       $this->getSource(),
+                       $derivative
                );
+
                return array( 'all' => array( $url ) );
        }
 
index 8a936c6..56eb0a0 100644 (file)
@@ -345,7 +345,6 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
        public static function getStartupModulesUrl( ResourceLoaderContext $context ) {
                // The core modules:
                $moduleNames = array( 'jquery', 'mediawiki' );
-               wfRunHooks( 'ResourceLoaderGetStartupModules', array( &$moduleNames ), '1.23' );
 
                // Get the latest version
                $loader = $context->getResourceLoader();
index e7a09d7..8a08fd1 100644 (file)
@@ -885,6 +885,45 @@ class RevDelArchivedFileItem extends RevDelFileItem {
                }
                return $link;
        }
+
+       public function getApiData( ApiResult $result ) {
+               $file = $this->file;
+               $user = $this->list->getUser();
+               $ret = array(
+                       'title' => $this->list->title->getPrefixedText(),
+                       'timestamp' => wfTimestamp( TS_ISO_8601, $file->getTimestamp() ),
+                       'width' => $file->getWidth(),
+                       'height' => $file->getHeight(),
+                       'size' => $file->getSize(),
+               );
+               $ret += $file->isDeleted( Revision::DELETED_USER ) ? array( 'userhidden' => '' ) : array();
+               $ret += $file->isDeleted( Revision::DELETED_COMMENT ) ? array( 'commenthidden' => '' ) : array();
+               $ret += $this->isDeleted() ? array( 'contenthidden' => '' ) : array();
+               if ( $this->canViewContent() ) {
+                       $ret += array(
+                               'url' => SpecialPage::getTitleFor( 'Revisiondelete' )->getLinkURL(
+                                       array(
+                                               'target' => $this->list->title->getPrefixedText(),
+                                               'file' => $file->getKey(),
+                                               'token' => $user->getEditToken( $file->getKey() )
+                                       ),
+                                       false, PROTO_RELATIVE
+                               ),
+                       );
+               }
+               if ( $file->userCan( Revision::DELETED_USER, $user ) ) {
+                       $ret += array(
+                               'userid' => $file->getUser( 'id' ),
+                               'user' => $file->getUser( 'text' ),
+                       );
+               }
+               if ( $file->userCan( Revision::DELETED_COMMENT, $user ) ) {
+                       $ret += array(
+                               'comment' => $file->getRawDescription(),
+                       );
+               }
+               return $ret;
+       }
 }
 
 /**
index 8ff2640..581d8bc 100644 (file)
@@ -174,8 +174,6 @@ class SearchMySQL extends SearchDatabase {
        }
 
        protected function searchInternal( $term, $fulltext ) {
-               global $wgCountTotalSearchHits;
-
                // This seems out of place, why is this called with empty term?
                if ( trim( $term ) === '' ) {
                        return null;
@@ -189,19 +187,17 @@ class SearchMySQL extends SearchDatabase {
                );
 
                $total = null;
-               if ( $wgCountTotalSearchHits ) {
-                       $query = $this->getCountQuery( $filteredTerm, $fulltext );
-                       $totalResult = $this->db->select(
-                               $query['tables'], $query['fields'], $query['conds'],
-                               __METHOD__, $query['options'], $query['joins']
-                       );
-
-                       $row = $totalResult->fetchObject();
-                       if ( $row ) {
-                               $total = intval( $row->c );
-                       }
-                       $totalResult->free();
+               $query = $this->getCountQuery( $filteredTerm, $fulltext );
+               $totalResult = $this->db->select(
+                       $query['tables'], $query['fields'], $query['conds'],
+                       __METHOD__, $query['options'], $query['joins']
+               );
+
+               $row = $totalResult->fetchObject();
+               if ( $row ) {
+                       $total = intval( $row->c );
                }
+               $totalResult->free();
 
                return new SqlSearchResultSet( $resultSet, $this->searchTerms, $total );
        }
index f430dd0..698f93c 100644 (file)
@@ -173,7 +173,12 @@ class SqlSearchResultSet extends SearchResultSet {
        }
 
        function getTotalHits() {
-               return $this->totalHits;
+               if ( !is_null( $this->totalHits ) ) {
+                       return $this->totalHits;
+               } else {
+                       // Special:Search expects a number here.
+                       return $this->numRows();
+               }
        }
 }
 
index 8e820f3..05d5ca0 100644 (file)
@@ -164,7 +164,7 @@ class SearchSqlite extends SearchDatabase {
        }
 
        protected function searchInternal( $term, $fulltext ) {
-               global $wgCountTotalSearchHits, $wgContLang;
+               global $wgContLang;
 
                if ( !$this->fulltextSearchSupported() ) {
                        return null;
@@ -174,14 +174,12 @@ class SearchSqlite extends SearchDatabase {
                $resultSet = $this->db->query( $this->getQuery( $filteredTerm, $fulltext ) );
 
                $total = null;
-               if ( $wgCountTotalSearchHits ) {
-                       $totalResult = $this->db->query( $this->getCountQuery( $filteredTerm, $fulltext ) );
-                       $row = $totalResult->fetchObject();
-                       if ( $row ) {
-                               $total = intval( $row->c );
-                       }
-                       $totalResult->free();
+               $totalResult = $this->db->query( $this->getCountQuery( $filteredTerm, $fulltext ) );
+               $row = $totalResult->fetchObject();
+               if ( $row ) {
+                       $total = intval( $row->c );
                }
+               $totalResult->free();
 
                return new SqlSearchResultSet( $resultSet, $this->searchTerms, $total );
        }
index 4854bcb..9711f04 100644 (file)
@@ -215,7 +215,7 @@ class MediaWikiSite extends Site {
                        // Filter the substructure down to what we actually are using.
                        $collectedHits = array_filter(
                                array_values( $externalData['query'][$listId] ),
-                               function( $a ) use ( $fieldId, $pageTitle ) {
+                               function ( $a ) use ( $fieldId, $pageTitle ) {
                                        return $a[$fieldId] === $pageTitle;
                                }
                        );
index e3559f5..fafb14c 100644 (file)
@@ -700,7 +700,7 @@ class Site implements Serializable {
 }
 
 /**
- * @deprecated
+ * @deprecated since 1.21
  */
 class SiteObject extends Site {
 }
index dfe4ec5..ecc38e2 100644 (file)
@@ -352,7 +352,7 @@ class SiteList extends GenericArrayObject {
 }
 
 /**
- * @deprecated
+ * @deprecated since 1.21
  */
 class SiteArray extends SiteList {
 }
index f382d98..6659407 100644 (file)
@@ -460,7 +460,7 @@ class SiteSQLStore implements SiteStore {
 }
 
 /**
- * @deprecated
+ * @deprecated since 1.21
  */
 class Sites extends SiteSQLStore {
 
@@ -468,7 +468,7 @@ class Sites extends SiteSQLStore {
         * Factory for creating new site objects.
         *
         * @since 1.21
-        * @deprecated
+        * @deprecated since 1.21
         *
         * @param string|bool $globalId
         *
@@ -485,7 +485,7 @@ class Sites extends SiteSQLStore {
        }
 
        /**
-        * @deprecated
+        * @deprecated since 1.21
         * @return SiteStore
         */
        public static function singleton() {
@@ -499,7 +499,7 @@ class Sites extends SiteSQLStore {
        }
 
        /**
-        * @deprecated
+        * @deprecated since 1.21
         * @param string $group
         * @return SiteList
         */
index ad1ee36..008200d 100644 (file)
@@ -348,10 +348,9 @@ abstract class ChangesListSpecialPage extends SpecialPage {
        abstract public function outputChangesList( $rows, $opts );
 
        /**
-        * Return the text to be displayed above the changes
+        * Set the text to be displayed above the changes
         *
         * @param FormOptions $opts
-        * @return string XHTML
         */
        public function doHeader( $opts ) {
                $this->setTopText( $opts );
index 1d8f57a..bf86ab2 100644 (file)
@@ -114,9 +114,10 @@ abstract class FormSpecialPage extends SpecialPage {
        /**
         * Process the form on POST submission.
         * @param array $data
-        * @return bool|array True for success, false for didn't-try, array of errors on failure
+        * @param HTMLForm $form
+        * @return bool|string|array|Status As documented for HTMLForm::trySubmit.
         */
-       abstract public function onSubmit( array $data );
+       abstract public function onSubmit( array $data /* $form = null */ );
 
        /**
         * Do something exciting on successful processing of the form, most likely to show a
index c42c089..6db9e5f 100644 (file)
@@ -92,12 +92,16 @@ class ActiveUsersPager extends UsersPager {
        function getQueryInfo() {
                $dbr = $this->getDatabase();
 
+               $activeUserSeconds = $this->getConfig()->get( 'ActiveUserDays' ) * 86400;
+               $timestamp = $dbr->timestamp( wfTimestamp( TS_UNIX ) - $activeUserSeconds );
                $conds = array(
                        'qcc_type' => 'activeusers',
                        'qcc_namespace' => NS_USER,
                        'user_name = qcc_title',
                        'rc_user_text = qcc_title',
-                       'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ) // Don't count wikidata.
+                       'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ), // Don't count wikidata.
+                       'rc_log_type IS NULL OR rc_log_type != ' . $dbr->addQuotes( 'newusers' ),
+                       'rc_timestamp >= ' . $dbr->addQuotes( $timestamp ),
                );
                if ( $this->requestedUser != '' ) {
                        $conds[] = 'qcc_title >= ' . $dbr->addQuotes( $this->requestedUser );
@@ -291,6 +295,7 @@ class SpecialActiveUsers extends SpecialPage {
                        'qci_timestamp',
                        array( 'qci_type' => 'activeusers' )
                );
+
                if ( !wfReadOnly() ) {
                        if ( !$cTime || ( time() - wfTimestamp( TS_UNIX, $cTime ) ) > $period ) {
                                $dbw = wfGetDB( DB_MASTER );
@@ -299,7 +304,7 @@ class SpecialActiveUsers extends SpecialPage {
                                } else {
                                        $window = $period * 2;
                                }
-                               self::doQueryCacheUpdate( $dbw, $window );
+                               $cTime = self::doQueryCacheUpdate( $dbw, $window ) ?: $cTime;
                        }
                }
 
@@ -322,7 +327,7 @@ class SpecialActiveUsers extends SpecialPage {
         *
         * @param DatabaseBase $dbw
         * @param int $window Maximum time range of new data to scan (in seconds)
-        * @return bool Success
+        * @return int|bool UNIX timestamp the cache is now up-to-date as of (false on error)
         */
        protected static function doQueryCacheUpdate( DatabaseBase $dbw, $window ) {
                global $wgActiveUserDays;
@@ -406,7 +411,9 @@ class SpecialActiveUsers extends SpecialPage {
                        }
                        foreach ( array_chunk( $newRows, 500 ) as $rowBatch ) {
                                $dbw->insert( 'querycachetwo', $rowBatch, __METHOD__ );
-                               wfWaitForSlaves();
+                               if ( !$dbw->trxLevel() ) {
+                                       wfWaitForSlaves();
+                               }
                        }
                }
 
@@ -420,6 +427,6 @@ class SpecialActiveUsers extends SpecialPage {
 
                $dbw->unlock( $lockKey, __METHOD__ );
 
-               return true;
+               return $eTimestamp;
        }
 }
index dcd2443..ba5c7ec 100644 (file)
@@ -260,7 +260,7 @@ class SpecialChangePassword extends FormSpecialPage {
                        );
                }
 
-               // @TODO Make these separate messages, since the message is written for both cases
+               // @todo Make these separate messages, since the message is written for both cases
                if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
                        wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
                        throw new PasswordError( $this->msg( 'resetpass-wrong-oldpass' )->text() );
index 05bbb5a..251ac51 100644 (file)
@@ -206,7 +206,7 @@ class SpecialContributions extends IncludableSpecialPage {
                                $output = $pager->getBody();
                                if ( !$this->including() ) {
                                        $output = '<p>' . $pager->getNavigationBar() . '</p>' .
-                                               $output.
+                                               $output .
                                                '<p>' . $pager->getNavigationBar() . '</p>';
                                }
                                $out->addHTML( $output );
@@ -790,7 +790,7 @@ class ContribsPager extends ReverseChronologicalPager {
                // Paranoia: avoid brute force searches (bug 17342)
                if ( !$user->isAllowed( 'deletedhistory' ) ) {
                        $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0';
-               } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                        $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::SUPPRESSED_USER ) .
                                ' != ' . Revision::SUPPRESSED_USER;
                }
index f3af312..30e3833 100644 (file)
@@ -43,7 +43,7 @@ class SpecialCreateAccount extends SpecialRedirectToSpecial {
        }
 
        public function isRestricted() {
-               return true;
+               return !User::groupHasPermission( '*', 'createaccount' );
        }
 
        public function userCanExecute( User $user ) {
index 4df5b2b..b69eb63 100644 (file)
@@ -62,7 +62,7 @@ class DeletedContribsPager extends IndexPager {
                // Paranoia: avoid brute force searches (bug 17792)
                if ( !$user->isAllowed( 'deletedhistory' ) ) {
                        $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::DELETED_USER ) . ' = 0';
-               } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                        $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::SUPPRESSED_USER ) .
                                ' != ' . Revision::SUPPRESSED_USER;
                }
index 369f11f..355726a 100644 (file)
@@ -244,7 +244,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                $talk = $this->msg( 'talkpagelinktext' )->escaped();
                // Do a batch existence check
                $batch = new LinkBatch();
-               if (count($titles) >= 100) {
+               if ( count( $titles ) >= 100 ) {
                        $output = wfMessage( 'watchlistedit-too-many' )->parse();
                        return;
                }
index b88e196..aec1257 100644 (file)
@@ -132,7 +132,11 @@ class LinkSearchPage extends QueryPage {
                                'target',
                                'target',
                                50,
-                               $target
+                               $target,
+                               array(
+                                       // URLs are always ltr
+                                       'dir' => 'ltr',
+                               )
                        ) . "\n";
 
                if ( !$wgMiserMode ) {
index 3715b8b..2ce45ac 100644 (file)
@@ -460,6 +460,19 @@ class ImageListPager extends TablePager {
                                        );
                                        $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped();
 
+                                       // Add delete links if allowed
+                                       // From https://github.com/Wikia/app/pull/3859
+                                       if ( $filePage->userCan( 'delete', $this->getUser() ) ) {
+                                               $deleteMsg = $this->msg( 'listfiles-delete' )->escaped();
+
+                                               $delete = Linker::linkKnown(
+                                                       $filePage, $deleteMsg, array(), array( 'action' => 'delete' )
+                                               );
+                                               $delete = $this->msg( 'parentheses' )->rawParams( $delete )->escaped();
+
+                                               return "$link $download $delete";
+                                       }
+
                                        return "$link $download";
                                } else {
                                        return htmlspecialchars( $value );
@@ -547,7 +560,9 @@ class ImageListPager extends TablePager {
                if ( !is_null( $this->mUserName ) ) {
                        # Append the username to the query string
                        foreach ( $queries as &$query ) {
-                               $query['user'] = $this->mUserName;
+                               if ( $query !== false ) {
+                                       $query['user'] = $this->mUserName;
+                               }
                        }
                }
 
index 367adef..53dddc7 100644 (file)
@@ -193,7 +193,7 @@ class UsersPager extends AlphabeticPager {
                $edits = '';
                global $wgEdititis;
                if ( !$this->including && $wgEdititis ) {
-                       // @fixme i18n issue: Hardcoded square brackets.
+                       // @todo fixme i18n issue: Hardcoded square brackets.
                        $edits = ' [' .
                                $this->msg( 'usereditcount' )->numParams( $row->edits )->escaped() .
                                ']';
@@ -399,6 +399,18 @@ class SpecialListUsers extends IncludableSpecialPage {
                $this->getOutput()->addHTML( $s );
        }
 
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * @param string $search Prefix to search for
+        * @param integer $limit Maximum number of results to return
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit = 10 ) {
+               $subpages = User::getAllGroups();
+               return self::prefixSearchArray( $search, $limit, $subpages );
+       }
+
        protected function getGroupName() {
                return 'users';
        }
index a27cf4c..9347af7 100644 (file)
@@ -133,7 +133,7 @@ class SpecialMergeHistory extends SpecialPage {
                if ( !$this->mTargetObj instanceof Title ) {
                        $errors[] = $this->msg( 'mergehistory-invalid-source' )->parseAsBlock();
                } elseif ( !$this->mTargetObj->exists() ) {
-                       $errors[] = $this->msg( 'mergehistory-no-source', array( 'parse' ),
+                       $errors[] = $this->msg( 'mergehistory-no-source',
                                wfEscapeWikiText( $this->mTargetObj->getPrefixedText() )
                        )->parseAsBlock();
                }
@@ -141,7 +141,7 @@ class SpecialMergeHistory extends SpecialPage {
                if ( !$this->mDestObj instanceof Title ) {
                        $errors[] = $this->msg( 'mergehistory-invalid-destination' )->parseAsBlock();
                } elseif ( !$this->mDestObj->exists() ) {
-                       $errors[] = $this->msg( 'mergehistory-no-destination', array( 'parse' ),
+                       $errors[] = $this->msg( 'mergehistory-no-destination',
                                wfEscapeWikiText( $this->mDestObj->getPrefixedText() )
                        )->parseAsBlock();
                }
@@ -452,6 +452,7 @@ class SpecialMergeHistory extends SpecialPage {
                                $dbw->insert( 'pagelinks',
                                        array(
                                                'pl_from' => $this->mDestID,
+                                               'pl_from_namespace' => $destTitle->getNamespace(),
                                                'pl_namespace' => $destTitle->getNamespace(),
                                                'pl_title' => $destTitle->getDBkey() ),
                                        __METHOD__
@@ -476,7 +477,7 @@ class SpecialMergeHistory extends SpecialPage {
                        array( $destTitle->getPrefixedText(), $timestampLimit ), $this->getUser()
                );
 
-               # @TODO: message should use redirect=no
+               # @todo message should use redirect=no
                $this->getOutput()->addWikiMsg( 'mergehistory-success',
                        $targetTitle->getPrefixedText(), $destTitle->getPrefixedText(), $count );
 
index dce5ad9..7223efd 100644 (file)
@@ -567,10 +567,14 @@ class MovePageForm extends UnlistedSpecialPage {
                $oldLink = Linker::link(
                        $ot,
                        null,
-                       array(),
+                       array( 'id' => 'movepage-oldlink' ),
                        array( 'redirect' => 'no' )
                );
-               $newLink = Linker::linkKnown( $nt );
+               $newLink = Linker::linkKnown(
+                       $nt,
+                       null,
+                       array( 'id' => 'movepage-newlink' )
+               );
                $oldText = $ot->getPrefixedText();
                $newText = $nt->getPrefixedText();
 
index a432f10..24eca07 100644 (file)
@@ -107,7 +107,7 @@ class SpecialPageLanguage extends FormSpecialPage {
                // Returns the default since the page is not loaded from DB
                $defLang = $title->getPageLanguage()->getCode();
 
-               $pageId =  $title->getArticleID();
+               $pageId = $title->getArticleID();
 
                // Check if article exists
                if ( !$pageId ) {
index f770307..aa8ed82 100644 (file)
@@ -350,10 +350,9 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
        }
 
        /**
-        * Return the text to be displayed above the changes
+        * Set the text to be displayed above the changes
         *
         * @param FormOptions $opts
-        * @return string XHTML
         */
        public function doHeader( $opts ) {
                global $wgScript;
index d3b168b..9cec847 100644 (file)
@@ -161,7 +161,14 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                        throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
                }
                $this->typeLabels = self::$UILabels[$this->typeName];
+               $list = $this->getList();
+               $list->reset();
+               $bitfield = $list->current()->getBits();
                $this->mIsAllowed = $user->isAllowed( RevisionDeleter::getRestriction( $this->typeName ) );
+               $canViewSuppressedOnly = $this->getUser()->isAllowed( 'viewsuppressed' ) &&
+                       !$this->getUser()->isAllowed( 'suppressrevision' );
+               $pageIsSuppressed = $bitfield & Revision::DELETED_RESTRICTED;
+               $this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed );
 
                # Allow the list type to adjust the passed target
                $this->targetObj = RevisionDeleter::suggestTarget(
@@ -417,7 +424,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                                                Xml::listDropDown( 'wpRevDeleteReasonList',
                                                        $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->text(),
                                                        $this->msg( 'revdelete-reasonotherlist' )->inContentLanguage()->text(),
-                                                       $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ), 'wpReasonDropDown', 1
+                                                       $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ), 'wpReasonDropDown'
                                                ) .
                                        '</td>' .
                                "</tr><tr>\n" .
@@ -444,12 +451,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                                Html::hidden( 'target', $this->targetObj->getPrefixedText() ) .
                                Html::hidden( 'type', $this->typeName ) .
                                Html::hidden( 'ids', implode( ',', $this->ids ) ) .
-                               Xml::closeElement( 'fieldset' ) . "\n";
-               } else {
-                       $out = '';
-               }
-               if ( $this->mIsAllowed ) {
-                       $out .= Xml::closeElement( 'form' ) . "\n";
+                               Xml::closeElement( 'fieldset' ) . "\n" .
+                               Xml::closeElement( 'form' ) . "\n";
                        // Show link to edit the dropdown reasons
                        if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
                                $title = Title::makeTitle( NS_MEDIAWIKI, 'Revdelete-reason-dropdown' );
@@ -461,6 +464,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                                );
                                $out .= Xml::tags( 'p', array( 'class' => 'mw-revdel-editreasons' ), $link ) . "\n";
                        }
+               } else {
+                       $out = '';
                }
                $this->getOutput()->addHTML( $out );
        }
index 13591aa..15a7b59 100644 (file)
@@ -114,7 +114,7 @@ class SpecialSearch extends SpecialPage {
         */
        public function load() {
                $request = $this->getRequest();
-               list( $this->limit, $this->offset ) = $request->getLimitOffset( 20 );
+               list( $this->limit, $this->offset ) = $request->getLimitOffset( 20, '' );
                $this->mPrefix = $request->getVal( 'prefix', '' );
 
                $user = $this->getUser();
@@ -207,8 +207,7 @@ class SpecialSearch extends SpecialPage {
 
                $profile = new ProfileSection( __METHOD__ );
                $search = $this->getSearchEngine();
-               // Request an extra result to determine whether a "next page" link is useful
-               $search->setLimitOffset( $this->limit + 1, $this->offset );
+               $search->setLimitOffset( $this->limit, $this->offset );
                $search->setNamespaces( $this->namespaces );
                $this->saveNamespaces();
                $search->prefix = $this->mPrefix;
@@ -352,7 +351,7 @@ class SpecialSearch extends SpecialPage {
                                        $this->offset,
                                        $this->limit,
                                        $this->powerSearchOptions() + array( 'search' => $term ),
-                                       max( $titleMatchesNum, $textMatchesNum ) <= $this->limit
+                                       $this->limit + $this->offset >= $totalRes
                                );
                        }
                        wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
@@ -551,11 +550,9 @@ class SpecialSearch extends SpecialPage {
 
                $out = "<ul class='mw-search-results'>\n";
                $result = $matches->next();
-               $count = 0;
-               while ( $result && $count < $this->limit ) {
+               while ( $result ) {
                        $out .= $this->showHit( $result, $terms );
                        $result = $matches->next();
-                       $count++;
                }
                $out .= "</ul>\n";
 
@@ -717,7 +714,7 @@ class SpecialSearch extends SpecialPage {
                                                $thumb->toHtml( array( 'desc-link' => true ) ) .
                                                '</td>' .
                                                '<td style="vertical-align: top;">' .
-                                               "{$link} {$fileMatch}" .
+                                               "{$link} {$redirect} {$section} {$fileMatch}" .
                                                $extract .
                                                "<div class='mw-search-result-data'>{$score}{$desc} - {$date}{$related}</div>" .
                                                '</td>' .
@@ -896,9 +893,7 @@ class SpecialSearch extends SpecialPage {
                        }
 
                        $rows[$subject] .=
-                               Xml::openElement(
-                                       'td', array( 'style' => 'white-space: nowrap' )
-                               ) .
+                               Xml::openElement( 'td' ) .
                                Xml::checkLabel(
                                        $name,
                                        "ns{$namespace}",
@@ -956,10 +951,7 @@ class SpecialSearch extends SpecialPage {
                }
 
                // Return final output
-               return Xml::openElement(
-                       'fieldset',
-                       array( 'id' => 'mw-searchoptions', 'style' => 'margin:0em;' )
-               ) .
+               return Xml::openElement( 'fieldset', array( 'id' => 'mw-searchoptions' ) ) .
                        Xml::element( 'legend', null, $this->msg( 'powersearch-legend' )->text() ) .
                        Xml::tags( 'h4', null, $this->msg( 'powersearch-ns' )->parse() ) .
                        Html::element( 'div', array( 'id' => 'mw-search-togglebox' ) ) .
@@ -1104,7 +1096,8 @@ class SpecialSearch extends SpecialPage {
                                ->params( wfEscapeWikiText( $term ) )
                                ->numParams( $resultsShown )
                                ->parse();
-                       $out .= Xml::tags( 'div', array( 'class' => 'results-info' ), $top );
+                       $out .= Xml::tags( 'div', array( 'class' => 'results-info' ), $top ) .
+                               Xml::element( 'div', array( 'style' => 'clear:both' ), '', false );
                }
 
                return $out . $this->didYouMeanHtml;
index bea65ba..73bdbd6 100644 (file)
@@ -59,7 +59,7 @@ class SpecialTrackingCategories extends SpecialPage {
                        </tr></thead>"
                );
 
-               foreach( $wgTrackingCategories as $catMsg ) {
+               foreach ( $wgTrackingCategories as $catMsg ) {
                        /*
                         * Check if the tracking category varies by namespace
                         * Otherwise only pages in the current namespace will be displayed
index 797543f..96e4dbf 100644 (file)
@@ -83,7 +83,7 @@ class SpecialUnblock extends SpecialPage {
                        'Target' => array(
                                'type' => 'text',
                                'label-message' => 'ipaddressorusername',
-                               'tabindex' => '1',
+                               'autofocus' => true,
                                'size' => '45',
                                'required' => true,
                        ),
@@ -131,6 +131,9 @@ class SpecialUnblock extends SpecialPage {
                                                $fields['Target']['default'] = "#{$this->target}";
                                                break;
                                }
+                               // target is hidden, so the reason is the first element
+                               $fields['Target']['autofocus'] = false;
+                               $fields['Reason']['autofocus'] = true;
                        }
                } else {
                        $fields['Target']['default'] = $this->target;
index 01c0aaf..fc18706 100644 (file)
@@ -788,6 +788,18 @@ class UploadForm extends HTMLForm {
                wfRunHooks( 'UploadFormInitDescriptor', array( &$descriptor ) );
                parent::__construct( $descriptor, $context, 'upload' );
 
+               # Add a link to edit MediaWik:Licenses
+               if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
+                       $licensesLink = Linker::link(
+                               Title::makeTitle( NS_MEDIAWIKI, 'Licenses' ),
+                               $this->msg( 'licenses-edit' )->escaped(),
+                               array(),
+                               array( 'action' => 'edit' )
+                       );
+                       $editLicenses = '<p class="mw-upload-editlicenses">' . $licensesLink . '</p>';
+                       $this->addFooterText( $editLicenses, 'description' );
+               }
+
                # Set some form properties
                $this->setSubmitText( $this->msg( 'uploadbtn' )->text() );
                $this->setSubmitName( 'wpUpload' );
@@ -827,7 +839,7 @@ class UploadForm extends HTMLForm {
                }
 
                $canUploadByUrl = UploadFromUrl::isEnabled()
-                       && UploadFromUrl::isAllowed( $this->getUser() )
+                       && ( UploadFromUrl::isAllowed( $this->getUser() ) === true )
                        && $wgCopyUploadsFromSpecialUpload;
                $radio = $canUploadByUrl;
                $selectedSourceType = strtolower( $this->getRequest()->getText( 'wpSourceType', 'File' ) );
index c9e2e18..28ad0f4 100644 (file)
@@ -211,7 +211,9 @@ class SpecialVersion extends SpecialPage {
                // wikimarkup can be used.
                $software = array();
                $software['[https://www.mediawiki.org/ MediaWiki]'] = self::getVersionLinked();
-               $software['[http://www.php.net/ PHP]'] = phpversion() . " (" . PHP_SAPI . ")";
+               $phpKey = wfIsHHVM() ? '[http://hhvm.com/ HHVM]' :
+                       '[http://www.php.net/ PHP]';
+               $software[$phpKey] = PHP_VERSION . " (" . PHP_SAPI . ")";
                $software[$dbr->getSoftwareLink()] = $dbr->getServerInfo();
 
                // Allow a hook to add/remove items.
@@ -511,7 +513,7 @@ class SpecialVersion extends SpecialPage {
                        );
 
                        array_walk( $tags, function ( &$value ) {
-                               $value = '&lt;' . htmlentities( $value ) . '&gt;';
+                               $value = '&lt;' . htmlspecialchars( $value ) . '&gt;';
                        } );
                        $out .= $this->listToText( $tags );
                } else {
@@ -648,6 +650,7 @@ class SpecialVersion extends SpecialPage {
 
                if ( isset( $extension['path'] ) ) {
                        global $IP;
+                       $extensionPath = dirname( $extension['path'] );
                        if ( $this->coreId == '' ) {
                                wfDebug( 'Looking up core head id' );
                                $coreHeadSHA1 = self::getGitHeadSha1( $IP );
@@ -666,7 +669,6 @@ class SpecialVersion extends SpecialPage {
 
                        if ( !$vcsVersion ) {
                                wfDebug( "Getting VCS info for extension $extensionName" );
-                               $extensionPath = dirname( $extension['path'] );
                                $gitInfo = new GitInfo( $extensionPath );
                                $vcsVersion = $gitInfo->getHeadSHA1();
                                if ( $vcsVersion !== false ) {
index fa68504..8269b01 100644 (file)
@@ -49,23 +49,44 @@ class WantedFilesPage extends WantedQueryPage {
                        $category = false;
                }
 
+               $noForeign = '';
+               if ( !$this->likelyToHaveFalsePositives() ) {
+                       // Additional messages for grep:
+                       // wantedfiletext-cat-noforeign, wantedfiletext-nocat
+                       $noForeign = '-noforeign';
+               }
+
                if ( $category ) {
                        return $this
-                               ->msg( 'wantedfiletext-cat' )
+                               ->msg( 'wantedfiletext-cat' . $noForeign )
                                ->params( $category->getFullText() )
                                ->parseAsBlock();
                } else {
                        return $this
-                               ->msg( 'wantedfiletext-nocat' )
+                               ->msg( 'wantedfiletext-nocat' . $noForeign )
                                ->parseAsBlock();
                }
        }
 
+       /**
+        * Whether foreign repos are likely to cause false positives
+        *
+        * In its own function to allow subclasses to override.
+        * @see SpecialWantedFilesGUOverride in GlobalUsage extension.
+        * @since 1.24
+        */
+       protected function likelyToHaveFalsePositives() {
+               return RepoGroup::singleton()->hasForeignRepos();
+       }
+
        /**
         * KLUGE: The results may contain false positives for files
         * that exist e.g. in a shared repo.  Setting this at least
         * keeps them from showing up as redlinks in the output, even
         * if it doesn't fix the real problem (bug 6220).
+        *
+        * @note could also have existing links here from broken file
+        * redirects.
         * @return bool
         */
        function forceExistenceCheck() {
@@ -74,17 +95,39 @@ class WantedFilesPage extends WantedQueryPage {
 
        function getQueryInfo() {
                return array(
-                       'tables' => array( 'imagelinks', 'image' ),
+                       'tables' => array(
+                               'imagelinks',
+                               'page',
+                               'redirect',
+                               'img1' => 'image',
+                               'img2' => 'image',
+                       ),
                        'fields' => array(
                                'namespace' => NS_FILE,
                                'title' => 'il_to',
                                'value' => 'COUNT(*)'
                        ),
-                       'conds' => array( 'img_name IS NULL' ),
+                       'conds' => array(
+                               'img1.img_name' => null,
+                               // We also need to exclude file redirects
+                               'img2.img_name' => null,
+                       ),
                        'options' => array( 'GROUP BY' => 'il_to' ),
-                       'join_conds' => array( 'image' =>
-                               array( 'LEFT JOIN',
-                                       array( 'il_to = img_name' )
+                       'join_conds' => array(
+                               'img1' => array( 'LEFT JOIN',
+                                       'il_to = img1.img_name'
+                               ),
+                               'page' => array( 'LEFT JOIN', array(
+                                       'il_to = page_title',
+                                       'page_namespace' => NS_FILE,
+                               ) ),
+                               'redirect' => array( 'LEFT JOIN', array(
+                                       'page_id = rd_from',
+                                       'rd_namespace' => NS_FILE,
+                                       'rd_interwiki' => ''
+                               ) ),
+                               'img2' => array( 'LEFT JOIN',
+                                       'rd_title = img2.img_name'
                                )
                        )
                );
index 21a1f9b..94de5ce 100644 (file)
@@ -258,7 +258,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                // the necessary rights.
                if ( !$user->isAllowed( 'deletedhistory' ) ) {
                        $bitmask = LogPage::DELETED_ACTION;
-               } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
                        $bitmask = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED;
                } else {
                        $bitmask = 0;
@@ -388,10 +388,9 @@ class SpecialWatchlist extends ChangesListSpecialPage {
        }
 
        /**
-        * Return the text to be displayed above the changes
+        * Set the text to be displayed above the changes
         *
         * @param FormOptions $opts
-        * @return string XHTML
         */
        public function doHeader( $opts ) {
                $user = $this->getUser();
index d980f79..694bc83 100644 (file)
@@ -101,10 +101,10 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
         * @param int $back Display from this article ID at backwards scrolling (default: 0)
         */
        function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) {
-               global $wgMaxRedirectLinksRetrieved;
+               global $wgMaxRedirectLinksRetrieved, $wgUseLinkNamespaceDBFields;
+
                $out = $this->getOutput();
                $dbr = wfGetDB( DB_SLAVE );
-               $options = array();
 
                $hidelinks = $this->opts->getValue( 'hidelinks' );
                $hideredirs = $this->opts->getValue( 'hideredirs' );
@@ -113,77 +113,85 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
 
                $fetchlinks = ( !$hidelinks || !$hideredirs );
 
-               // Make the query
-               $plConds = array(
-                       'page_id=pl_from',
+               // Build query conds in concert for all three tables...
+               $conds['pagelinks'] = array(
                        'pl_namespace' => $target->getNamespace(),
                        'pl_title' => $target->getDBkey(),
                );
-               if ( $hideredirs ) {
-                       $plConds['rd_from'] = null;
-               } elseif ( $hidelinks ) {
-                       $plConds[] = 'rd_from is NOT NULL';
-               }
-
-               $tlConds = array(
-                       'page_id=tl_from',
+               $conds['templatelinks'] = array(
                        'tl_namespace' => $target->getNamespace(),
                        'tl_title' => $target->getDBkey(),
                );
-
-               $ilConds = array(
-                       'page_id=il_from',
+               $conds['imagelinks'] = array(
                        'il_to' => $target->getDBkey(),
                );
 
                $namespace = $this->opts->getValue( 'namespace' );
                if ( is_int( $namespace ) ) {
-                       $plConds['page_namespace'] = $namespace;
-                       $tlConds['page_namespace'] = $namespace;
-                       $ilConds['page_namespace'] = $namespace;
+                       if ( $wgUseLinkNamespaceDBFields ) {
+                               $conds['pagelinks']['pl_from_namespace'] = $namespace;
+                               $conds['templatelinks']['tl_from_namespace'] = $namespace;
+                               $conds['imagelinks']['il_from_namespace'] = $namespace;
+                       } else {
+                               $conds['pagelinks']['page_namespace'] = $namespace;
+                               $conds['templatelinks']['page_namespace'] = $namespace;
+                               $conds['imagelinks']['page_namespace'] = $namespace;
+                       }
                }
 
                if ( $from ) {
-                       $tlConds[] = "tl_from >= $from";
-                       $plConds[] = "pl_from >= $from";
-                       $ilConds[] = "il_from >= $from";
+                       $conds['templatelinks'][] = "tl_from >= $from";
+                       $conds['pagelinks'][] = "pl_from >= $from";
+                       $conds['imagelinks'][] = "il_from >= $from";
                }
 
-               // Read an extra row as an at-end check
-               $queryLimit = $limit + 1;
-
-               $options['LIMIT'] = $queryLimit;
-               $fields = array( 'page_id', 'page_namespace', 'page_title', 'rd_from' );
+               if ( $hideredirs ) {
+                       $conds['pagelinks']['rd_from'] = null;
+               } elseif ( $hidelinks ) {
+                       $conds['pagelinks'][] = 'rd_from is NOT NULL';
+               }
 
-               $joinConds = array( 'redirect' => array( 'LEFT JOIN', array(
-                       'rd_from = page_id',
-                       'rd_namespace' => $target->getNamespace(),
-                       'rd_title' => $target->getDBkey(),
-                       'rd_interwiki = ' . $dbr->addQuotes( '' ) . ' OR rd_interwiki IS NULL'
-               ) ) );
+               $queryFunc = function( $dbr, $table, $fromCol ) use ( $conds, $target, $limit ) {
+                       global $wgUseLinkNamespaceDBFields;
+                       // Read an extra row as an at-end check
+                       $queryLimit = $limit + 1;
+                       $on = array(
+                               "rd_from = $fromCol",
+                               'rd_title' => $target->getDBkey(),
+                               'rd_interwiki = ' . $dbr->addQuotes( '' ) . ' OR rd_interwiki IS NULL'
+                       );
+                       if ( $wgUseLinkNamespaceDBFields ) { // migration check
+                               $on['rd_namespace'] = $target->getNamespace();
+                       }
+                       // Inner LIMIT is 2X in case of stale backlinks with no page
+                       $subQuery = $dbr->selectSqlText(
+                               array( $table, 'redirect' ),
+                               array( $fromCol, 'rd_from' ),
+                               $conds[$table],
+                               __CLASS__ . '::showIndirectLinks',
+                               array( 'ORDER BY' => $fromCol, 'LIMIT' => 2 * $queryLimit ),
+                               array( 'redirect' => array( 'LEFT JOIN', $on ) )
+                       );
+                       return $dbr->select(
+                               array( 'page', 'temp_backlink_range' => "($subQuery)" ),
+                               array( 'page_id', 'page_namespace', 'page_title', 'rd_from' ),
+                               array(),
+                               __CLASS__ . '::showIndirectLinks',
+                               array( 'ORDER BY' => 'page_id', 'LIMIT' => $queryLimit ),
+                               array( 'page' => array( 'INNER JOIN', "$fromCol = page_id" ) )
+                       );
+               };
 
                if ( $fetchlinks ) {
-                       $options['ORDER BY'] = 'pl_from';
-                       $plRes = $dbr->select( array( 'pagelinks', 'page', 'redirect' ), $fields,
-                               $plConds, __METHOD__, $options,
-                               $joinConds
-                       );
+                       $plRes = $queryFunc( $dbr, 'pagelinks', 'pl_from' );
                }
 
                if ( !$hidetrans ) {
-                       $options['ORDER BY'] = 'tl_from';
-                       $tlRes = $dbr->select( array( 'templatelinks', 'page', 'redirect' ), $fields,
-                               $tlConds, __METHOD__, $options,
-                               $joinConds
-                       );
+                       $tlRes = $queryFunc( $dbr, 'templatelinks', 'tl_from' );
                }
 
                if ( !$hideimages ) {
-                       $options['ORDER BY'] = 'il_from';
-                       $ilRes = $dbr->select( array( 'imagelinks', 'page', 'redirect' ), $fields,
-                               $ilConds, __METHOD__, $options,
-                               $joinConds
-                       );
+                       $ilRes = $queryFunc( $dbr, 'imagelinks', 'il_from' );
                }
 
                if ( ( !$fetchlinks || !$plRes->numRows() )
index 19ea20b..bab544b 100644 (file)
@@ -29,6 +29,7 @@ class UserloginTemplate extends BaseTemplate {
                $expirationDays = ceil( $wgCookieExpiration / ( 3600 * 24 ) );
 ?>
 <div class="mw-ui-container">
+       <div id="userloginprompt"><?php $this->msgWiki('loginprompt') ?></div>
        <?php if ( $this->haveData( 'languages' ) ) { ?>
                <div id="languagelinks">
                        <p><?php $this->html( 'languages' ); ?></p>
index d6c666a..8798de5 100644 (file)
@@ -277,8 +277,16 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
                                        foreach ( $this->localInterwikis as $localIW ) {
                                                if ( 0 == strcasecmp( $parts['interwiki'], $localIW ) ) {
                                                        if ( $dbkey == '' ) {
-                                                               # Can't have an empty self-link
-                                                               throw new MalformedTitleException( 'Local interwiki with empty title: ' . $text );
+                                                               # Empty self-links should point to the Main Page, to ensure
+                                                               # compatibility with cross-wiki transclusions and the like.
+                                                               $mainPage = Title::newMainPage();
+                                                               return array(
+                                                                       'interwiki' => $mainPage->getInterwiki(),
+                                                                       'fragment' => $mainPage->getFragment(),
+                                                                       'namespace' => $mainPage->getNamespace(),
+                                                                       'dbkey' => $mainPage->getDBkey(),
+                                                                       'user_case_dbkey' => $mainPage->getUserCaseDBKey()
+                                                               );
                                                        }
                                                        $parts['interwiki'] = '';
 
index d1de993..5defd45 100644 (file)
@@ -435,7 +435,7 @@ abstract class UploadBase {
                }
 
                $this->mFileProps = FSFile::getPropsFromPath( $this->mTempPath, $this->mFinalExtension );
-               $mime = $this->mFileProps['file-mime'];
+               $mime = $this->mFileProps['mime'];
 
                if ( $wgVerifyMimeType ) {
                        # XXX: Missing extension will be caught by validateName() via getTitle()
index b16d4a4..b97e2ad 100644 (file)
@@ -34,7 +34,7 @@ abstract class CdbReader {
        /**
         * Open a file and return a subclass instance
         *
-        * @param $fileName string
+        * @param string $fileName
         *
         * @return CdbReader
         */
@@ -64,7 +64,7 @@ abstract class CdbReader {
        /**
         * Create the object and open the file
         *
-        * @param $fileName string
+        * @param string $fileName
         */
        abstract public function __construct( $fileName );
 
@@ -76,7 +76,7 @@ abstract class CdbReader {
        /**
         * Get a value with a given key. Only string values are supported.
         *
-        * @param $key string
+        * @param string $key
         */
        abstract public function get( $key );
 }
@@ -107,7 +107,7 @@ abstract class CdbWriter {
         * Open a writer and return a subclass instance.
         * The user must have write access to the directory, for temporary file creation.
         *
-        * @param $fileName string
+        * @param string $fileName
         *
         * @return CdbWriterDBA|CdbWriterPHP
         */
@@ -120,14 +120,14 @@ abstract class CdbWriter {
        /**
         * Create the object and open the file
         *
-        * @param $fileName string
+        * @param string $fileName
         */
        abstract public function __construct( $fileName );
 
        /**
         * Set a key to a given value. The value will be converted to string.
-        * @param $key string
-        * @param $value string
+        * @param string $key
+        * @param string $value
         */
        abstract public function set( $key, $value );
 
index baba580..19d747a 100644 (file)
@@ -32,8 +32,8 @@ class CdbFunctions {
         * Take a modulo of a signed integer as if it were an unsigned integer.
         * $b must be less than 0x40000000 and greater than 0
         *
-        * @param $a
-        * @param $b
+        * @param int $a
+        * @param int $b
         *
         * @return int
         */
@@ -49,8 +49,8 @@ class CdbFunctions {
 
        /**
         * Shift a signed integer right as if it were unsigned
-        * @param $a
-        * @param $b
+        * @param int $a
+        * @param int $b
         * @return int
         */
        public static function unsignedShiftRight( $a, $b ) {
@@ -67,7 +67,7 @@ class CdbFunctions {
        /**
         * The CDB hash function.
         *
-        * @param $s string
+        * @param string $s
         *
         * @return int
         */
@@ -125,7 +125,7 @@ class CdbReaderPHP extends CdbReader {
        protected $dlen;
 
        /**
-        * @param $fileName string
+        * @param string $fileName
         * @throws CdbException
         */
        public function __construct( $fileName ) {
@@ -145,7 +145,7 @@ class CdbReaderPHP extends CdbReader {
        }
 
        /**
-        * @param $key
+        * @param mixed $key
         * @return bool|string
         */
        public function get( $key ) {
@@ -158,8 +158,8 @@ class CdbReaderPHP extends CdbReader {
        }
 
        /**
-        * @param $key
-        * @param $pos
+        * @param string $key
+        * @param int $pos
         * @return bool
         */
        protected function match( $key, $pos ) {
@@ -174,8 +174,8 @@ class CdbReaderPHP extends CdbReader {
 
        /**
         * @throws CdbException
-        * @param $length
-        * @param $pos
+        * @param int $length
+        * @param int $pos
         * @return string
         */
        protected function read( $length, $pos ) {
@@ -200,7 +200,7 @@ class CdbReaderPHP extends CdbReader {
 
        /**
         * Unpack an unsigned integer and throw an exception if it needs more than 31 bits
-        * @param $s
+        * @param string $s
         * @throws CdbException
         * @return mixed
         */
@@ -216,7 +216,7 @@ class CdbReaderPHP extends CdbReader {
 
        /**
         * Unpack a 32-bit signed integer
-        * @param $s
+        * @param string $s
         * @return int
         */
        protected function unpackSigned( $s ) {
@@ -226,7 +226,7 @@ class CdbReaderPHP extends CdbReader {
        }
 
        /**
-        * @param $key
+        * @param string $key
         * @return bool
         */
        protected function findNext( $key ) {
@@ -274,7 +274,7 @@ class CdbReaderPHP extends CdbReader {
        }
 
        /**
-        * @param $key
+        * @param mixed $key
         * @return bool
         */
        protected function find( $key ) {
@@ -295,7 +295,7 @@ class CdbWriterPHP extends CdbWriter {
        protected $pos;
 
        /**
-        * @param $fileName string
+        * @param string $fileName
         */
        public function __construct( $fileName ) {
                $this->realFileName = $fileName;
@@ -347,7 +347,7 @@ class CdbWriterPHP extends CdbWriter {
 
        /**
         * @throws CdbException
-        * @param $buf
+        * @param string $buf
         */
        protected function write( $buf ) {
                $len = fwrite( $this->handle, $buf );
@@ -358,7 +358,7 @@ class CdbWriterPHP extends CdbWriter {
 
        /**
         * @throws CdbException
-        * @param $len
+        * @param int $len
         */
        protected function posplus( $len ) {
                $newpos = $this->pos + $len;
@@ -370,9 +370,9 @@ class CdbWriterPHP extends CdbWriter {
        }
 
        /**
-        * @param $keylen
-        * @param $datalen
-        * @param $h
+        * @param int $keylen
+        * @param int $datalen
+        * @param int $h
         */
        protected function addend( $keylen, $datalen, $h ) {
                $this->hplist[] = array(
@@ -388,8 +388,8 @@ class CdbWriterPHP extends CdbWriter {
 
        /**
         * @throws CdbException
-        * @param $keylen
-        * @param $datalen
+        * @param int $keylen
+        * @param int $datalen
         */
        protected function addbegin( $keylen, $datalen ) {
                if ( $keylen > 0x7fffffff ) {
@@ -481,7 +481,7 @@ class CdbWriterPHP extends CdbWriter {
        /**
         * Clean up the temp file and throw an exception
         *
-        * @param $msg string
+        * @param string $msg
         * @throws CdbException
         */
        protected function throwException( $msg ) {
index e4e1cfd..0e2db8c 100644 (file)
@@ -73,8 +73,8 @@ class IP {
         * SIIT IPv4-translated addresses are rejected.
         * Note: canonicalize() tries to convert translated addresses to IPv4.
         *
-        * @param string $ip possible IP address
-        * @return Boolean
+        * @param string $ip Possible IP address
+        * @return bool
         */
        public static function isIPAddress( $ip ) {
                return (bool)preg_match( '/^' . IP_ADDRESS_STRING . '$/', $ip );
@@ -84,8 +84,8 @@ class IP {
         * Given a string, determine if it as valid IP in IPv6 only.
         * Note: Unlike isValid(), this looks for networks too.
         *
-        * @param string $ip possible IP address
-        * @return Boolean
+        * @param string $ip Possible IP address
+        * @return bool
         */
        public static function isIPv6( $ip ) {
                return (bool)preg_match( '/^' . RE_IPV6_ADD . '(?:\/' . RE_IPV6_PREFIX . ')?$/', $ip );
@@ -95,8 +95,8 @@ class IP {
         * Given a string, determine if it as valid IP in IPv4 only.
         * Note: Unlike isValid(), this looks for networks too.
         *
-        * @param string $ip possible IP address
-        * @return Boolean
+        * @param string $ip Possible IP address
+        * @return bool
         */
        public static function isIPv4( $ip ) {
                return (bool)preg_match( '/^' . RE_IP_ADD . '(?:\/' . RE_IP_PREFIX . ')?$/', $ip );
@@ -107,8 +107,8 @@ class IP {
         * SIIT IPv4-translated addresses are rejected.
         * Note: canonicalize() tries to convert translated addresses to IPv4.
         *
-        * @param $ip String
-        * @return Boolean: True if it is valid.
+        * @param string $ip
+        * @return bool True if it is valid
         */
        public static function isValid( $ip ) {
                return ( preg_match( '/^' . RE_IP_ADD . '$/', $ip )
@@ -120,8 +120,8 @@ class IP {
         * SIIT IPv4-translated addresses are rejected.
         * Note: canonicalize() tries to convert translated addresses to IPv4.
         *
-        * @param $ipblock String
-        * @return Boolean: True if it is valid.
+        * @param string $ipblock
+        * @return bool True if it is valid
         */
        public static function isValidBlock( $ipblock ) {
                return ( preg_match( '/^' . RE_IPV6_BLOCK . '$/', $ipblock )
@@ -134,7 +134,7 @@ class IP {
         * IPv4 addresses are just trimmed.
         *
         * @param string $ip IP address in quad or octet form (CIDR or not).
-        * @return String
+        * @return string
         */
        public static function sanitizeIP( $ip ) {
                $ip = trim( $ip );
@@ -186,7 +186,7 @@ class IP {
         * Prettify an IP for display to end users.
         * This will make it more compact and lower-case.
         *
-        * @param $ip string
+        * @param string $ip
         * @return string
         */
        public static function prettifyIP( $ip ) {
@@ -286,9 +286,9 @@ class IP {
         * brackets like in RFC 2732. If the port matches the default port, omit
         * the port specification
         *
-        * @param $host string
-        * @param $port int
-        * @param $defaultPort bool|int
+        * @param string $host
+        * @param int $port
+        * @param bool|int $defaultPort
         * @return string
         */
        public static function combineHostAndPort( $host, $port, $defaultPort = false ) {
@@ -305,8 +305,8 @@ class IP {
        /**
         * Convert an IPv4 or IPv6 hexadecimal representation back to readable format
         *
-        * @param string $hex number, with "v6-" prefix if it is IPv6
-        * @return String: quad-dotted (IPv4) or octet notation (IPv6)
+        * @param string $hex Number, with "v6-" prefix if it is IPv6
+        * @return string Quad-dotted (IPv4) or octet notation (IPv6)
         */
        public static function formatHex( $hex ) {
                if ( substr( $hex, 0, 3 ) == 'v6-' ) { // IPv6
@@ -319,8 +319,8 @@ class IP {
        /**
         * Converts a hexadecimal number to an IPv6 address in octet notation
         *
-        * @param $ip_hex String: pure hex (no v6- prefix)
-        * @return String (of format a:b:c:d:e:f:g:h)
+        * @param string $ip_hex Pure hex (no v6- prefix)
+        * @return string (of format a:b:c:d:e:f:g:h)
         */
        public static function hexToOctet( $ip_hex ) {
                // Pad hex to 32 chars (128 bits)
@@ -339,8 +339,8 @@ class IP {
        /**
         * Converts a hexadecimal number to an IPv4 address in quad-dotted notation
         *
-        * @param $ip_hex String: pure hex
-        * @return String (of format a.b.c.d)
+        * @param string $ip_hex Pure hex
+        * @return string (of format a.b.c.d)
         */
        public static function hexToQuad( $ip_hex ) {
                // Pad hex to 8 chars (32 bits)
@@ -361,8 +361,8 @@ class IP {
         * Determine if an IP address really is an IP address, and if it is public,
         * i.e. not RFC 1918 or similar
         *
-        * @param $ip String
-        * @return Boolean
+        * @param string $ip
+        * @return bool
         */
        public static function isPublic( $ip ) {
                static $privateSet = null;
@@ -388,8 +388,8 @@ class IP {
         * function for an IPv6 address will be prefixed with "v6-", a non-
         * hexadecimal string which sorts after the IPv4 addresses.
         *
-        * @param string $ip quad dotted/octet IP address.
-        * @return String|bool false on failure
+        * @param string $ip Quad dotted/octet IP address.
+        * @return string|bool False on failure
         */
        public static function toHex( $ip ) {
                if ( self::isIPv6( $ip ) ) {
@@ -420,8 +420,8 @@ class IP {
        /**
         * Given an IPv6 address in octet notation, returns a pure hex string.
         *
-        * @param string $ip octet ipv6 IP address.
-        * @return String|bool pure hex (uppercase); false on failure
+        * @param string $ip Octet ipv6 IP address.
+        * @return string|bool Pure hex (uppercase); false on failure
         */
        private static function IPv6ToRawHex( $ip ) {
                $ip = self::sanitizeIP( $ip );
@@ -529,7 +529,7 @@ class IP {
         * Convert a network specification in IPv6 CIDR notation to an
         * integer network and a number of bits
         *
-        * @param $range
+        * @param string $range
         *
         * @return array(string, int)
         */
@@ -570,7 +570,7 @@ class IP {
         *     2001:0db8:85a3::7344 - 2001:0db8:85a3::7344   Explicit range
         *     2001:0db8:85a3::7344/96                       Single IP
         *
-        * @param $range
+        * @param string $range
         *
         * @return array(string, string)
         */
@@ -616,9 +616,9 @@ class IP {
        /**
         * Determine if a given IPv4/IPv6 address is in a given CIDR network
         *
-        * @param string $addr the address to check against the given range.
-        * @param string $range the range to check the given address against.
-        * @return Boolean: whether or not the given address is in the given range.
+        * @param string $addr The address to check against the given range.
+        * @param string $range The range to check the given address against.
+        * @return bool Whether or not the given address is in the given range.
         */
        public static function isInRange( $addr, $range ) {
                $hexIP = self::toHex( $addr );
@@ -635,8 +635,8 @@ class IP {
         * This currently only checks a few IPV4-to-IPv6 related cases.  More
         * unusual representations may be added later.
         *
-        * @param string $addr something that might be an IP address
-        * @return String: valid dotted quad IPv4 address or null
+        * @param string $addr Something that might be an IP address
+        * @return string Valid dotted quad IPv4 address or null
         */
        public static function canonicalize( $addr ) {
                // remove zone info (bug 35738)
index 6b6655e..8610386 100644 (file)
@@ -101,7 +101,7 @@ class MWCryptHKDF {
        /**
         * @param string $hash Name of hashing algorithm
         * @param BagOStuff $cache
-        * @param string|array $context to mix into HKDF context
+        * @param string|array $context Context to mix into HKDF context
         */
        public function __construct( $secretKeyMaterial, $algorithm, $cache, $context ) {
                if ( strlen( $secretKeyMaterial ) < 16 ) {
@@ -133,7 +133,7 @@ class MWCryptHKDF {
 
        /**
         * MW specific salt, cached from last run
-        * @return string binary string
+        * @return string Binary string
         */
        protected function getSaltUsingCache() {
                if ( $this->salt == '' ) {
@@ -189,9 +189,9 @@ class MWCryptHKDF {
        /**
         * Produce $bytes of secure random data. As a side-effect,
         * $this->lastK is set to the last hashLen block of key material.
-        * @param int $bytes number of bytes of data
-        * @param string $context to mix into CTXinfo
-        * @return string binary string of length $bytes
+        * @param int $bytes Number of bytes of data
+        * @param string $context Context to mix into CTXinfo
+        * @return string Binary string of length $bytes
         */
        protected function realGenerate( $bytes, $context = '' ) {
 
@@ -237,13 +237,13 @@ class MWCryptHKDF {
         * N.B. http://eprint.iacr.org/2010/264.pdf seems to differ from RFC 5869 in that the test
         * vectors from RFC 5869 only work if K(0) = '' and K(1) = HMAC(PRK, K(0) || CTXinfo || 1)
         *
-        * @param string $hash the hashing function to use (e.g., sha256)
-        * @param string $ikm the input keying material
-        * @param string $salt the salt to add to the ikm, to get the prk
-        * @param string $info optional context (change the output without affecting
+        * @param string $hash The hashing function to use (e.g., sha256)
+        * @param string $ikm The input keying material
+        * @param string $salt The salt to add to the ikm, to get the prk
+        * @param string $info Optional context (change the output without affecting
         *      the randomness properties of the output)
-        * @param integer $L number of bytes to return
-        * @return string cryptographically secure pseudorandom binary string
+        * @param int $L Number of bytes to return
+        * @return string Cryptographically secure pseudorandom binary string
         */
        public static function HKDF( $hash, $ikm, $salt, $info, $L ) {
                $prk = self::HKDFExtract( $hash, $salt, $ikm );
@@ -256,10 +256,10 @@ class MWCryptHKDF {
         * Note that the hmac is keyed with XTS (the salt),
         * and the SKM (source key material) is the "data".
         *
-        * @param string $hash the hashing function to use (e.g., sha256)
-        * @param string $ikm the input keying material
-        * @param string $salt the salt to add to the ikm, to get the prk
-        * @return string binary string (pseudorandm key) used as input to HKDFExpand
+        * @param string $hash The hashing function to use (e.g., sha256)
+        * @param string $ikm The input keying material
+        * @param string $salt The salt to add to the ikm, to get the prk
+        * @return string Binary string (pseudorandm key) used as input to HKDFExpand
         */
        private static function HKDFExtract( $hash, $salt, $ikm ) {
                return hash_hmac( $hash, $ikm, $salt, true );
@@ -268,16 +268,16 @@ class MWCryptHKDF {
        /**
         * Expand the key with the given context
         *
-        * @param $hash Hashing Algorithm
-        * @param $prk a pseudorandom key of at least HashLen octets
-         *     (usually, the output from the extract step)
-        * @param $info optional context and application specific information
-         *     (can be a zero-length string)
-        * @param $bytes length of output keying material in bytes
-         *     (<= 255*HashLen)
-        * @param &$lastK set by this function to the last block of the expansion.
+        * @param string $hash Hashing Algorithm
+        * @param string $prk A pseudorandom key of at least HashLen octets
+             (usually, the output from the extract step)
+        * @param string $info Optional context and application specific information
+             (can be a zero-length string)
+        * @param int $bytes Length of output keying material in bytes
+             (<= 255*HashLen)
+        * @param string &$lastK Set by this function to the last block of the expansion.
         *      In MediaWiki, this is used to seed future Extractions.
-        * @return string cryptographically secure random string $bytes long
+        * @return string Cryptographically secure random string $bytes long
         */
        private static function HKDFExpand( $hash, $prk, $info, $bytes, &$lastK = '' ) {
                $hashLen = MWCryptHKDF::$hashLength[$hash];
@@ -293,7 +293,7 @@ class MWCryptHKDF {
                for ( $counter = 1; $counter <= $rounds; ++$counter ) {
                        $lastK = hash_hmac(
                                $hash,
-                               $lastK . $info . chr($counter),
+                               $lastK . $info . chr( $counter ),
                                $prk,
                                true
                        );
@@ -306,9 +306,9 @@ class MWCryptHKDF {
        /**
         * Generate cryptographically random data and return it in raw binary form.
         *
-        * @param int $bytes the number of bytes of random data to generate
-        * @param string $context string to mix into HMAC context
-        * @return string binary string of length $bytes
+        * @param int $bytes The number of bytes of random data to generate
+        * @param string $context String to mix into HMAC context
+        * @return string Binary string of length $bytes
         */
        public static function generate( $bytes, $context ) {
                return self::singleton()->realGenerate( $bytes, $context );
@@ -318,9 +318,9 @@ class MWCryptHKDF {
         * Generate cryptographically random data and return it in hexadecimal string format.
         * See MWCryptRand::realGenerateHex for details of the char-to-byte conversion logic.
         *
-        * @param int $chars the number of hex chars of random data to generate
-        * @param string $context string to mix into HMAC context
-        * @return string random hex characters, $chars long
+        * @param int $chars The number of hex chars of random data to generate
+        * @param string $context String to mix into HMAC context
+        * @return string Random hex characters, $chars long
         */
        public static function generateHex( $chars, $context = '' ) {
                $bytes = ceil( $chars / 2 );
index eb74d12..31a71c4 100644 (file)
@@ -147,7 +147,7 @@ class MWCryptRand {
         * Randomly hash data while mixing in clock drift data for randomness
         *
         * @param string $data The data to randomly hash.
-        * @return String The hashed bytes
+        * @return string The hashed bytes
         * @author Tim Starling
         */
        protected function driftHash( $data ) {
@@ -214,7 +214,7 @@ class MWCryptRand {
        /**
         * Decide on the best acceptable hash algorithm we have available for hash()
         * @throws MWException
-        * @return String A hash algorithm
+        * @return string A hash algorithm
         */
        protected function hashAlgo() {
                if ( !is_null( $this->algo ) ) {
@@ -259,8 +259,8 @@ class MWCryptRand {
         * Generate an acceptably unstable one-way-hash of some text
         * making use of the best hash algorithm that we have available.
         *
-        * @param $data string
-        * @return String A raw hash of the data
+        * @param string $data
+        * @return string A raw hash of the data
         */
        protected function hash( $data ) {
                return hash( $this->hashAlgo(), $data, true );
@@ -270,9 +270,9 @@ class MWCryptRand {
         * Generate an acceptably unstable one-way-hmac of some text
         * making use of the best hash algorithm that we have available.
         *
-        * @param $data string
-        * @param $key string
-        * @return String A raw hash of the data
+        * @param string $data
+        * @param string $key
+        * @return string A raw hash of the data
         */
        protected function hmac( $data, $key ) {
                return hash_hmac( $this->hashAlgo(), $data, $key, true );
@@ -487,11 +487,11 @@ class MWCryptRand {
         * You can use MWCryptRand::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
+        * @param int $bytes The number of bytes of random data to generate
         * @param bool $forceStrong Pass true if you want generate to prefer cryptographically
         *                          strong sources of entropy even if reading from them may steal
         *                          more entropy from the system than optimal.
-        * @return String Raw binary random data
+        * @return string Raw binary random data
         */
        public static function generate( $bytes, $forceStrong = false ) {
                return self::singleton()->realGenerate( $bytes, $forceStrong );
@@ -503,11 +503,11 @@ class MWCryptRand {
         * You can use MWCryptRand::wasStrong() if you wish to know if the source used
         * was cryptographically strong.
         *
-        * @param int $chars the number of hex chars of random data to generate
+        * @param int $chars The number of hex chars of random data to generate
         * @param bool $forceStrong Pass true if you want generate to prefer cryptographically
         *                          strong sources of entropy even if reading from them may steal
         *                          more entropy from the system than optimal.
-        * @return String Hexadecimal random data
+        * @return string Hexadecimal random data
         */
        public static function generateHex( $chars, $forceStrong = false ) {
                return self::singleton()->realGenerateHex( $chars, $forceStrong );
index 7105f6c..3a0492d 100644 (file)
@@ -24,7 +24,7 @@ class MWFunction {
 
        /**
         * @deprecated since 1.22; use call_user_func()
-        * @param $callback
+        * @param callable $callback
         * @return mixed
         */
        public static function call( $callback ) {
@@ -36,8 +36,8 @@ class MWFunction {
 
        /**
         * @deprecated since 1.22; use call_user_func_array()
-        * @param $callback
-        * @param $argsarams
+        * @param callable $callback
+        * @param array $argsarams
         * @return mixed
         */
        public static function callArray( $callback, $argsarams ) {
@@ -47,8 +47,8 @@ class MWFunction {
        }
 
        /**
-        * @param $class
-        * @param $args array
+        * @param string $class
+        * @param array $args
         * @return object
         */
        public static function newObj( $class, $args = array() ) {
index 9cd3d3f..86f4512 100644 (file)
@@ -42,11 +42,11 @@ class StringUtils {
         * Beware of this when backporting code to that version of MediaWiki.
         *
         * @param string $value String to check
-        * @param boolean $disableMbstring Whether to use the pure PHP
+        * @param bool $disableMbstring Whether to use the pure PHP
         * implementation instead of trying mb_check_encoding. Intended for unit
         * testing. Default: false
         *
-        * @return boolean Whether the given $value is a valid UTF-8 encoded string
+        * @return bool Whether the given $value is a valid UTF-8 encoded string
         */
        static function isUtf8( $value, $disableMbstring = false ) {
                $value = (string)$value;
@@ -121,10 +121,10 @@ class StringUtils {
         * hungry and inflexible. The memory requirements are such that I don't
         * recommend using it on anything but guaranteed small chunks of text.
         *
-        * @param $startDelim
-        * @param $endDelim
-        * @param $replace
-        * @param $subject
+        * @param string $startDelim
+        * @param string $endDelim
+        * @param string $replace
+        * @param string $subject
         *
         * @return string
         */
@@ -157,11 +157,11 @@ class StringUtils {
         * start, so e.g. /*\/ is not considered to be both the start and end of a
         * comment. /*\/xy/*\/ is considered to be a single comment with contents /xy/.
         *
-        * @param string $startDelim start delimiter
-        * @param string $endDelim end delimiter
-        * @param $callback Callback: function to call on each match
-        * @param $subject String
-        * @param string $flags regular expression flags
+        * @param string $startDelim Start delimiter
+        * @param string $endDelim End delimiter
+        * @param callable $callback Function to call on each match
+        * @param string $subject
+        * @param string $flags Regular expression flags
         * @throws MWException
         * @return string
         */
@@ -245,13 +245,13 @@ class StringUtils {
         *
         *   preg_replace( "!$startDelim(.*)$endDelim!$flags", $replace, $subject )
         *
-        * @param string $startDelim start delimiter regular expression
-        * @param string $endDelim end delimiter regular expression
-        * @param string $replace replacement string. May contain $1, which will be
+        * @param string $startDelim Start delimiter regular expression
+        * @param string $endDelim End delimiter regular expression
+        * @param string $replace Replacement string. May contain $1, which will be
         *                 replaced by the text between the delimiters
-        * @param string $subject to search
-        * @param string $flags regular expression flags
-        * @return String: The string with the matches replaced
+        * @param string $subject String to search
+        * @param string $flags Regular expression flags
+        * @return string The string with the matches replaced
         */
        static function delimiterReplace( $startDelim, $endDelim, $replace, $subject, $flags = '' ) {
                $replacer = new RegexlikeReplacer( $replace );
@@ -361,8 +361,8 @@ class RegexlikeReplacer extends Replacer {
  */
 class DoubleReplacer extends Replacer {
        /**
-        * @param $from
-        * @param $to
+        * @param mixed $from
+        * @param mixed $to
         * @param int $index
         */
        function __construct( $from, $to, $index = 0 ) {
@@ -387,7 +387,7 @@ class HashtableReplacer extends Replacer {
        private $table, $index;
 
        /**
-        * @param $table
+        * @param array $table
         * @param int $index
         */
        function __construct( $table, $index = 0 ) {
index 0ce90c1..604d381 100644 (file)
@@ -37,7 +37,7 @@ class UIDGenerator {
        protected $lockFile88; // string; local file path
        protected $lockFile128; // string; local file path
 
-       /** @var Array */
+       /** @var array */
        protected $fileHandles = array(); // cache file handles
 
        const QUICK_RAND = 1; // get randomness from fast and insecure sources
@@ -102,7 +102,7 @@ class UIDGenerator {
         *
         * UID generation is serialized on each server (as the node ID is for the whole machine).
         *
-        * @param $base integer Specifies a base other than 10
+        * @param int $base Specifies a base other than 10
         * @return string Number
         * @throws MWException
         */
@@ -146,7 +146,7 @@ class UIDGenerator {
         *
         * UID generation is serialized on each server (as the node ID is for the whole machine).
         *
-        * @param $base integer Specifies a base other than 10
+        * @param int $base Specifies a base other than 10
         * @return string Number
         * @throws MWException
         */
@@ -185,7 +185,7 @@ class UIDGenerator {
        /**
         * Return an RFC4122 compliant v4 UUID
         *
-        * @param $flags integer Bitfield (supports UIDGenerator::QUICK_RAND)
+        * @param int $flags Bitfield (supports UIDGenerator::QUICK_RAND)
         * @return string
         * @throws MWException
         */
@@ -211,7 +211,7 @@ class UIDGenerator {
        /**
         * Return an RFC4122 compliant v4 UUID
         *
-        * @param $flags integer Bitfield (supports UIDGenerator::QUICK_RAND)
+        * @param int $flags Bitfield (supports UIDGenerator::QUICK_RAND)
         * @return string 32 hex characters with no hyphens
         * @throws MWException
         */
@@ -226,8 +226,8 @@ class UIDGenerator {
         * If UIDGenerator::QUICK_VOLATILE is used the counter might reset on server restart.
         *
         * @param string $bucket Arbitrary bucket name (should be ASCII)
-        * @param integer $bits Bit size (<=48) of resulting numbers before wrap-around
-        * @param integer $flags (supports UIDGenerator::QUICK_VOLATILE)
+        * @param int $bits Bit size (<=48) of resulting numbers before wrap-around
+        * @param int $flags (supports UIDGenerator::QUICK_VOLATILE)
         * @return float Integer value as float
         * @since 1.23
         */
@@ -240,9 +240,9 @@ class UIDGenerator {
         *
         * @see UIDGenerator::newSequentialPerNodeID()
         * @param string $bucket Arbitrary bucket name (should be ASCII)
-        * @param integer $bits Bit size (16 to 48) of resulting numbers before wrap-around
-        * @param integer $count Number of IDs to return (1 to 10000)
-        * @param integer $flags (supports UIDGenerator::QUICK_VOLATILE)
+        * @param int $bits Bit size (16 to 48) of resulting numbers before wrap-around
+        * @param int $count Number of IDs to return (1 to 10000)
+        * @param int $flags (supports UIDGenerator::QUICK_VOLATILE)
         * @return array Ordered list of float integer values
         * @since 1.23
         */
@@ -256,9 +256,9 @@ class UIDGenerator {
         *
         * @see UIDGenerator::newSequentialPerNodeID()
         * @param string $bucket Arbitrary bucket name (should be ASCII)
-        * @param integer $bits Bit size (16 to 48) of resulting numbers before wrap-around
-        * @param integer $count Number of IDs to return (1 to 10000)
-        * @param integer $flags (supports UIDGenerator::QUICK_VOLATILE)
+        * @param int $bits Bit size (16 to 48) of resulting numbers before wrap-around
+        * @param int $count Number of IDs to return (1 to 10000)
+        * @param int $flags (supports UIDGenerator::QUICK_VOLATILE)
         * @return array Ordered list of float integer values
         */
        protected function getSequentialPerNodeIDs( $bucket, $bits, $count, $flags ) {
@@ -337,9 +337,9 @@ class UIDGenerator {
         * This is useful for making UIDs sequential on a per-node bases.
         *
         * @param string $lockFile Name of a local lock file
-        * @param $clockSeqSize integer The number of possible clock sequence values
-        * @param $counterSize integer The number of possible counter values
-        * @return Array (result of UIDGenerator::millitime(), counter, clock sequence)
+        * @param int $clockSeqSize The number of possible clock sequence values
+        * @param int $counterSize The number of possible counter values
+        * @return array (result of UIDGenerator::millitime(), counter, clock sequence)
         * @throws MWException
         */
        protected function getTimestampAndDelay( $lockFile, $clockSeqSize, $counterSize ) {
@@ -420,7 +420,7 @@ class UIDGenerator {
         * timestamp. This returns false if it would have to wait more than 10ms.
         *
         * @param array $time Result of UIDGenerator::millitime()
-        * @return Array|bool UIDGenerator::millitime() result or false
+        * @return array|bool UIDGenerator::millitime() result or false
         */
        protected function timeWaitUntil( array $time ) {
                do {
@@ -449,7 +449,7 @@ class UIDGenerator {
        }
 
        /**
-        * @return Array (current time in seconds, milliseconds since then)
+        * @return array (current time in seconds, milliseconds since then)
         */
        protected static function millitime() {
                list( $msec, $sec ) = explode( ' ', microtime() );
index 6be186f..0f56e33 100644 (file)
@@ -64,7 +64,7 @@ class ZipDirectoryReader {
         *        valid ZIP64 file, and working out what non-ZIP64 readers will make
         *        of such a file is not trivial.
         *
-        * @return Status object. The following fatal errors are defined:
+        * @return Status A Status object. The following fatal errors are defined:
         *
         *      - zip-file-open-error: The file could not be opened.
         *
@@ -181,6 +181,8 @@ class ZipDirectoryReader {
 
        /**
         * Throw an error, and log a debug message
+        * @param mixed $code
+        * @param string $debugMessage
         */
        function error( $code, $debugMessage ) {
                wfDebug( __CLASS__ . ": Fatal error: $debugMessage\n" );
@@ -299,7 +301,7 @@ class ZipDirectoryReader {
         * Find the location of the central directory, as would be seen by a
         * non-ZIP64 reader.
         *
-        * @return List containing offset, size and end position.
+        * @return array List containing offset, size and end position.
         */
        function findOldCentralDirectory() {
                $size = $this->eocdr['CD size'];
@@ -430,9 +432,7 @@ class ZipDirectoryReader {
                                $year, $month, $day, $hour, $minute, $second );
 
                        // Convert the character set in the file name
-                       if ( !function_exists( 'iconv' )
-                               || $this->testBit( $data['general bits'], self::GENERAL_UTF8 )
-                       ) {
+                       if ( $this->testBit( $data['general bits'], self::GENERAL_UTF8 ) ) {
                                $name = $data['name'];
                        } else {
                                $name = iconv( 'CP437', 'UTF-8', $data['name'] );
@@ -485,6 +485,7 @@ class ZipDirectoryReader {
 
        /**
         * Get the length of the file.
+        * @return int
         */
        function getFileLength() {
                if ( $this->fileLength === null ) {
@@ -661,7 +662,7 @@ class ZipDirectoryReader {
         * Returns a bit from a given position in an integer value, converted to
         * boolean.
         *
-        * @param $value integer
+        * @param int $value
         * @param int $bitIndex The index of the bit, where 0 is the LSB.
         * @return bool
         */
@@ -671,6 +672,7 @@ class ZipDirectoryReader {
 
        /**
         * Debugging helper function which dumps a string in hexdump -C format.
+        * @param string $s
         */
        function hexDump( $s ) {
                $n = strlen( $s );
index bc46111..b35967b 100644 (file)
--- a/index.php
+++ b/index.php
@@ -34,7 +34,7 @@
 # has structures (try/catch, foo()->bar(), etc etc) which throw parse errors in
 # PHP 4. Setup.php and ObjectCache.php have structures invalid in PHP 5.0 and
 # 5.1, respectively.
-if ( !function_exists( 'version_compare' ) || version_compare( phpversion(), '5.3.2' ) < 0 ) {
+if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.3.2' ) < 0 ) {
        // We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+
        require dirname( __FILE__ ) . '/includes/PHPVersionError.php';
        wfPHPVersionError( 'index.php' );
index bf30455..88d0f23 100644 (file)
@@ -339,7 +339,7 @@ class Language {
                        throw new MWException( __METHOD__ . " must be passed a string, $type given$addmsg" );
                }
 
-               return (bool)preg_match( '/^[a-z0-9-]{2,}$/i', $code );
+               return (bool)preg_match( '/^[a-z0-9-]{2,}$/', $code );
        }
 
        /**
@@ -443,17 +443,6 @@ class Language {
        function initContLang() {
        }
 
-       /**
-        * Same as getFallbacksFor for current language.
-        * @return array|bool
-        * @deprecated since 1.19
-        */
-       function getFallbackLanguageCode() {
-               wfDeprecated( __METHOD__, '1.19' );
-
-               return self::getFallbackFor( $this->mCode );
-       }
-
        /**
         * @return array
         * @since 1.19
@@ -857,6 +846,11 @@ class Language {
                        include "$IP/languages/Names.php";
                }
 
+               // If passed an invalid language code to use, fallback to en
+               if ( $inLanguage !== null && !Language::isValidCode( $inLanguage ) ) {
+                       $inLanguage = 'en';
+               }
+
                $names = array();
 
                if ( $inLanguage ) {
@@ -2402,7 +2396,7 @@ class Language {
                        // Timestamps are in different years: use full timestamp
                        // Also do full timestamp for future dates
                        /**
-                        * @FIXME Add better handling of future timestamps.
+                        * @todo FIXME: Add better handling of future timestamps.
                         */
                        $format = $this->getDateFormatString( 'both', $user->getDatePreference() ?: 'default' );
                        $ts = $this->sprintfDate( $format, $ts->getTimestamp( TS_MW ) );
index 9c46ab1..e1b03b5 100644 (file)
        'tt-latn' => 'tatarça',        # Tatar (Latin script)
        'tum' => 'chiTumbuka',  # Tumbuka
        'tw' => 'Twi',                  # Twi, (FIXME!)
-       'ty' => 'Reo Mā`ohi',  # Tahitian
+       'ty' => 'reo tahiti',   # Tahitian
        'tyv' => 'тыва дыл',     # Tyvan
+       'tzm' => 'ⵜⴰⵎⴰⵣⵉⵖⵜ',    # Tamazight
        'udm' => 'удмурт',        # Udmurt
        'ug' => 'ئۇيغۇرچە / Uyghurche', # Uyghur (multiple scripts - defaults to Arabic)
        'ug-arab' => 'ئۇيغۇرچە', # Uyghur (Arabic script) (default)
index 740663f..226e313 100644 (file)
@@ -65,6 +65,8 @@ class LanguageRu extends Language {
                                                $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'тей';
                                        } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ды' ) {
                                                $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'дов';
+                                       } elseif ( join( '', array_slice( $chars[0], -1 ) ) === 'д' ) {
+                                               $word = join( '', array_slice( $chars[0], 0, -1 ) ) . 'да';
                                        } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ник' ) {
                                                $word = join( '', array_slice( $chars[0], 0, -3 ) ) . 'ника';
                                        } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ные' ) {
@@ -91,6 +93,8 @@ class LanguageRu extends Language {
                                                $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'тях';
                                        } elseif ( join( '', array_slice( $chars[0], -2 ) ) === 'ды' ) {
                                                $word = join( '', array_slice( $chars[0], 0, -2 ) ) . 'дах';
+                                       } elseif ( join( '', array_slice( $chars[0], -1 ) ) === 'д' ) {
+                                               $word = join( '', array_slice( $chars[0], 0, -1 ) ) . 'де';
                                        } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ник' ) {
                                                $word = join( '', array_slice( $chars[0], 0, -3 ) ) . 'нике';
                                        } elseif ( join( '', array_slice( $chars[0], -3 ) ) === 'ные' ) {
index 4a8a589..8070e2d 100644 (file)
        "talkpagelinktext": "نقاش",
        "specialpage": "صفحة خاصة",
        "personaltools": "أدوات شخصية",
-       "postcomment": "قسم جديد",
        "articlepage": "اعرض صفحة المحتوى",
        "talk": "نقاش",
        "views": "معاينة",
        "viewsourcetext": "تمكنك مطالعة و نسخ مصدر هذه الصفحة:",
        "viewyourtext": "يمكنك استعراض و نسخ مصدر ''' تعديلاتك ''' في هذه الصفحة:",
        "protectedinterface": "توفر هذه الصفحة نص الواجهة للبرنامج على هذا الويكي، وهي محمية لمنع سوء أستخدامها.\nلإضافة أو تغيير الترجمات لجميع مشاريع الويكي، رجاءً أستخدم [//translatewiki.net/ translatewiki.net]، مشروع الترجمة الخاص بميدياويكي.",
-       "editinginterface": "'''تحذير:''' أنت تقوم بتحرير صفحة تستخدم في الواجهة النصية للبرنامج.\nسوف تؤثر التغييرات في هذه الصفحة على مظهر واجهة المستخدم للمستخدمين الآخرين على هذا الويكي.\nلإضافة أو تغيير الترجمات في جميع مشاريع الويكي، رجاءً استخدم [//translatewiki.net/ translatewiki.net]، مشروع الترجمة الخاص بميدياويكي.",
+       "editinginterface": "<strong>تنبيه:</strong> تعديل هذه الصفحة سيحفظ في هذا الويكي فقط. لتعميم التعديل على جميع مشاريع ميدياويكي، عدلها في [//translatewiki.net/ مشروع ترجمة الويكي].",
        "cascadeprotected": "تمت حماية هذه الصفحة من التعديل لأنها مدمجة في {{PLURAL:$1||الصفحة التالية، والتي|الصفحتين التاليتين، واللتين|الصفحات التالية، والتي}} تم استعمال خاصية \"حماية الصفحات المدمجة\" {{PLURAL:$1||بها|بهما|بها}}:\n$2",
        "namespaceprotected": "لا تمتلك الصلاحية لتعديل الصفحات في نطاق '''$1'''.",
        "customcssprotected": "أنت لا تمتلك السماح لتعديل صفحة الCSS هذه، لأنها تحتوي على الإعدادات الشخصية لمستخدم آخر.",
        "virus-badscanner": "ضبط سيء: ماسح فيروسات غير معروف: ''$1''",
        "virus-scanfailed": "فشل المسح (كود $1)",
        "virus-unknownscanner": "مضاد فيروسات غير معروف:",
-       "logouttext": "'''أنت الآن غير مسجل الدخول.'''\n\nقد ترى بعض الصفحات كما لو أنك ما زلت مسجل الدخول، وذلك حتى تفرغ التخزين المؤقت في متصفحك.",
+       "logouttext": "<strong>أنت الآن غير مسجل الدخول.</strong> قد ترى بعض الصفحات كما لو أنك ما زلت مسجل الدخول، وذلك حتى تفرغ التخزين المؤقت في متصفحك.",
        "welcomeuser": "أهلاً بك يا $1!",
        "welcomecreation-msg": "تم إنشاء حسابك.\nلا تنس تعديل [[Special:Preferences|تفضيلاتك في {{SITENAME}}]].",
        "yourname": "اسم المستخدم:",
        "externaldberror": "هناك إما خطأ في دخول قاعدة البيانات الخارجية أو أنه غير مسموح لك بتحديث حسابك الخارجي.",
        "login": "تسجيل الدخول",
        "nav-login-createaccount": "دخول / إنشاء حساب",
-       "loginprompt": "يجب أن تكون الكوكيز لديك مفعلة لتسجل الدخول إلى {{SITENAME}}.",
        "userlogin": "دخول / إنشاء حساب",
        "userloginnocreate": "تسجيل الدخول",
        "logout": "تسجيل الخروج",
        "license-nopreview": "(العرض المسبق غير متوفر)",
        "upload_source_url": "  (مسار صحيح، يمكن الوصول إليه)",
        "upload_source_file": " (ملف على حاسوبك)",
+       "listfiles-delete": "حذف",
        "listfiles-summary": "هذه الصفحة الخاصة تعرض كل الملفات المرفوعة.",
        "listfiles_search_for": "ابحث عن اسم الميديا:",
        "imgfile": "ملف",
        "exbeforeblank": "المحتوى قبل الإفراغ كان: '$1'",
        "delete-confirm": "حذف \"$1\"",
        "delete-legend": "حذف",
-       "historywarning": "'''تحذير:''' الصفحة التي توشك على حذفها لها تاريخ فيه {{PLURAL:$1||مراجعة واحدة|مراجعتان|$1 مراجعات|$1 مراجعة}} تقريبا:",
+       "historywarning": "'''تنبيه:''' الصفحة التي تريد حذفها بها {{PLURAL:$1|نسخة|نسخة واحدة|نسختان|$1 نسخ|$1 نسخة}}. انظر",
        "confirmdeletetext": "أنت على وشك أن تقوم بحذف صفحة بالإضافة إلى كل تاريخها.\nمن فضلك التأكد من عزمك على الحذف، وبأنك مدرك للعواقب، وبأنك تقوم بهذا بالتوافق مع [[{{MediaWiki:Policy-url}}|السياسة]].",
        "actioncomplete": "انتهاء العملية",
        "actionfailed": "الفعل فشل",
        "delete-edit-reasonlist": "عدل أسباب الحذف",
        "delete-toobig": "لهذه الصفحة تاريخ تعديل طويل، أكثر من {{PLURAL:$1||مراجعة واحدة|مراجعتين|$1 مراجعات|$1 مراجعة}}.\nقُيّد محذف مثل هذه الصفحات لمنع الاضطراب المفاجئة في {{SITENAME}}.",
        "delete-warning-toobig": "لهذه الصفحة تاريخ تعديل طويل، أكثر من {{PLURAL:$1||مراجعة واحدة|مراجعتين|$1 مراجعات|$1 مراجعة}}.\nقد يؤدي حذفها إلى اضطراب عمليات قاعدة البيانات في {{SITENAME}}؛\nاستمر مع الحذر.",
-       "deleting-backlinks-warning": "'''تحذير:''' ترتبط [[Special:WhatLinksHere/{{FULLPAGENAME}}|صفحات أخرى]] بالصفحة التي أنت على وشك حذفها.",
+       "deleting-backlinks-warning": "[[Special:WhatLinksHere/{{FULLPAGENAME}}|تتصل صفحات أخرى]] بالصفحة التي تريد حذفها.",
        "rollback": "استرجاع التعديلات",
        "rollback_short": "استرجع",
        "rollbacklink": "استرجع",
        "expand_templates_remove_nowiki": "أخفِ وسوم <nowiki> في الناتج",
        "expand_templates_generate_xml": "اعرض شجرة XML parse",
        "expand_templates_generate_rawhtml": "أظهر خام HTML",
-       "expand_templates_preview": "عرض مسبق"
+       "expand_templates_preview": "عرض مسبق",
+       "pagelang-name": "صفحة"
 }
index c1885cf..9b12248 100644 (file)
        "tog-hideminor": "خبي الكتيبات الصغيرة في التبديلات التوالا",
        "tog-hidepatrolled": "خبي الكتيبات المعسوسه في التبديلات التوالا",
        "tog-newpageshidepatrolled": "خبي الباجات المعسوسه اللي في ليستت الباجات الجدد",
-       "tog-extendwatchlist": "دÙ\84Ù\8a Ø§Ù\84Ù\84Ù\8aستÙ\87 Ù\86تاع Ø§Ù\84تبÙ\8aعÙ\87 Ø¨Ø§Ø´ ØªØ¹Ø±Ø¶ Ù\83اÙ\85Ù\84 Ø§Ù\84تبدÙ\8aÙ\84ات Ù\88 Ù\85Ø´Ù\8a Ø¨Ø±Ù\83 التوالا",
-       "tog-usenewrc": "اجÙ\85ع Ø§Ù\84Ù\80تبداÙ\84ات Ø¨Ù\84 ØµÙ\81حات Ù\81Ù\84 ØªØ¨Ø¯Ø§Ù\84ات Ø§Ù\84Ù\80تاÙ\84Ù\8aØ© Ù\88 Ø§Ù\84Ù\80Ù\84Ù\8aستة ØªØ§Ø¹ Ø§Ù\84Ù\80Ù\85راÙ\82بة (تستحÙ\82 Ø§Ù\84Ù\80 JavaScript)",
+       "tog-extendwatchlist": "دÙ\84Ù\91Ù\8a Ø§Ù\84Ù\84Ù\8aستة ØªØ§Ø¹ Ø§Ù\84تتباع Ø¨Ø§Ø´ ØªÙ\88رÙ\91Ù\8a Ù\83اÙ\85Ù\84 Ø§Ù\84تبدÙ\8aÙ\84اتØ\8c Ù\85اشÙ\8a Ø¨Ø±Ù\83 ØºÙ\8aر التوالا",
+       "tog-usenewrc": "جÙ\85Ù\91ع Ø§Ù\84Ù\80تبداÙ\84ات Ø¨Ù\84 ØµÙ\81حة Ù\81Ù\84 ØªØ¨Ø¯Ø§Ù\84ات Ø§Ù\84Ù\80جدÙ\8aدة Ù\88 Ø§Ù\84Ù\80Ù\84Ù\8aستة ØªØ§Ø¹ Ø§Ù\84Ù\80عسÙ\91Ø©",
        "tog-numberheadings": "رقم اليا عناوين السكسيو",
-       "tog-showtoolbar": "تبÙ\8aاÙ\86 Ø¨Ø§Ø±Ù\87 Ø§Ù\84Ù\83تÙ\8aبات (Ù\8aÙ\84زÙ\85Ù\87ا Ø¬Ø§Ù\81اسÙ\83رÙ\8aبت)",
-       "tog-editondblclick": "كتيبت الباجات بالزوج دركات (يلزمها جافاسكربت)",
-       "tog-editsectiononrightclick": "اÙ\83تÙ\8aÙ\81Ù\8a Ù\83تÙ\8aبت Ø§Ù\84سÙ\83سÙ\8aÙ\88ات Ø¨Ø§Ù\84درÙ\8aÙ\83 Ø¨Ø§Ù\84Ù\8aÙ\85Ù\8aÙ\86 Ø¹Ù\84Ù\89 Ø§Ù\84عÙ\86اÙ\88Ù\8aÙ\86 Ù\86تاعÙ\87Ù\85\8aتطÙ\84ب Ø¬Ø§Ù\81اسÙ\83رÙ\8aبت)",
+       "tog-showtoolbar": "بÙ\8aÙ\91Ù\86 Ø§Ù\84بارÙ\91Ø© ØªØ§Ø¹ Ø¯Ù\88زاÙ\86â\80\98 Ø§Ù\84Ù\83تبة",
+       "tog-editondblclick": "آكتيفي التبدال تاع الباجات بل زوج ضركات تاع الفارة",
+       "tog-editsectiononrightclick": "Ø¢Ù\83تÙ\8aÙ\81Ù\8a Ø§Ù\84تبداÙ\84 ØªØ§Ø¹ Ø§Ù\84سÙ\83سÙ\8aÙ\88Ù\91ات Ø¨Ù\84 Ø¶Ø±Ù\8aÙ\83 Ø¨Ù\84 Ù\84Ù\8aÙ\85Ù\86Ø© Ø¹Ù\84Ù\89 Ø§Ù\84عÙ\84اÙ\88Ù\8aÙ\86 Ù\86تاعÙ\87Ù\85",
        "tog-watchcreations": "زيد الـصفحات اللي نخلقها و الـفيشيّات فل قايمة تاع التتباع تاعي",
        "tog-watchdefault": "زيد الـصفحات و الـفيشيّات اللي نبدّلها فل قايمة تاع الـتتباع تاعي",
        "tog-watchmoves": "زيد الـصفحات و الـفيشيات اللي نحوّلها فل قايمة تاع الـتباع تاعي",
        "tog-watchdeletion": "زيد الـصفحات اللي نفصيها فل قايمة تاع التتباع تاعي",
        "tog-minordefault": "ماركي كل التبديلات بلي راهي خفيفه",
-       "tog-previewontop": "Ù\88رÙ\8a Ø´Ù\88Ù\81Ù\87\82بÙ\84Ù\8aÙ\87 Ù\84Ù\84Ù\83تبÙ\87 Ù\81Ù\88Ù\82 ØµÙ\86دÙ\88Ù\82 Ø§Ù\84Ù\83تÙ\8aبÙ\87",
+       "tog-previewontop": "Ù\88رÙ\91Ù\8a Ù\86ضرة Ù\82بÙ\84Ù\8aÙ\91Ø© ØªØ§Ø¹ Ù\88اش Ù\8aصراØ\8c Ù\81Ù\88Ù\82 Ø§Ù\84جÙ\8aÙ\87Ø© ØªØ§Ø¹ Ø§Ù\84تبداÙ\84",
        "tog-previewonfirst": "بين شوفه-قبليه مع اول تبديله",
        "tog-enotifwatchlistpages": "ابحت لي إيمال كي تتبدّل صفحة ولا فيشي من الـليستة تاع الـتتباع تاعي",
-       "tog-enotifusertalkpages": "ابعثÙ\84Ù\8a Ø¨Ø±Ù\8aÙ\87 Ù\83Ù\84 Ù\85ا ØªØ¨Ø¯Ù\84ت Ø¨Ø§Ø¬Øª Ù\86Ù\82اش ديالي",
+       "tog-enotifusertalkpages": "ابعثÙ\84Ù\8a Ø¨Ø±Ù\8aÙ\91Ø© Ù\83Ù\84Ù\91 Ù\85ا ØªØ¨Ø¯Ù\91Ù\84ت Ø¨Ø§Ø¬ØªÙ° Ø§Ù\84تÙ\82رعÙ\8aج ديالي",
        "tog-enotifminoredits": "ابعت لي بريه حتا يلا كانت تبدالات صغيرة فلباجات و الـفيشيّات",
        "tog-enotifrevealaddr": "بين لادريستي إلكترونيك في براوات الاعلام",
        "tog-shownumberswatching": "بين شحال كاين من مستعمل يتبع الباجه",
        "tog-oldsig": "خطّ‘لـيدّ اللي كاين",
        "tog-fancysig": "اعتبر التوقيع كي كتيبه ويكي (بلا وصيله توماتيك)",
-       "tog-uselivepreview": "استعمل الـنضرة الـقبلانيّة (تستحق الـ JavaScript) (تجرابيّة)",
+       "tog-uselivepreview": "استعمل الـنضرة الـقبلانيّة الحيّة (عفسة تجرابيّة، تخلّيك تشوف التبدال الّي يصرا فل وقت الّي تكون تكتب)",
        "tog-forceeditsummary": "نبّهني كي تندخل كاش صفحة خاوية",
        "tog-watchlisthideown": "خبّي الـتبدالات تاوعي فل ليستة تاع الـتتباع",
        "tog-watchlisthidebots": "خبّي الـتبدالات تاع الـروبويات فل ليستة تاع التتباع تاعي",
        "newwindow": "(حل في تاقة جديدة)",
        "cancel": "انيلي",
        "moredotdotdot": "كتر...",
-       "morenotlisted": "Ù\83تر Ù\85اشÙ\8a Ù\85Ù\84Ù\8aستÙ\8a...",
+       "morenotlisted": "Ù\87اد Ø§Ù\84Ù\84Ù\8aستة Ù\85ا Ø±Ø§Ù\87Ù\8aØ´ Ù\85Ù\83Ù\85Ù\88Ù\84Ø©",
        "mypage": "باجه",
-       "mytalk": "نقاش",
+       "mytalk": "تقرعيج",
        "anontalk": "تناقش على الـ ip هادي",
        "navigation": "تبحار",
        "and": "&#32;و",
        "qbmyoptions": "الباجات نتاوعى",
        "faq": "المسقسية المتعاوده",
        "faqpage": "Project:سؤالات متكرره",
-       "vector-action-addsection": "زيد موضوع",
-       "vector-action-delete": "امحي",
-       "vector-action-move": "حول",
-       "vector-action-protect": "بروجي",
-       "vector-action-undelete": "ردّ كيما كان",
-       "vector-action-unprotect": "بدّل الـحماية",
-       "vector-view-create": "أصنع",
-       "vector-view-edit": "بدل",
-       "vector-view-history": "روح للتاريخي",
-       "vector-view-view": "أقرى",
-       "vector-view-viewsource": "شوف المصدر",
        "actions": "أفعال",
        "namespaces": "بلاصه تع أسموات",
        "variants": "متغيرات",
        "history": "تاريخ الملف",
        "history_short": "تاريخ",
        "updatedmarker": "مبدّل منلي الزيارة تاعي الـتالية",
-       "printableversion": "نسخه نتاع طبيع",
+       "printableversion": "نسخة تاع طبيع",
        "permalink": "وصيل دايم",
        "print": "امبريمي",
        "view": "اقرا",
+       "view-foreign": "شوف على $1",
        "edit": "بدل",
+       "edit-local": "عدّل التوصاف المبلّد",
        "create": "أصنع",
+       "create-local": "زيد توصاف مبلّد",
        "editthispage": "بدّل هاد الـصفحة",
        "create-this-page": "خلّق صفحة ب هاد الـعلوان",
        "delete": "امحي",
        "deletethispage": "امحي هاد الـصفحة",
        "undeletethispage": "ردّ الصفحة الّي محيتها",
+       "undelete_short": "رجّع {{PLURAL:$1||تعديل واحد|$1 تعديل}}",
+       "viewdeleted_short": "شوف {{PLURAL:$1||تعديل واحد|$1 تعديل}}",
        "protect": "حمايه",
        "protect_change": "بدل",
+       "protectthispage": "بروتيجي هاد الباجة",
+       "unprotect": "بدّل الحضية",
+       "unprotectthispage": "بدّل الحضية تاع هاد الباجة",
        "newpage": "باجه جديده",
+       "talkpage": "قرعَج على هاد الباجة",
        "talkpagelinktext": "ناقش",
+       "specialpage": "باجة خوصوصيّة",
        "personaltools": "ادوالت شخصيه",
+       "articlepage": "شوف الباجة تاع المحتاوا",
        "talk": "مناقشه",
        "views": "شوفات",
-       "toolbox": "صندوق الادوات",
+       "toolbox": "صندوق تاع الدوزان",
+       "userpage": "شوف الباجة تاع المستعملي",
+       "projectpage": "شوف الباجة تاع البروجي",
+       "imagepage": "شوف الباجة تاع الفيشي",
+       "mediawikipage": "شوف الباجة تاع الميساج",
+       "templatepage": "شوف الباجة تاع القالب",
+       "viewhelppage": "شوف الباجة تاع المعاونة",
+       "categorypage": "شوف الباجة تاع الصنيف",
+       "viewtalkpage": "شوف التقرعيج",
        "otherlanguages": "بلوغات وحد اوخره",
        "redirectedfrom": "(محول من $1)",
+       "redirectpagesub": "باجة تاع التحوال",
        "lastmodifiedat": "هاد الباجه راهي تبدّلت نهار الـ $1, على الـساعة $2.",
+       "viewcount": "هاد الباجة نشافت {{PLURAL:$1|خطرة وحدة|$1 خطرة}}.",
+       "protectedpage": "باجة محضيّة",
        "jumpto": "اقفز ل:",
        "jumptonavigation": "تجوال",
        "jumptosearch": "تفتاش",
+       "view-pool-error": "اعدرونا، السربايات راهم مغبّنين ف هاد الوقيتة.\nبزّاف المستعمليّين راهم باغيين يشوفو هاد الباجة.\nاصبرو شي وقيتة قبل ما تحاولو تلحقو لها عاود.\n\n$1",
+       "generic-pool-error": "اعدرونا، السربايات راهم مغبّنين ف هاد الوقيتة.\nبزّاف المستعمليّين راهم باغيين يشوفو هاد الباجة.\nاصبرو شي وقيتة قبل ما تحاولو تلحقو لها عاود.",
+       "pool-timeout": "المهلة تاع المقارعة راهي فاتت",
+       "pool-queuefull": "السنسلة تاع المقارعة راهي عامرة",
+       "pool-errorunknown": "خلطة ماشي معروفة",
+       "pool-servererror": "السربيس تاع العدّان راه حابس ( $1 ).",
        "aboutsite": "على{{SITENAME}}",
        "aboutpage": "Project:على",
+       "copyright": "المحتاوا راه تحت النسخة $1 تاع الليسانس، غير يلا كان مكتوب حاجاخرة.",
        "copyrightpage": "{{ns:project}}:حقوق النسخ",
        "currentevents": "الخبورات",
        "currentevents-url": "Project:خبورات",
        "disclaimers": "تنبيهات",
        "disclaimerpage": "Project:التحذيرات العامه",
        "edithelp": "معونة",
-       "mainpage": "الباجة اللوله",
+       "mainpage": "الباجة اللولانيّة",
        "mainpage-description": "الباجة اللوله",
+       "policy-url": "Project:المقاون",
        "portal": "المجتمع",
        "portal-url": "Project:بورطاي المجتمع",
        "privacy": "السياسة تاع الخصوصيات (الدين الضيّق)",
        "privacypage": "Project:خصوصيه",
+       "badaccess": "مشكل فل مسموحات",
+       "badaccess-group0": "ماشي مقبول ليك تدير الشي الّي راك تسيّي تديرهُ.",
+       "badaccess-groups": "الفعلة الّي راك سيّيت تديرها مسموحة برك لل مستعملّين {{PLURAL:$2||الّي هوما منل جماعة|الّي هوما من وحدة من هاد الجمايع}}: $1.",
+       "versionrequired": "النسخة $1 تاع ميدياويكي ملزومة",
+       "versionrequiredtext": "النسخة $1 تاع ميدياويكي راهي ملزومة باش تنجم تستعمل هاد الباجة.\nشوف [[Special:Version|الباجة تاع النسخات باش تفهم كتَر على هاد الشي]]",
+       "ok": "قابل",
        "retrievedfrom": "جايبينه من \"$1\"",
        "youhavenewmessages": "عندك $1 ($2).",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|عندك}} $1 من عند {PLURAL:$3|مستعملي واحد|زوج تاع المستعمليّين|$3 مستعملي}} ($2).",
+       "youhavenewmessagesmanyusers": "عندك $1 من عند شحال من مستعملي ($2).",
+       "newmessageslinkplural": "{{PLURAL:$1|بريّة جديدة وحدة|999=بريّة جديدة}}",
+       "newmessagesdifflinkplural": "{{PLURAL:$1التبديلة التالية|التبديلات التاليين}}",
+       "youhavenewmessagesmulti": "عندك بريّة جديدة في $1.",
        "editsection": "بدل",
        "editold": "بدل",
        "viewsourceold": "شوف الاصل",
        "viewsourcelink": "شوف العين",
        "editsectionhint": "إيديتي الصنف:$1",
        "toc": "محتويات",
+       "showtoc": "ورّي",
+       "hidetoc": "خبّي",
+       "collapsible-collapse": "خبّي",
+       "collapsible-expand": "ورّي",
+       "thisisdeleted": "راك باغي تشوف ولا ترجّع $1؟",
+       "viewdeleted": "شوف $1؟",
+       "restorelink": "{{PLURAL:$1|تبدال واحد مفاصي|$1 تبدالات مفاصيين|$1 تبدال مفاصي}}",
+       "feedlinks": "السيلان:",
+       "feed-invalid": "النوع تاع التلقيمة ماشي مصلاح.",
+       "feed-unavailable": "التلقيمات ما راهمش موجودين.",
        "site-rss-feed": "تيار آر‌إس‌إس $1",
        "site-atom-feed": "$1 تيار آتوم",
+       "page-rss-feed": "تلقيمة RSS تاع \"$1\"",
        "page-atom-feed": "$1 تيار آتوم",
        "red-link-title": "$1 (الباجه ما كاينش)",
+       "sort-descending": "رتّب بل نازولي",
+       "sort-ascending": "رتّب بل طالوعي",
        "nstab-main": "الباجة",
        "nstab-user": "باجة{{GENDER:{{BASEPAGENAME}}|المستخدم|المستخدمة}}",
+       "nstab-media": "باجة تاع ميديا",
        "nstab-special": "باجه خوصوصيّة",
        "nstab-project": "باجه مشروع",
        "nstab-image": "ملف",
+       "nstab-mediawiki": "بريّة",
        "nstab-template": "مودال",
+       "nstab-help": "باجة تاع معاونة",
        "nstab-category": "تصنيف",
+       "nosuchaction": "الشي الّي طلبتهُ ما كاينش",
+       "nosuchactiontext": "الفعلة الّي مطلوبة فل URL ماشي مقبولة.\nبالاك ما دخّلتوش الـ URL كيما لازم ولا تاني تبّعتو كاش وصيل مغلوط.\nينجم تاني يكون كاين عُلّة فل لوجيسيال الّي مستعمل فـ {{SITENAME}}.",
+       "nosuchspecialpage": "هاد الباجة الخوصوصيّة ما كاينش منها",
+       "nospecialpagetext": "<strong>راك طلبت باجة خوصوصيّة ماشي صحيحة.</strong>\n\nتصيب الليستة تاع الباجات الخوصوصيّة في [[Special:SpecialPages|{{int:specialpages}}]].",
+       "error": "غلطة",
+       "databaseerror": "غلطة فل دخيرة تاع الخبيرات (DB)",
+       "databaseerror-text": "صرات غلطة عند المسقسية تاع الدخيرة تاع الخبيرات. هاد الشي ينجم يكون جاي من غلطة فل برنامج.",
+       "databaseerror-textcl": "صرات غلطة عند المسقسية تاع الدخيرة تاع الخبيرات.",
+       "databaseerror-query": "مسقسية : $1",
+       "databaseerror-function": "دالّة: $1",
+       "databaseerror-error": "غلطة: $1",
+       "laggedslavemode": "<strong>ردّ بالك:</strong> هاد الباجة تنجم تكون ما حاوياش التبدالات التاليين الّي ندارو.",
+       "readonly": "الدخيرة تاع الخبيرات راهي مغلوقة",
+       "enterlockreason": "حطّ السبّة تاع القفيل و المدّة تاعهُ بل ميز.",
+       "readonlytext": "الدخيرة تاع الخبيرات راهي مغلوقة على الدخلات الجديدة ولا التبدالات، بالاك علاجال كاش صيانة عاديّة، مور ماش غادي تعاود ترجع لل طبَع.\n\nالإيداري الّي دار هاد الشي راه يعطي التفسيرات هادي: $1",
        "missing-article": "الداتاباز ما صابتش باجه كان لازم تنصاب، الباجه هي \"$1\" $2.\n\nنورمالمو يصرا هذا مين اتبع فرق بيريمي والا وصيل تأريخ باجة ممحيه.\n\nإذا ما كانش هذا هو الحال همالا راك طحت في علة تاع البرمجية.\nمن فضلك سينياليها لواحد من[[Special:ListUsers/sysop|الإداريين]]، و أعطه مسار هذه الباجه.",
        "missingarticle-rev": "(رقم الفرسيون: $1)",
+       "missingarticle-diff": "(فرق بين: $1، $2)",
+       "readonly_lag": "الدخيرة تاع الخبرات راهي مقفولة بيدما السربايات التوناويّة يلحقو التوخار الّي عندهم معا السرباي اللولاني",
+       "internalerror": "غلطة دخلانيّة",
+       "internalerror_info": "غلطة دخلانيّة: $1",
+       "filecopyerror": "ما قدرش تنساخ الفيشي \"$1\" لل \"$2\"",
+       "filerenameerror": "ما قدرش تبدال السميّة تاع الفيشي \"$1\" لل \"$2\".",
+       "filedeleteerror": "ما قدرش تمحيتٰ الفيشي \"$1\".",
+       "directorycreateerror": "ما قدرش خلقان الدفتار \"$1\".",
+       "filenotfound": "ما قدرش مصيبتٰ الفيشي \"$1\".",
+       "unexpected": "قيمة ما شي مستنية : \"$1\"=\"$2\".",
+       "formerror": "غلطة: ما قدرش ترسال الستيمارة",
+       "badarticleerror": "هاد الفعلة ما تنجمش تندار ف هاد الباجة.",
+       "cannotdelete": "ما تنجّمش تمحيتٰ الباجة ولا الفيشي \"$1\".\nبالاك كان دار المحيان شي واحد من قبَل.",
+       "cannotdelete-title": "ما يمكنش محيان الباجة \"$1\".",
+       "delete-hook-aborted": "المحيان راه منحّي من عند كاش توسيعة.\nما عندنا حتا تفسار على هاد الشي.",
+       "no-null-revision": "ما يمكنش تخلاق مراجعة جديدة خاوية لل باجة \"$1\".",
        "badtitle": "عنوان عيان",
        "badtitletext": "عنوان الباجه المطلوب إما ماشي صحيح والا فارغ، وبالاك الوصيل بين اللغات والا بين البروجيات ماشي صحيح.\nبالاك فيه حروف ما تصلحش  باس يستعملوها فالعناوين.",
+       "perfcached": "الموطايات هادي راهي مخبّية و بالاك تاني يكون فات عليها الوقت. {{PLURAL:$1||ناتج واحد|زوج نواتج|$1 نواتج|$1 ناتج}} على الكتَر {{PLURAL:$1||مخبّي|مخبّيين}}.",
        "viewsource": "شوف الاصل",
        "yourname": "اسم المستخدم:",
        "yourpassword": "كلمة السر:",
        "remembermypassword": "اتفكر الدخول تاعي ب هاذ النافيكاتور (ب مدّة حدها{{PLURAL:$1||يوم واحد|يومين|$1 إيّام|$1 يوم}})",
        "login": "كونكسيون",
        "nav-login-createaccount": "تسجل/ اصنع حساب",
-       "loginprompt": "لازم تكون الكوكيز لديك ماكتيفيه باش تكونيكتي و تدخل ل{{SITENAME}}.",
        "userlogin": "تسجل/ اصنع حساب",
        "userlogout": "سجل خروج",
        "nologin": "ما عندكش حساب مسجل؟ '''$1'''.",
        "link_tip": "وصيلة داخليه",
        "extlink_sample": "http://www.example.com اسم الوصيلة",
        "extlink_tip": "وصيلة برانية (ما تنساش البديةhttp://)",
-       "headline_sample": "كتبة نتاع عنوان كبير",
+       "headline_sample": "كتبة تاع علوان كبير",
        "headline_tip": "عنوان من المستوى الثاني",
        "nowiki_sample": "دخل الكتبة مشي مستفة هنا",
        "nowiki_tip": "اهمل طريقةالويكي",
        "post-expand-template-argument-warning": "'''توليه:''' هذه الباجه فيها عامل قالب واحد على الأقل عندو حجم تمدد كبير بزاف.\nهاذالعوامل اتمحات.",
        "post-expand-template-argument-category": "باجات فيها مدخلات القالب الممحي",
        "viewpagelogs": "بين العمليات على هاذ الباحه",
-       "currentrev-asof": "النسخه نتاع دروك تاريجها $1",
+       "currentrev-asof": "نسخة ضركانية بل تاريخ تاع $1",
        "revisionasof": "معاودة تاع الـ $1",
        "revision-info": "مراجعه $1 بواسطت $2",
        "previousrevision": "← نسخة اللوله",
        "lineno": "سطر$1:",
        "compareselectedversions": "كومباري بين نسختين مخيرين",
        "editundo": "نحي",
-       "searchresults": "ريزيلته نتاع التفتاش",
+       "searchresults": "نتاج تاع التفتيشة",
        "searchresults-title": "ريزيلته تاع التحواس \"$1\"",
        "prevn": "{{PLURAL:$1|précédente|$1 اللولانيين}}",
        "nextn": "{{PLURAL:$1|suivante|$1 التاليين}}",
        "searchmenu-exists": "'''كاين باجه اسمها « [[:$1]] » في هاذ الويكي'''",
        "searchmenu-new": "'''أصنع الباجه « [[:$1|$1]] » في هذ الويكي !'''",
        "searchprofile-articles": "باجه تع محتوى",
-       "searchprofile-project": "باجه تع المعونه و البروجي",
        "searchprofile-images": "ميلتيميديا",
        "searchprofile-everything": "كلش",
        "searchprofile-advanced": "تفتاش متقدم",
        "searchprofile-articles-tooltip": "فتش في $1",
-       "searchprofile-project-tooltip": "فتش في  $1",
        "searchprofile-images-tooltip": "فتش على ملفات ميلتيميديا",
        "searchprofile-everything-tooltip": "فتش في قاع السيت (حتى في باجات المناقشه)",
        "searchprofile-advanced-tooltip": "خير إسباسات الأسامي للتفتاش",
        "booksources-go": "اذهب",
        "log": "ريجيسترات العمليات",
        "allpages": "قاع الباجات",
-       "alphaindexline": "$1 إلى $2",
        "allarticles": "قاع الباجات",
        "allpagessubmit": "روح",
        "categories": "تصنيفات",
        "linksearch-line": "$1 موصولة من $2",
        "listgrouprights-members": "(ليسته الأعضاء)",
        "emailuser": "ابعث بريه لهاذ المستخدم",
-       "watchlist": "ليستة نتاع التابعه",
-       "mywatchlist": "ليستة نتاع التابعه",
+       "watchlist": "ليستة تاع المتابعة",
+       "mywatchlist": "ليستة تاع المتابعة",
        "watchlistfor2": "ل$1 ($2)",
        "watch": "تبع",
        "unwatch": "ما تزيدش تعس",
        "sp-contributions-blocklog": "ريجيسترالمنع",
        "sp-contributions-uploads": "مرفوعات",
        "sp-contributions-logs": "ريجيسترات",
-       "sp-contributions-talk": "نقاش",
+       "sp-contributions-talk": "تقرعيج",
        "sp-contributions-search": "تفتاش المشاركات",
        "sp-contributions-username": "عنوان أيبي والال اسم مستخدم:",
-       "sp-contributions-toponly": "ما تبين غير المشاركات التوالا نتاع المقالات",
+       "sp-contributions-toponly": "ما تورّي غير المشاركات التوالا تاع المقالات",
        "sp-contributions-submit": "تفتاش",
        "whatlinkshere": "واش يوصل هنا",
        "whatlinkshere-title": "الباجات اللي تقين في \"$1\"",
        "tooltip-pt-mycontris": "ليسته نتع مساهماتك",
        "tooltip-pt-login": "مادابيك تسجل الدخول تاعك، بصّح ماشي ملزوم عليك",
        "tooltip-pt-logout": "سجل خروج",
-       "tooltip-ca-talk": "نقاش على باجت المحتوى",
+       "tooltip-ca-talk": "تقرعيج على باجتٰ المحتاوا",
        "tooltip-ca-edit": "تنجم تحرر هاذ الباجه ،ماذابيك تستعمل قفله المراجعه قبل ما تحفظ",
        "tooltip-ca-addsection": "ابدأ طرف جديد",
        "tooltip-ca-viewsource": "هاذ الباجه محميه. و شنو تقدرو تشوفو الأصلي نتاعها",
-       "tooltip-ca-history": "المراجعات التوالى نتاع الباجه (مع المساهمين نتاوعها)",
+       "tooltip-ca-history": "المراجعات التوالا تاع الباجة (معا المساهمين تاوعها)",
        "tooltip-ca-protect": "بروتيجي هاذالباجه",
        "tooltip-ca-delete": "امحي هاذ الباجه",
        "tooltip-ca-move": "بدل أسم هذ الباجه",
-       "tooltip-ca-watch": "زيد هذ الباجه لليستتك نتاع التتباع",
-       "tooltip-ca-unwatch": "اÙ\82Ù\84ع Ù\87اذ Ø§Ù\84باجÙ\87 Ù\85Ù\86 Ø§Ù\84Ù\84Ù\8aستÙ\87 Ù\86تاع التتباع",
+       "tooltip-ca-watch": "زيد هذ الباجة لل ليستة تاعك تاع التتباع",
+       "tooltip-ca-unwatch": "اÙ\82Ù\84ع Ù\87اد Ø§Ù\84باجة Ù\85Ù\86Ù\84 Ù\84Ù\8aستة ØªØ§Ø¹Ù\83 تاع التتباع",
        "tooltip-search": " فتّش في {{SITENAME}}",
        "tooltip-search-go": "روح الباجه عندها نفس الآسم إذا كانت كاينه",
        "tooltip-search-fulltext": "فتّش على باجه بهاد الكتبة",
        "tooltip-n-mainpage": "زور الباجه اللوله",
        "tooltip-n-mainpage-description": "زور الباجه لوله",
        "tooltip-n-portal": "على الپروجي،واش تنجم تدير، وين تصيب واش تحتاج",
-       "tooltip-n-currentevents": "تحÙ\88اس Ø¹Ù\84Ù\89 Ù\85عÙ\84Ù\88Ù\85ات Ø£Ø³Ø§Ø³Ù\8aØ© Ù\84صÙ\88اÙ\84Ø­ ØµØ±Ø§Ù\88 Ø°Ø±Ù\88Ù\83",
+       "tooltip-n-currentevents": "صÙ\8aب Ø®Ø¨Ø§Ø±Ø§Øª Ù\85ستÙ\91رÙ\8aÙ\86 Ø¹Ù\84Ù\89 Ø§Ù\84صÙ\88اÙ\84Ø­ Ø§Ù\84Ù\91Ù\8a Ø±Ø§Ù\87Ù\85 Ù\8aصراÙ\88 Ø¶Ø±Ù\83ا",
        "tooltip-n-recentchanges": "الليستة تاع التبديلات التوالا فل ويكي",
        "tooltip-n-randompage": "طلّع باجه على الزهر",
        "tooltip-n-help": "بلاصة المعونة",
-       "tooltip-t-whatlinkshere": "ليسته نتاع قاع باجات المحتوى الي توصل هنا",
-       "tooltip-t-recentchangeslinked": "ليسته نتاع التبديلات التواله نتاع الباجات الي عندهم علاقه بهاذي",
-       "tooltip-feed-atom": "سيلان آتوم نتاع الباجه",
+       "tooltip-t-whatlinkshere": "ليستة تاع كاع الباجات تاع المحتاوا الي توصّل لهنا",
+       "tooltip-t-recentchangeslinked": "ليستة تاع التبديلات التوالا تاع الباجات الّي عندهم رباط معا هادي",
+       "tooltip-feed-atom": "سيلان آتوم تاع هاد الباجة",
        "tooltip-t-contributions": "شوفان ليسته مساهمات هاذا المستخدم",
        "tooltip-t-emailuser": "أرسل بريه لهاذ المستخدم",
        "tooltip-t-upload": "أرسل تصويرة و إلا أي ملف ميديا للسرفر",
        "tooltip-t-specialpages": "ليستة تاع كامل الباجات الخصوصيّة",
        "tooltip-t-print": "نسخه لهاذ الباجه قابله للطبيع",
-       "tooltip-t-permalink": "توصيله دايمه رايحه لهاذ النسخة نتاع الباجة",
+       "tooltip-t-permalink": "وصيل دايم رايح ل هاد النسخة تاع الباجة",
        "tooltip-ca-nstab-main": "شوف باجه المحتوى",
        "tooltip-ca-nstab-user": "شوف باجت المستعمل",
        "tooltip-ca-nstab-special": "هذه الباجه خصوصيه،ما تقدرش تبدل فيها",
        "tooltip-minoredit": "ماركي هاذا تبديل صغير",
        "tooltip-save": "سجل تبديلات نتاعك",
        "tooltip-preview": "بين التغييرات نتاعك، من فضلك استخدم هذا قبل ما تنشر!",
-       "tooltip-diff": "تخلي الشوفان نتاع التبديلات اللي ندارو.",
+       "tooltip-diff": "ورّي التبدالات الّي راك درتهم فل نصّ.",
        "tooltip-compareselectedversions": "شوف الفروق بين نسختين مخيرين من هاذ الباجه.",
-       "tooltip-watch": "زÙ\8aد Ù\87Ø° Ø§Ù\84باجÙ\87 Ù\84Ù\84Ù\8aستتÙ\83 Ù\86تاع التتباع",
-       "tooltip-rollback": "يولي : بدركة وحده تآنيلي التبديله و إلا التبديلات نتاع المساهم التالي",
+       "tooltip-watch": "زÙ\8aد Ù\87اد Ø§Ù\84باجة Ù\84Ù\84 Ù\84Ù\8aستة ØªØ§Ø¹Ù\83 تاع التتباع",
+       "tooltip-rollback": "\"نحّي\" : ب ضركة وحدة تآنيلي التبديلة ولا التبديلات تاع المساهم التالي",
        "tooltip-undo": "\"نحّي\" فاصي هاد الـمعاودة و حلّ تاقة تاع تبدال بشوفه قبلانيّه. تخلّي باش ترجع لل معاوده التاليه و تزيد الـسبّة علاش فل قابسه تاع الـحويصله.",
        "tooltip-summary": "دخل تلخيص صغير",
        "previousdiff": "→ التعديل الي قبل",
        "file-nohires": "ما كانش دقه اكثر من هاك",
        "svg-long-desc": "فيشيي SVG، أبعاده $1 × $2 بكسل، تاي الفيشي : $3",
        "show-big-image": "تصويرة دقة عالية",
-       "bad_image_list": "الفورمه كيما التابعة:\nما كاين غير السطور الّي باديين بل *، الّي يكونو معدودين\nالـوصيل الـلوّل نتاع سطر لازم تكون تاع تصويرة ضايعة.\nكامل الوصيلات لخرين الّي فل سطر، يكونو معدودين كلّي تتنيّات، بل كي الباجات وين الـفيشي يكون باين.",
+       "bad_image_list": "الفورمة راهي كيما واش يتبع:\nما كاين غير السطور الّي باديين بل *، الّي يكونو معدودين\nالـوصيل الـلوّل تاع سطر لازم كون تاع تصويرة ضايعة.\nكامل الوصيلات لخرين الّي فل سطر، يكونو معدودين كلّي تتنيّات، بل متال باجات وين الـتصويرة تنجم تبان.",
        "metadata": "بايان ميتا",
-       "metadata-help": "هذا الملف راه فيه معلومات زيادة، بالاك تكون انزادت من عند صواره نيميريك ولا سكانر مين صنع الملف.\nالأصلي، شي تفاصيل بالاك ما تعبرش على الملف المعدل.",
-       "metadata-fields": "غادÙ\8a Ù\8aÙ\86عرض Ø§Ù\84Ø­Ù\82Ù\84 Ù\86تاع Ù\85عطÙ\8aات Ø§Ù\84Ù\85Ù\8aتا Ø§Ù\84Ù\83اÙ\8aÙ\86Ù\87 Ù\81Ù\8a Ù\87اذ Ø§Ù\84برÙ\8aÙ\87 Ù\81Ù\8a Ø¨Ø§Ø¬Ù\87 Ø§Ù\84تصÙ\88Ù\8aرة Ù\85Ù\86Ù\8aÙ\86 Ù\8aÙ\83Ù\88Ù\86 Ø¬Ø¯Ù\88Ù\84 Ù\85عطÙ\8aات Ø§Ù\84Ù\85Ù\8aتا Ù\85Ø·Ù\88Ù\8aاÙ\8b.\nاÙ\84Ø­Ù\82Ù\88Ù\84 Ù\84خرÙ\87 ØªÙ\83Ù\88Ù\86 Ù\85خبÙ\8aØ© Ø¨Ø§Ø± ديفو.\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-help": "هذا الملف راه فيه خبيرات زايدين، بالاك تكون انزادت من عند صواره نيميريك ولا سكانر مين صنع الملف.\nالأصلي، شي تفاصيل بالاك ما تعبرش على الملف المعدل.",
+       "metadata-fields": "اÙ\84Ø­Ù\82Ù\88Ù\84 ØªØ§Ø¹ Ø§Ù\84Ù\85Ù\8aتا Ù\85عطÙ\8aÙ\91ات ØªØ§Ø¹ ØªØµØ§Ù\88ر Ø§Ù\84Ù\91Ù\8a Ù\8aÙ\83Ù\88Ù\86Ù\88 Ù\81 Ù\87اد Ø§Ù\84برÙ\8aÙ\91Ø© ØºØ§Ø¯Ù\8a Ù\8aÙ\86حطÙ\91Ù\88 Ù\81Ù\84 Ø¨Ø§Ø¬Ø© ØªØ§Ø¹ Ø§Ù\84تÙ\88صاÙ\81 ØªØ§Ø¹ Ø§Ù\84تصÙ\88Ù\8aرة Ù\85Ù\86Ù\8aÙ\86 Ù\8aÙ\83Ù\88Ù\86 Ø§Ù\84جدÙ\88Ù\84 ØªØ§Ø¹  Ø§Ù\84Ù\85Ù\8aتااÙ\84Ù\85عطÙ\8aات Ù\85Ø·Ù\88Ù\8a.\nاÙ\84Ø­Ù\82Ù\88Ù\84 Ù\84خرة Ù\8aÙ\83Ù\88Ù\86Ù\88 Ù\85خبÙ\8aÙ\8aÙ\86 Ø¨Ø§Ø±ديفو.\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",
        "watchlistall2": "لكل",
        "namespacesall": "لكل",
        "monthsall": "لكل",
index e04983e..63a7d9f 100644 (file)
@@ -8,7 +8,8 @@
                        "Meno25",
                        "Ouda",
                        "Ramsis II",
-                       "아라"
+                       "아라",
+                       "Oldstoneage"
                ]
        },
        "tog-underline": "حط خط تحت اللينكات:",
        "talkpagelinktext": "مناقشه",
        "specialpage": "صفحة مخصوصة",
        "personaltools": "ادوات شخصيه",
-       "postcomment": "قسم جديد",
        "articlepage": "بين صفحة المحتوى",
        "talk": "مناقشه",
        "views": "مناظر",
        "externaldberror": "يا إما فى حاجة غلط فى الدخول على قاعدة البيانات الخارجية أو انت مش مسموح لك تعمل تحديث لحسابك الخارجي.",
        "login": "دخول",
        "nav-login-createaccount": "تسجيل دخول / فتح حساب",
-       "loginprompt": "لازم تكون الكوكيز عندك مفعله علشان تقدر تدخل ل {{SITENAME}}.",
        "userlogin": "دخول / فتح حساب",
        "userloginnocreate": "دخول",
        "logout": "خروج",
        "timezone-utc": "يو تى سى",
        "unknown_extension_tag": "تاج بتاع امتداد مش معروف \"$1\"",
        "duplicate-defaultsort": "تحزير: زرار الترتيب الاوتوماتيكي\"$2\" بيوقف زرار الترتيب الاوتوماتيكي\"$1\" القديم.",
-       "version": "نسخه",
+       "version": "نسخة",
        "version-extensions": "الامتدادات المتثبتة",
        "version-specialpages": "صفحات مخصوصة",
        "version-parserhooks": "خطاطيف البريزر",
index 53e2e7b..45b37ee 100644 (file)
        "talkpagelinktext": "Alderique",
        "specialpage": "Páxina especial",
        "personaltools": "Ferramientes personales",
-       "postcomment": "Seición nueva",
        "articlepage": "Ver la páxina de conteníu",
        "talk": "Alderique",
        "views": "Vistes",
        "externaldberror": "O hebo un fallu d'autenticación de la base de datos o nun tienes permisu p'anovar la to cuenta esterna.",
        "login": "Entrar",
        "nav-login-createaccount": "Entrar / crear cuenta",
-       "loginprompt": "Ha de tener les «cookies» activaes p'aniciar sesión en {{SITENAME}}.",
        "userlogin": "Entrar / crear cuenta",
        "userloginnocreate": "Aniciar sesión",
        "logout": "Salir",
        "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 '''atrás''' 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.''\nPoro, tenemos qu'usar la direición numbérica IP pa identificalu/la.\nEsa IP pue tar compartida por varios usuarios.\nSi ye un usuariu anónimu y cree qu'hai comentarios irrelevantes empobinaos a vusté, por favor, [[Special:UserLogin/signup|cree una cuenta]] o [[Special:UserLogin/signup|anicie sesión]] pa torgar futures confusiones con otros usuarios anónimos.",
-       "noarticletext": "Nestos momentos nun hai testu nesta páxina.\nPue [[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}} editar esta páxina]</span>.",
+       "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:UserLogin/signup|crea una cuenta]] o [[Special:UserLogin/signup|identifícate]] pa torgar futures confusiones con otros usuarios anónimos.",
+       "noarticletext": "Nestos momentos nun hai testu nesta páxina.\nPues [[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}} editar esta páxina]</span>.",
        "noarticletext-nopermission": "Nestos momentos nun hai testu nesta páxina.\nPue [[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 tiene 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].",
        "userpage-userdoesnotexist": "La cuenta d'usuariu «$1» nun ta rexistrada.\nPor favor comprueba si quies crear/editar esta páxina.",
        "currentrev": "Revisión actual",
        "currentrev-asof": "Revisión actual a fecha de $1",
        "revisionasof": "Revisión a fecha de $1",
-       "revision-info": "Revisión a fecha de $1; $2",
+       "revision-info": "La revisión del $4 a les $5 por {{GENDER:$6|$2}}$7",
        "previousrevision": "←Revisión anterior",
        "nextrevision": "Revisión siguiente→",
        "currentrevisionlink": "Revisión actual",
        "revdelete-text-text": "Les revisiones desaniciaes inda apaecerán nel historial de la páxina, pero partes del conteníu nun sedrán accesibles al públicu.",
        "revdelete-text-file": "Les versiones del ficheru desaniciaes inda apaecerán nel historial del ficheru, pero partes del conteníu nun sedrán accesibles al públicu.",
        "logdelete-text": "Los socesos del rexistru desaniciaos inda apaecerán nos rexistros, pero partes del conteníu nun sedrán accesibles al públicu.",
-       "revdelete-text-others": "Otros alministradores de {{SITENAME}} inda tendrán accesu al conteníu anubríu y puen desfacer l'anubrimientu con esta mesma interfaz, mentanto nun se configuren otres torgues más.",
+       "revdelete-text-others": "Otros alministradores inda tendrán accesu al conteníu anubríu y puen desfacer el desaniciu, mentanto nun se configuren otres torgues más.",
        "revdelete-confirm": "Confirma que quies facer esto, qu'entiendes les consecuencies, y que vas facer esto d'alcuerdo [[{{MediaWiki:Policy-url}}|cola política]].",
        "revdelete-suppress-text": "La supresión '''namái''' tendría d'usase nos casos darréu:\n* Información que pudiere ser bilordiosa\n* Información personal inapropiada\n*: ''direiciones de llares y númberos de teléfonu, númberos d'identidá nacional, etc.''",
        "revdelete-legend": "Establecer torgues de visibilidá",
        "mergehistory-empty": "Nun se pue fusionar nenguna revisión.",
        "mergehistory-success": "$3 {{PLURAL:$3|revisión|revisiones}} de [[:$1]] fusionaes correutamente en [[:$2]].",
        "mergehistory-fail": "Nun se pudo facer la fusión d'historiales, por favor verifica la páxina y los parámetros temporales.",
+       "mergehistory-fail-toobig": "Nun pudo fusionase l'historial porque moveríense más del máximu de $1 {{PLURAL:$1|revisión|revisiones}}.",
        "mergehistory-no-source": "La páxina d'orixe $1 nun esiste.",
        "mergehistory-no-destination": "La páxina de destín $1 nun esiste.",
        "mergehistory-invalid-source": "La páxina d'orixe ha tener un títulu válidu.",
        "powersearch-togglelabel": "Comprobar:",
        "powersearch-toggleall": "Toos",
        "powersearch-togglenone": "Dengún",
+       "powersearch-remember": "Recordar la seleición pa guetes futures",
        "search-external": "Busca esterna",
        "searchdisabled": "La busca en {{SITENAME}} ta desactivada. Mentanto, pues buscar en Google. Has fixate en que'l conteníu de los sos índices de {{SITENAME}} pue tar desfasáu.",
        "search-error": "Hebo un error al buscar: $1",
        "largefileserver": "Esti ficheru ye mayor de lo que permite la configuración del sirvidor.",
        "emptyfile": "El ficheru que xubisti paez tar vaciu.\nEsto podría ser pola mor d'un enquivocu nel nome del ficheru.\nPor favor, camienta si daveres quies xubir esti archivu.",
        "windows-nonascii-filename": "Esta wiki nun permite nomes de ficheru con caráuteres especiales.",
-       "fileexists": "Yá esiste un ficheru con esti nome, por favor comprueba <strong>[[:$1]]</strong> si nun tas seguru de querer camudalu.\n[[$1|thumb]]",
+       "fileexists": "Yá esiste un ficheru con esti nome, por favor comprueba <strong>[[:$1]]</strong> si nun tas {{GENDER:|seguru|segura}} de querer camudalu.\n[[$1|thumb]]",
        "filepageexists": "La páxina de descripción d'esti ficheru creóse yá en <strong>[[:$1]]</strong>, pero anguaño nun esiste nengún ficheru con esti nome.\nEl resume que pongas nun va apaecer na páxina de descripción.\nPa facer que'l to resume apaeza, vas tener qu'editalu manualmente.\n[[$1|thumb]]",
-       "fileexists-extension": "Yá esiste un ficheru con un nome asemeyáu: [[$2|thumb]]\n* Nome del ficheru que se quier xubir: <strong>[[:$1]]</strong>\n* Nome del ficheru esistente: <strong>[[:$2]]</strong>\nPor favor escueyi un nome diferente.",
+       "fileexists-extension": "Yá esiste un ficheru con un nome asemeyáu: [[$2|thumb]]\n* Nome del ficheru que se quier xubir: <strong>[[:$1]]</strong>\n* Nome del ficheru esistente: <strong>[[:$2]]</strong>\n¿Quies meyor usar un nome más distinguible?",
        "fileexists-thumbnail-yes": "El ficheru paez ser una imaxe de tamañu menguáu ''(miniatura)''.\n [[$1|thumb]]\nPor favor comprueba el ficheru <strong>[[:$1]]</strong>.\nSi'l ficheru comprobáu tien el mesmu tamañu que la imaxe orixinal, nun ye necesario xubir una miniatura estra.",
        "file-thumbnail-no": "El ficheru entama con <strong>$1</strong>.\nPaez ser una imaxe de tamañu menguáu ''(miniatura)''.\nSi tienes esta imaxe a resolución completa xúbila; si non, por favor camuda'l nome del ficheru.",
        "fileexists-forbidden": "Yá esiste un ficheru con esti nome, y nun se pue renomar.\nSi tovía asina quies xubir el ficheru, por favor vuelvi atrás y usa otru nome.\n[[File:$1|thumb|center|$1]]",
        "license": "Llicencia:",
        "license-header": "Llicencia",
        "nolicense": "Nenguna seleicionada",
+       "licenses-edit": "Editar les opciones de llicencia",
        "license-nopreview": "(Previsualización non disponible)",
        "upload_source_url": " (una URL válida y accesible públicamente)",
        "upload_source_file": " (un archivu del to ordenador)",
+       "listfiles-delete": "desaniciar",
        "listfiles-summary": "Esta páxina especial amuesa tolos ficheros xubíos.",
        "listfiles_search_for": "Buscar por nome d'archivu multimedia:",
        "imgfile": "archivu",
        "filedelete-maintenance": "El desaniciu y restauración de ficheros ta desactivao temporalmente mientres ta en mantenimientu.",
        "filedelete-maintenance-title": "Nun se pue desaniciar el ficheru",
        "mimesearch": "Busca MIME",
-       "mimesearch-summary": "Esta páxina activa'l filtráu d'archivos en función de la so triba MIME. Entrada: contenttype/subtype, p.ex. <code>image/jpeg</code>.",
+       "mimesearch-summary": "Esta páxina permite filtriar los ficheros pol so tipu MIME.\nEntrada: contenttype/subtype o contenttype/*, p.ex. <code>image/jpeg</code>.",
        "mimetype": "Triba MIME:",
        "download": "descargar",
        "unwatchedpages": "Páxines ensin vixilar",
        "wantedpages-badtitle": "Títulu inválidu nel conxuntu de resultaos: $1",
        "wantedfiles": "Archivos buscaos",
        "wantedfiletext-cat": "Los ficheros siguientes tan usándose, pero nun esisten. Ye posible qu'apaezan ficheros de repositorios esternos ensin qu'esistan. Cualesquier falsu positivu tará <del>tacháu</del>. Amás, les páxines qu'inxerten ficheros que nun esisten apaecen na llista de [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Los ficheros siguientes tán usándose, pero nun existen. Amás, hai una llista de páxines qu'incluyen ficheros que non existen en [[:$1]].",
        "wantedfiletext-nocat": "Los ficheros siguientes tan usándose, pero nun esisten. Ye posible qu'apaezan ficheros de repositorios esternos ensin qu'esistan. Cualesquier falsu positivu tará <del>tacháu</del>.",
+       "wantedfiletext-nocat-noforeign": "Los ficheros siguientes tán usándose, pero nun existen.",
        "wantedtemplates": "Plantíes más buscaes",
        "mostlinked": "Páxines más enllaciaes",
        "mostlinkedcategories": "Categoríes más enllaciaes",
-       "mostlinkedtemplates": "Plantíes más enllaciaes",
+       "mostlinkedtemplates": "Páxines más trescluíes",
        "mostcategories": "Páxines con más categoríes",
        "mostimages": "Archivos más enllaciaos",
        "mostinterwikis": "Páxines con más interwikis",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|alderique]])",
        "unknown_extension_tag": "Etiqueta d'estensión \"$1\" desconocida",
        "duplicate-defaultsort": "Avisu: La clave d'ordenación predeterminada \"$2\" anula la clave d'ordenación anterior \"$1\".",
+       "duplicate-displaytitle": "<strong>Avisu:</strong> El títulu a amosar \"$2\" anula el títulu anterior \"$1\".",
        "version": "Versión",
        "version-extensions": "Estensiones instalaes",
+       "version-skins": "Temes instalaos",
        "version-specialpages": "Páxines especiales",
        "version-parserhooks": "Hooks d'análisis sintáuticu",
        "version-variables": "Variables",
        "version-antispam": "Prevención del corréu puxarra",
-       "version-skins": "Apariencia",
        "version-other": "Otros",
        "version-mediahandlers": "Remanadores d'archivos multimedia",
        "version-hooks": "Hooks",
        "version-hook-name": "Nome del hook",
        "version-hook-subscribedby": "Suscritu por",
        "version-version": "(Versión $1)",
+       "version-no-ext-name": "[ensin nome]",
        "version-license": "Llicencia de MediaWiki",
        "version-ext-license": "Llicencia",
        "version-ext-colheader-name": "Estensión",
+       "version-skin-colheader-name": "Apariencia",
        "version-ext-colheader-version": "Versión",
        "version-ext-colheader-license": "Llicencia",
        "version-ext-colheader-description": "Descripción",
        "expand_templates_remove_nowiki": "Quitar les etiquetes <nowiki> nos resultaos",
        "expand_templates_generate_xml": "Amosar l'árbole d'análisis sintáuticu XML",
        "expand_templates_generate_rawhtml": "Ver el HTML en bruto",
-       "expand_templates_preview": "Vista previa"
+       "expand_templates_preview": "Vista previa",
+       "pagelanguage": "Selector de llingua de la páxina",
+       "pagelang-name": "Páxina",
+       "pagelang-language": "Llingua",
+       "pagelang-use-default": "Usar la llingua predeterminada",
+       "pagelang-select-lang": "Escoyer llingua",
+       "right-pagelang": "Cambiar la llingua de la páxina",
+       "action-pagelang": "cambiar la llingua de la páxina",
+       "log-name-pagelang": "Rexistru de cambios de llingua",
+       "log-description-pagelang": "Esti ye un rexistru de los cambios de llingua de les páxines.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|cambió}} la llingua de la páxina $3 del $4 al $5."
 }
index 6954042..1669b9d 100644 (file)
@@ -23,7 +23,8 @@
                        "Wertuose",
                        "לערי ריינהארט",
                        "아라",
-                       "Arystanbek"
+                       "Arystanbek",
+                       "Dağlı95"
                ]
        },
        "tog-underline": "Keçidlərin altını xətlə:",
        "talkpagelinktext": "Müzakirə",
        "specialpage": "Xüsusi səhifə",
        "personaltools": "Şəxsi alətlər",
-       "postcomment": "Yeni bölmə",
        "articlepage": "Məqaləni nəzərdən keçir",
        "talk": "Müzakirə",
        "views": "Görünüş",
        "showhideselectedversions": "Seçilən versiyaları göstər/gizlə",
        "editundo": "əvvəlki halına qaytar",
        "diff-multi-manyusers": "({{PLURAL:$2|Bir istifadəçi|$2 istifadəçi}} tərəfindən edilən {{PLURAL:$1|bir ara redaktə|$1 ara redaktə}} göstərilmir)",
+       "difference-missing-revision": "Səhifənin  {{PLURAL:$2|bu versiyasının|$2 versiyalarının}} müqayisəsi ($1) tapılmadı.\nBu xəta adətən, köhnəlmiş səhifələrin müqayisə versiyalarından keçid edildikdə baş verir.\nDaha ətraflı məlumat üçün [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} silmə qeydlərinə] baxın.",
        "searchresults": "Axtarış nəticələri",
        "searchresults-title": "''$1'' üçün axtarış nəticələri",
        "titlematches": "Səhifə adı eynidir",
        "recentchanges-label-minor": "Bu kiçik redaktədir",
        "recentchanges-label-bot": "Bu redaktə bot tərəfindən edilmişdir",
        "recentchanges-label-unpatrolled": "Bu redaktə hələ nəzərdən keçirilməmişdir",
+       "recentchanges-label-plusminus": "Səhifənin ölçüsü bayt miqdarı ilə təyin edilir",
        "recentchanges-legend-newpage": "$1 - yeni səhifə",
        "rcnotefrom": "Aşağıda <strong>$2</strong>-dən bu yana olan dəyişikliklər göstərilib (<strong>$1</strong>-dən çox olmayaraq).",
        "rclistfrom": "$3 $2 vaxtından başlayaraq yeni dəyişiklikləri göstər",
        "badfilename": "Faylın adı dəyişildi. Yeni adı: \"$1\".",
        "filetype-mime-mismatch": "\".$1\" fayl uzantısı faylın MIME tipinə ($2) uyğun gəlmir.",
        "filetype-badmime": "\"$1\" MIME tipindəki faylların yüklənməsinə icazə verilmir.",
+       "filetype-banned-type": "'''\".$1\"''' {{PLURAL:$4|icazə verilən fayl formatı deyil}}. İcazə verilən {{PLURAL:$3|fayl formatı|fayl formatı bunlardır:}} $2.",
        "filetype-missing": "Faylın heç bir uzantısı yoxdur (məsələn, \".jpg\").",
        "empty-file": "Göndərdiyiniz fayl boşdur.",
        "file-too-large": "Göndərdiyiniz fayl çox böyükdür.",
        "largefileserver": "Faylın ölçüsü yol verilən həddi aşır.",
        "emptyfile": "Yüklədiyiniz fayl boşdur. Bu faylın adında olan hərf səhvi ilə bağlı ola bilər. Xahiş olunur ki, doğurdan da bu faylı yükləmək istədiyinizi yoxlayasınız.",
        "fileexists": "Yükləmək istədiyiniz adda fayl mövcuddur.\nLütfən <strong>[[:$1]]</strong> keçidini yoxlayın və bu faylı yükləmək istədiyinizdən əmin olun.\n[[$1|thumb]]",
+       "fileexists-extension": "Bu adda başqa bir fayl mövcuddur: [[$2|thumb]]\n* Yüklənilən faylın adı: <strong>[[:$1]]</strong>\n* Mövcud faylın adı: <strong>[[:$2]]</strong>\nXahiş edirik, başqa ad seçin.",
        "uploadwarning": "Yükləmə xəbərdarlığı",
        "savefile": "Faylı qeyd et",
        "uploadedimage": "\"[[$1]]\" yükləndi",
        "upload-description": "Faylın izahı",
        "upload-options": "Yükləmə parametrləri",
        "watchthisupload": "Bu faylı izlə",
+       "filename-bad-prefix": "Yüklədiyiniz faylın adı, çox güman ki, rəqəmsal kameralar tərəfindən avtomatik olaraq əlavə edilən və heç bir açıqlaması olmayan '''\"$1\"''' ilə başlayır.\nXahiş edirik faylın adını daha düzgün seçin.",
        "filename-prefix-blacklist": " #<!-- Bu sətrə toxunmayın --> <pre>\n# Sintaksis aşağıdakı kimi görünür:\n#   * \"#\" simvolundan sətrin sonuna kimi yazılar şərhdir\n#   * Tipik fayl adları üçün olan prefiksdəki hər bir boş olmayan sətir rəqəmli kamera trəfindən avtomatik qeydə alınır\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # digər mobil telefonlar\nIMG # generic\nJD # Jenoptik\nMGP # Pentax\nPICT # misc.\n #</pre> <!-- Bu sətrə toxunmayın -->",
        "upload-success-subj": "Yükləmə tamamlandı",
        "upload-failure-subj": "Yükləmə problemi",
        "linkstoimage-redirect": "$1 (fayl istiqamətləndirilir) $2",
        "sharedupload": "Bu fayl $1-dandır və ola bilsin ki, başqa layihələrdə də istifadə edilir.",
        "sharedupload-desc-here": "Bu fayl $1dandır və başqa layihələrdə də istifadə edilə bilər.\nFaylın [$2 təsvir səhifəsindəki] məlumat aşağıda göstərilib.",
+       "filepage-nofile": "Bu adda fayl mövcud deyil.",
+       "filepage-nofile-link": "Bu adda fayl mövcud deyil, amma bu faylı siz [$1 yükləyə bilərsiz]",
        "uploadnewversion-linktext": "Bu faylın yeni versiyasını yüklə",
        "shared-repo-from": "$1-dən",
        "shared-repo": "ümumi fayl anbarı",
        "filedelete": "$1 adlı faylı sil",
        "filedelete-legend": "Faylı sil",
        "filedelete-intro": "'''[[Media:$1|$1]]''' faylını və onunla bağlı bütün tarixçəni silmək ərəfəsindəsiniz.",
+       "filedelete-intro-old": "'''[[Media:$1|$1]]''' faylının [$4 $3, $2] tarixli versiyasını silirsiz.",
        "filedelete-comment": "Səbəb:",
        "filedelete-submit": "Sil",
        "filedelete-success": "'''$1''' silinmişdir.",
        "filedelete-reason-otherlist": "Başqa səbəb",
        "filedelete-reason-dropdown": "*Əsas silmə səbəbi\n** Müəllif hüququ pozuntusu\n** Dublikat fayl\n** Keyfiyyətsiz şəkil\n** İstifadəsiz fayl\n** Qeyri-ensiklopedik şəxs\n** Lisenziyasız fayl\n** Azad şəkillə əvəz olundu\n** Müəllif istəyi",
        "filedelete-edit-reasonlist": "Silmə səbəblərini redaktə et",
+       "filedelete-maintenance": "Texniki işlər səbəbindən faylların silinməsi və bərpası müvəqqəti olaraq bağlanmışdır.",
+       "filedelete-maintenance-title": "Faylı silmək mümkün olmadı.",
        "mimesearch": "MIME axtar",
        "mimetype": "MIME tipi:",
        "download": "Yüklə",
        "filedeleteerror-short": "Fayl silinərkən xəta: $1",
        "filedeleteerror-long": "Fayl silinərkən üzə çıxan xətalar:\n\n$1",
        "filedelete-missing": "\"$1\" faylı mövcud olmadığından silinə bilinmir.",
+       "filedelete-old-unregistered": "Göstərilən faylın \"$1\" versiyası verilənlər bazasında mövcud deyil.",
        "filedelete-current-unregistered": "Göstərilən \"$1\" faylı verilənlər bazasında yoxdur.",
        "filedelete-archive-read-only": "\"$1\" kataloqunun arxivi veb-server yazıları üçün qapalıdır.",
        "previousdiff": "← Əvvəlki redaktə",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|səhifə|səhifələr}}",
        "file-info": "faylın ölçüsü: $1, MIME tipi: $2",
        "file-info-size": "$1 × $2 piksel, fayl həcmi: $3, MIME növü: $4",
+       "file-info-size-pages": "$1 × $2 piksel, faylın ölçüsü: $3, MIME-tipi: $4, $5 {{PLURAL:$5|səhifə|səhifələr}}",
        "file-nohires": "Daha dəqiq versiyası yoxdur.",
        "svg-long-desc": "SVG fayl, nominal olaraq $1 × $2 piksel, faylın ölçüsü: $3",
        "show-big-image": "Faylın əsli",
        "file-info-gif-frames": "$1 {{PLURAL:$1|frame|çərçivə}}",
        "file-info-png-looped": "ilmələnib",
        "file-info-png-frames": "$1 {{PLURAL:$1|frame|çərçivə}}",
+       "file-no-thumb-animation": "'''Qeyd. Texniki səbəblərdən bu fayl tipinin animasiyası mümkün deyil.'''",
+       "file-no-thumb-animation-gif": "'''Qeyd. Yüksək ayırdetmə dəqiqliyinə malik belə GIF-təsvirlərinin animasiyası texniki səbəblərdən mümkün deyil.'''",
        "newimages": "Yeni faylların siyahısı",
        "newimages-legend": "Filtrlər",
        "newimages-label": "Faylın (və ya onun bir hissəsinin) adı:",
        "duplicate-defaultsort": "<strong>Diqqət:</strong> Susmaya görə \"$2\" çeşidləmə açarı susmaya görə əvvəlki \"$1\" çeşidləmə açarını inkar edir.",
        "version": "Versiya",
        "version-extensions": "NIzamlanmış genişlənmələr",
+       "version-skins": "Üzlük",
        "version-specialpages": "Xüsusi səhifələr",
        "version-parserhooks": "Parser hooks",
        "version-variables": "Dəyişkənlər",
        "version-antispam": "Spam önləmə",
-       "version-skins": "Üzlük",
        "version-other": "Digər",
        "version-hooks": "Çəngəllər",
        "version-hook-name": "Çəngəlin adı",
        "fileduplicatesearch-legend": "Dublikatı axtar",
        "fileduplicatesearch-filename": "Fayl adı:",
        "fileduplicatesearch-submit": "Axtar",
+       "fileduplicatesearch-result-1": "\"$1\" faylı hər hansı eyni dublikata malik deyil.",
+       "fileduplicatesearch-result-n": "\"$1\" faylı  $2 {{PLURAL:$2|eyni duplikata|eyni duplikatlara}} malikdir.",
        "fileduplicatesearch-noresults": "\"$1\" adında fayl tapılmadı.",
        "specialpages": "Xüsusi səhifələr",
        "specialpages-group-maintenance": "Cari məruzələr",
index 4f28db5..4e2de7b 100644 (file)
@@ -24,7 +24,7 @@
        "tog-newpageshidepatrolled": "Яңы биттәр исемлегендә тикшерелгән үҙгәртеүҙәрҙе йәшер",
        "tog-extendwatchlist": "Барлыҡ үҙгәртеүҙәрҙе үҙ эсенә алған, киңәйтелгән күҙәтеү исемлеге",
        "tog-usenewrc": "Һуңғы төҙәтеүҙәр һәм күҙәтеү исемлегендәге үҙгәрештәрҙе төркөмдәргә бүлергә",
-       "tog-numberheadings": "Башисемдәрҙе автоматик рәүештә номерлаe",
+       "tog-numberheadings": "Башисемдәрҙе автоматик рәүештә номерланһын",
        "tog-showtoolbar": "Мөхәррирләгән ваҡытта өҫкө ҡоралдар панелен күрһәтергә (JavaScript кәрәк)",
        "tog-editondblclick": "Биттәрҙе ике сиртеү менән мөхәррирләргә",
        "tog-editsectiononrightclick": "Бүлектәрҙе исемдәренә төрткөнөң уң яғына сиртеп үҙгәртергә",
        "october-date": "Октябрь $1",
        "november-date": "Ноябрь $1",
        "december-date": "Сентябрь $1",
-       "pagecategories": "{{PLURAL:$1|1=Категория|Категория}}",
+       "pagecategories": "{{PLURAL:$1|1=Категория|Категориялар}}",
        "category_header": "«$1» категорияһындағы биттәр",
        "subcategories": "Эске категориялар",
        "category-media-header": "«$1» категорияһындағы файлдар",
        "category-empty": "\"Был категория әлегә буш.\"",
-       "hidden-categories": "{{PLURAL:$1|1=Йәшерен категория|Йәшерен категориялар}}",
+       "hidden-categories": "{{PLURAL:$1|Йәшерен категория|Йәшерен категориялар}}",
        "hidden-category-category": "Йәшерен категориялар",
-       "category-subcat-count": "{{PLURAL:$2|1=Был категорияла тик киләһе эске категория ғына бар.|$2 эске категорияның $1 эске категорияһы күрһәтелгән.}}",
-       "category-subcat-count-limited": "Был категорияла {{PLURAL:$1|$1 эске категория}} бар.",
+       "category-subcat-count": "{{PLURAL:$2|Был категорияла тик киләһе эске категория ғына бар.|Барлығы $2 категориянан, был категорияла киләһе  {{PLURAL:$1|эске категория|$1 эске категория}} күрһәтелә.}}",
+       "category-subcat-count-limited": "Был категорияға киләһе {{PLURAL:$1|эске категория|$1 эске категория}} ингән.",
        "category-article-count": "{{PLURAL:$2|1=Был категорияла бер генә бит бар.|Категориялағы $2 биттең $1 бите күрһәтелгән.}}",
        "category-article-count-limited": "Был категорияла {{PLURAL:$1|$1 бит}} бар.",
        "category-file-count": "{{PLURAL:$2|Был категорияла бер генә файл бар.|Категориялағы $2 файлдың {{PLURAL:$1|$1 файлы күрһәтелгән}}.}}",
-       "category-file-count-limited": "Ð\91Ñ\83 категорияла {{PLURAL:$1|$1 файл}} бар.",
+       "category-file-count-limited": "Ð\91Ñ\8bл категорияла {{PLURAL:$1|$1 файл}} бар.",
        "listingcontinuesabbrev": "(дауамы)",
        "index-category": "Индексланған биттәр",
        "noindex-category": "Индексланмаған биттәр",
        "talkpagelinktext": "әңг.",
        "specialpage": "Ярҙамсы бит",
        "personaltools": "Шәхси ҡоралдар",
-       "postcomment": "Яңы бүлек",
        "articlepage": "Мәҡәләне ҡарап сығырға",
        "talk": "Әңгәмә",
        "views": "Ҡарауҙар",
        "invalidtitle-knownnamespace": "\"$2\" исем арауығы һәм \"$3\"  тексты исем өсөн ярамай",
        "invalidtitle-unknownnamespace": "\"$2\" тексты һәм \"$1\" арауыҡ өсөн билдәһеҙ номерлы исем ярамай",
        "exception-nologin": "Танылмағанһығыҙ",
-       "exception-nologin-text": "Ð\91Ñ\8bл Ð±Ð¸Ñ\82Ñ\82е Ò¡Ð°Ñ\80аÑ\80 Ð¹Ó\99ки Ò»Ð¾Ñ\80аÑ\82Ñ\8bлÒ\93ан Ò\93Ó\99мÓ\99лде Ð±Ð°Ñ\88ҡаÑ\80Ñ\8bÑ\80 Ó©Ñ\81өн Ñ\81иÑ\81Ñ\82емала Ñ\82анÑ\8bлÑ\8bÑ\83 кәрәк.",
+       "exception-nologin-text": "Ð\91Ñ\8bл Ð±Ð¸Ñ\82Ñ\82е Ò¡Ð°Ñ\80аÑ\83 Ð¹Ó\99ки Ò»Ð¾Ñ\80аÑ\82Ñ\8bлÒ\93ан Ò\93Ó\99мÓ\99лде Ð±Ð°Ñ\88ҡаÑ\80Ñ\8bÑ\83 Ó©Ñ\81өн Ñ\81иÑ\81Ñ\82емала [[Special:Userlogin|Ñ\82анÑ\8bлÑ\8bÑ\80Ò\93а]] кәрәк.",
        "virus-badscanner": "Көйләү хатаһы: Билдәһеҙ вирустар сканеры: ''$1''",
        "virus-scanfailed": "сканлау хатаһы ($1 коды)",
        "virus-unknownscanner": "беленмәгән антивирус:",
        "externaldberror": "Тышҡы мәғлүмәт базаһы менән танылғанда хата барлыҡҡа килде йәки тышҡы үҙ көйләүҙәрегеҙҙе үҙгәртер өсөн хоҡуҡтарығыҙ етәрле түгел.",
        "login": "Танылыу",
        "nav-login-createaccount": "Танылыу йәки теркәлеү",
-       "loginprompt": "{{SITENAME}} проектына кереү өсөн «cookies» рөхсәт ителгән булырға тейеш.",
        "userlogin": "Танылыу йәки теркәлеү",
        "userloginnocreate": "Танылыу",
        "logout": "Тамамлау",
        "nologinlink": "Иҫәп яҙыуын булдырырға",
        "createaccount": "Яңы ҡатнашыусыны теркәү",
        "gotaccount": "Әгәр Һеҙ теркәлеү үткән булһағыҙ? '''$1'''.",
-       "gotaccountlink": "Үҙегеҙ менән таныштырығыҙ",
+       "gotaccountlink": "Танылыу",
        "userlogin-resetlink": "Танылыу мәғлүмәттәрен оноттоғоҙмо?",
        "userlogin-resetpassword-link": "Серһүҙҙе ҡабул итмәү",
        "userlogin-loggedin": " Һеҙ {{GENDER:$1|$1}} булараҡ индегеҙ инде. Башҡа файҙаланыусы булып инер өсөн аҫтағы ҡалыпты ҡулланығыҙ.",
        "password-login-forbidden": "Был ҡатнашыусы исемен һәм серһүҙҙе ҡулланыу тыйылған",
        "mailmypassword": "Яңы серһүҙ ебәрергә",
        "passwordremindertitle": "{{SITENAME}} өсөн яңы ваҡытлыса серһүҙ",
-       "passwordremindertext": "Кемдер (бәлки, һеҙ, IP-адресы: $1) {{SITENAME}} ($4) өсөн яңы серһүҙ һоратты. $2 ҡатнашыусыһы өсөн ваҡытлыса яңы серһүҙ яһалды: $3. Әгәр был һеҙ булһағыҙ, системага керегеҙ һәм серһүҙ алмаштырығыҙ. Яңы серһүҙ $5 {{PLURAL:$5|көн}} ғәмәлдә буласаҡ.\n\nӘгәр һеҙ серһүҙҙе алмаштырыуҙы һоратмаған йәки онотоп кире иҫләгән булһағыҙ һәм үҙгәртергә теләмәһәгеҙ, был хәбәргә иғтибар итмәгеҙ һәм элекке серһүҙегеҙҙе ҡулланыуығыҙҙы дауам итегеҙ.",
+       "passwordremindertext": "Кемдер (бәлки, һеҙ, IP-адресы: $1) {{SITENAME}} ($4) өсөн яңы серһүҙ һоратты. $2 ҡатнашыусыһы өсөн ваҡытлыса яңы серһүҙ яһалды: $3. Әгәр был һеҙ булһағыҙ, системага керегеҙ һәм серһүҙ алмаштырығыҙ. Яңы серһүҙ $5 {{PLURAL:$5|көн}} ғәмәлдә буласаҡ.\n\nӘгәр һеҙ серһүҙҙе алмаштырыуҙы һоратмаған йәки онотоп кире иҫләгән булһағыҙ һәм үҙгәртергә теләмәһәгеҙ, был хәбәргә иғтибар итмәгеҙ һәм элекке серһүҙҙе ҡулланыуҙы дауам итегеҙ.",
        "noemail": "$1 исемле ҡулланыусы өсөн электрон почта адресы белдерелмәгән.",
        "noemailcreate": "Дөрөҫ электрон почта адресы күрһәтеү кәрәк",
        "passwordsent": "Яңы серһүҙ $1 исемле ҡатнашыусының электрон почта адресына ебәрелде.\n\nЗинһар, серһүҙҙе алғас, системаға яңынан керегеҙ.",
        "loginlanguagelabel": "Тел: $1",
        "suspicious-userlogout": "Һеҙҙең сеансты тамамлау тураһында һорауығыҙ кире ҡағылды, сөнки ул төҙөк булмаған браузер йәки кэшлаусы прокси тарафынан ебәрелгән һорауға оҡшаған.",
        "createacct-another-realname-tip": "Ысын исемегеҙ (мотлаҡ түгел).\nУны яҙып ҡуйһағыҙ, ул биткә кем төҙәтеү индергәнен күрһәтеү өсөн ҡулланыласаҡ.",
+       "pt-login": "Танылыу",
+       "pt-login-button": "Танылыу",
+       "pt-userlogout": "Тамамлау",
        "php-mail-error-unknown": "PHP-ның mail() функцияһында билдәһеҙ хата",
        "user-mail-no-addy": "Электрон почта адресы булмайынса электрон хәбәр ебәреп ҡараны",
        "user-mail-no-body": "Буш йә мәғәнәһеҙ йөкмәткеле ҡыҫҡа электрон хат ебәрергә тырышҡан.",
        "resetpass-wrong-oldpass": "Хаталы ваҡытлыса йәки ағымдағы серһүҙ.\nҺеҙ, бәлки, серһүҙегеҙҙе алмаштырғанһығыҙ йәки яңы серһүҙ һоратҡанһығыҙ.",
        "resetpass-temp-password": "Ваҡытлыса серһүҙ",
        "resetpass-abort-generic": "Серһүҙҙе үҙгәртеү киңәйеү тарафынан өҙөлдө.",
+       "resetpass-expired": "Һеҙҙең серһүҙҙең ғәмәл ваҡыты үткән. Зинһар, системала танылыу өсөн яңы серҙһүҙ ҡуйығыҙ.",
        "passwordreset": "Серһүҙҙе ташлатыу",
        "passwordreset-text-one": "Серһүҙегеҙҙе ташлар өсөн ош ҡалыпты тултырығыҙ.",
        "passwordreset-text-many": "{{PLURAL:$1|Серһүҙҙе ташлар өсөн яландарҙың береһен тултырығыҙ.}}",
        "accmailtext": "[[User talk:$1|$1]] өсөн осраҡлы яһалған серһүҙ $2 адресына ебәрелде.\n\nТанылғандан һуң был иҫәп яҙмаһы өсөн серһүҙҙе ''[[Special:ChangePassword|серһүҙҙе үҙгәртеү өсөн махсус биттә үҙгәртә алаһығыҙ]]''.",
        "newarticle": "(Яңы)",
        "newarticletext": "Һеҙ һылтанма буйынса әлегә яһалмаған биткә күстегеҙ.\nЯңы бит яһар өсөн аҫтағы тәҙрәгә текст керетегеҙ (тулыраҡ мәғлүмәт өсөн [$1 ярҙам битен] ҡарағыҙ).\nӘгәр был биткә яңылыш килеп эләккән булһағыҙ, браузерығыҙҙың '''артҡа''' төймәһенә баҫығыҙ.",
-       "anontalkpagetext": "----''Был фекер алышыу бите, иҫәп яҙыуы булдырмаған йәки уны ҡулланмаған аноним ҡатнашыусының бите.\nШуның өсөн ҡулланыусыны таныу өсөн IP-адресы ҡулланыла.\nӘгәр һеҙ аноним ҡулланыусы булһағыҙ һәм һеҙгә ебәрелмәгән хәбәрҙәр алдым тиһәгеҙ (бер IP-адрес күп ҡулланыусы өсөн булырға мөмкин) һәм башҡа бындай аңлашылмаусанлыҡтар килеп сыҡмаһын өсөн, зинар, [[Special:UserLogin|системаға керегеҙ]] йәки [[Special:UserLogin/signup|теркәлегеҙ]].''",
+       "anontalkpagetext": "----\n<em>Был фекер алышыу бите, иҫәп яҙыуы булдырмаған йәки уны ҡулланмаған аноним ҡатнашыусының бите.</em>\nШуның өсөн ҡулланыусыны таныу өсөн IP-адресы ҡулланыла.\nӘгәр һеҙ аноним ҡулланыусы булһағыҙ һәм һеҙгә ебәрелмәгән хәбәрҙәр алдым тиһәгеҙ (бер IP-адрес күп ҡулланыусы өсөн булырға мөмкин) һәм башҡа бындай аңлашылмаусанлыҡтар килеп сыҡмаһын өсөн, зинар, [[Special:UserLogin|системаға керегеҙ]] йәки [[Special:UserLogin/signup|теркәлегеҙ]].",
        "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}}}} юйыу яҙмалары].",
        "revdelete-hide-text": "Биттең был версияһының текстын йәшерергә",
        "revdelete-hide-image": "Файл эстәлеген йәшерергә",
        "revdelete-hide-name": "Ғәмәлде һәм маҡсатын йәшерергә",
-       "revdelete-hide-comment": "Үҙгәртеү тасуирламаларын йәшерергә",
-       "revdelete-hide-user": "Мөхәррирләүсенең исемен/IP-адресын йәшерергә",
+       "revdelete-hide-comment": "Үҙгәртеүҙәр тасуирламаһы",
+       "revdelete-hide-user": "Мөхәррирләүсенең исеме/IP-адресы",
        "revdelete-hide-restricted": "Мәғлүмәттәрҙе хакимдәрҙән дә йәшерергә",
        "revdelete-radio-same": "(үҙгәртмәҫкә)",
-       "revdelete-radio-set": "Эйе",
-       "revdelete-radio-unset": "Юҡ",
+       "revdelete-radio-set": "Ð\99Ó\99Ñ\88еÑ\80ен",
+       "revdelete-radio-unset": "Ð\9aÒ¯Ñ\80енгÓ\99н",
        "revdelete-suppress": "Мәғлүмәттәрҙе шулай уҡ хакимдәрҙән дә йәшерергә",
        "revdelete-unsuppress": "Тергеҙелгән версияларҙан бар сикләүҙәрҙе алырға",
        "revdelete-log": "Сәбәп:",
-       "revdelete-submit": "Һайланған {{PLURAL:$1|1=версия|версиялар}} өсөн ҡулланырға",
+       "revdelete-submit": "Һайланған {{PLURAL:$1|версия|версиялар}} өсөн ҡулланырға",
        "revdelete-success": "'''Версия күренеүсәнлеге уңышлы үҙгәртелде.'''",
        "revdelete-failure": "'''Версия күренеүсәнлеген үҙгәртеп булмай:'''\n$1",
        "logdelete-success": "'''Яҙма күренеүсәнлеге үҙгәртелде.'''",
        "duplicate-defaultsort": "'''Иҫкәртеү:''' \"$2\" ғәҙәттәге тәпртипкә килтереү асҡысы элекке \"$1\" ғәҙәттәге тәртипкә килтереү асҡысын үҙгәртә.",
        "version": "MediaWiki өлгөһө",
        "version-extensions": "Ҡуйылған киңәйтеүҙәр",
+       "version-skins": "Күренештәр",
        "version-specialpages": "Махсус биттәр",
        "version-parserhooks": "Уҡыу ҡоралдары",
        "version-variables": "Үҙгәреүсән дәүмәлдәр",
        "version-antispam": "Спамға ҡаршы ҡорал",
-       "version-skins": "Күренештәр",
        "version-other": "Башҡалар",
        "version-mediahandlers": "Медиа эшкәртеүсе ҡоралдар",
        "version-hooks": "Эләктереп алыусылар",
index 78390b6..f8947bb 100644 (file)
@@ -24,7 +24,7 @@
        "tog-extendwatchlist": "Daweiterde Beówochtungslisten",
        "tog-usenewrc": "Endarunga vo \"Lezde Endarunga\" und vo \"Mei Beobochtd\" noch Seitn gruppian",
        "tog-numberheadings": "Ywerschriften autómaatisch nummerrirn",
-       "tog-showtoolbar": "Beorweiten-Werkzeigleisten åzoang (JavaScript werd braucht)",
+       "tog-showtoolbar": "Zoag de Edit Toolbar (JavaScript nedig)",
        "tog-editondblclick": "Seiten mid am Dóppedrucker beorweiden (JavaScript werd braucht)",
        "tog-editsectiononrightclick": "Oahzelne Obschnitt mid am Rechtsdrucker beorweiten (JavaScript werd braucht)",
        "tog-watchcreations": "Voh mir söwer eihgstöde Seiten autómaatisch beówochten",
        "talkpagelinktext": "Dischkrian",
        "specialpage": "Speziaalseiten",
        "personaltools": "Mei Weakzeig",
-       "postcomment": "Neicher Obschnit",
        "articlepage": "Seiteninhoid åzoang",
        "talk": "Dischkrian",
        "views": "Osichtn",
        "cannotdelete-title": "Seiten „$1“ kå néd gléschd wern",
        "badtitle": "koa gitiga Titl",
        "badtitletext": "Da Titl voh da ogfordatn Seitn is ned gitig, laar oda a ungitiga Sprochlink vonam andan Wiki.",
-       "perfcached": "Dé fóigernden Daaten staummern aus'm Cache und san méglicherweis nimmer aktuö. Maximoi {{PLURAL:$1|oah Ergebnis is|$1 Ergebniss san}} im Cache vafiagbor.",
-       "perfcachedts": "Dé Daaten staummern aus 'm Cache. Da Zeidbunkt voh da létzden Aktualisiarung: $1. Maximoi {{PLURAL:$4|oah Ergebnis is|$4 Ergebniss san}} im Cache vafiagbor.",
+       "perfcached": "De foigandn Datn stamma ausm Cache und san meglichaweis neama aktuäi. Maximoi {{PLURAL:$1|oa Eagebnis is|$1 Ergebniss san}} im Cache vafigboar.",
+       "perfcachedts": "De Datn stamma ausm Cache. Da Zeidpunkt vo da lezzdn Aktualisiarung: $2, $3 Uah. Maximoi {{PLURAL:$4|oa Ergebnis is|$4 Ergebniss san}} im Cache vafigboar.",
        "querypage-no-updates": "'''Dé Aktualisiarungsfunkzión voh derer Seiten is derzeid deaktivird. Dé Daaten wern bis auf Weiders néd daneiert.'''",
        "viewsource": "Quejtext ozoagn",
        "viewsource-title": "Quöntext voh da Seiten $1 auhschauh",
        "yourpassword": "Passwort:",
        "yourpasswordagain": "Es Passwort no amoi eigebm",
        "remembermypassword": "Mitm Brausa dauahoft ogmejd bleibm (maximoi $1 {{PLURAL:$1|Dog|Dog}})",
-       "yourdomainname": "Eanerne Domain:",
+       "yourdomainname": "Dei Domain:",
        "externaldberror": "Entweder es ligt a Feeler bai da externen Authentifiziarung vur oder du derfst dai externs Benytzerkonto ned aktualisirn.",
        "login": "Eilogga",
        "nav-login-createaccount": "Eilogga / Konto olegn",
-       "loginprompt": "Zua Omejdung miassen Cookies aktiviat sei.",
        "userlogin": "Eilogga / Konto olegn",
        "userloginnocreate": "Åmöden",
        "logout": "Obmöden",
        "wrongpassword": "Des Posswort is foisch! Bitschee prowirs nuamoi.",
        "wrongpasswordempty": "Es is koa Posswort ned aigeem worn. Bittschee prowirs nuamoi.",
        "mailmypassword": "Neichs Passwort zuaschicka",
-       "passwordremindertitle": "Naichs Posswort fyra {{SITENAME}}-Benytzerkonto",
+       "passwordremindertitle": "A neichs Kennwoat fiar a {{SITENAME}}-Nutzakonto",
        "acct_creation_throttle_hit": "Du host scho $1 {{PLURAL:$1|Benytzerkonto|Benytzerkonten}} und kååst jetzad koane mer åleeng.",
        "emailconfirmlink": "E-Póst-Adressen bstäting (Authentifiziarung)",
        "accountcreated": "Benytzerkonto is erstöid worn",
        "resetpass-submit-loggedin": "Posswort ändern",
        "resetpass-submit-cancel": "Obbrechen",
        "passwordreset": "Passwoat zrucksetzn",
-       "passwordreset-username": "Benutzernåm:",
+       "passwordreset-username": "Nutzanama:",
        "bold_sample": "Fetta Text",
        "bold_tip": "Fetta Text",
        "italic_sample": "Kursiva Text",
        "linkstoimage-more": "Es {{PLURAL:$1|valinkt|valinkn}} mea wia {{PLURAL:$1|oa Seitn |$1 Seitn}} auf de Datei.\nDe foignde Listn zaagt netta {{PLURAL:$1|in easten Link|de easten $1 Links}} auf de Datei.\nA [[Special:WhatLinksHere/$2|voiständige Listn]] gibt's aa.",
        "nolinkstoimage": "De Datei wead vo koana Seitn gnutzt.",
        "morelinkstoimage": "[[Special:WhatLinksHere/$1|Weidare Links]] fia de Datei.",
+       "linkstoimage-redirect": "$1 (Dateiweidaloatung) $2",
        "duplicatesoffile": "{{PLURAL:$1|D'foignde Datei is a Duplikat|De foigndn $1 Datein han Duplikate}} vu dea Datei ([[Special:FileDuplicateSearch/$2|weidare Deteus]]):",
        "sharedupload": "De Datei stãmmt aus $1 und deaf bei ãndare Projekte vawendt wean.",
        "sharedupload-desc-there": "De Datei stãmmt aus $1 und deaf bei ãndera Projekte vawendt wean. Schau auf'd [$2 Dateibeschreibungsseitn] fia weidare Infoamazionen.",
        "filedelete-intro": "Du léschst dé Daatei '''„[[Media:$1|$1]]“'''.",
        "mimesearch-summary": "Auf dieser Spezialseite können die Dateien nach dem MIME-Typ gefiltert werden. Die Eingabe muss immer den Medien- und Subtyp beinhalten: <code>image/jpeg</code> (siehe Bildbeschreibungsseite).",
        "download": "Owerlooden",
+       "listredirects": "Weidaloatunga",
        "unusedtemplates": "Net benutzte Vorlagen",
        "unusedtemplateswlh": "Aundre Links",
        "randompage": "Zuafoisseitn",
+       "randomredirect": "Zuafällige Weidaloatung",
        "statistics": "Statistik",
        "statistics-articles": "Inhoidsseiten",
        "statistics-pages": "Seiten",
        "statistics-edits-average": "Beorweitungen pró Seiten im Durchschnit",
        "statistics-views-total": "Seitenaufruaff gsåmmt",
        "statistics-mostpopular": "Dé am moastbsuachten Seiten",
-       "doubleredirects": "Doppede Weiderloatungen",
+       "doubleredirects": "Doppede Weidaloatunga",
+       "doubleredirectstext": "Af dea Seitn stengan Weidaloatunga, de wo af Weidaloatunga zoang.\n\nA <del>duachgstrichane</del> Eidrog is scho repariad worn.",
+       "double-redirect-fixed-maintenance": "Doppede Weidaloatunga vo [[$1]] af [[$2]] mid oana Aktion reparian.",
+       "brokenredirectstext": "Af dera Spezialseitn stengan Weidaloatunga af Artiken, de wo s ned gibt.",
        "brokenredirects-edit": "werkeln",
        "brokenredirects-delete": "léschen",
        "withoutinterwiki": "Seitn ohne Sprochlinks",
        "wantedcategories": "Bnutzde, ower néd åglégte Kategorien",
        "wantedpages": "Gwynschde Seiten",
        "wantedpages-badtitle": "Ungütiger Titel im Ergeewnis: $1",
-       "wantedfiles": "Fööhernde Daatein",
-       "wantedtemplates": "Fööhernde Vurlong",
+       "wantedfiles": "Datein, wo ma braucha",
+       "wantedtemplates": "Voalong, wo ma braucha",
        "mostlinked": "Haiffig valinkte Seiten",
        "mostlinkedcategories": "Haiffig brauchde Kategorien",
        "mostlinkedtemplates": "Haiffig brauchde Vurlong",
        "allpagesprefix": "Seiten zoang mid Präfix:",
        "allpagesbadtitle": "Da eihgeewerne Seitennaum is néd gütig: Er hod éntwéder a vurauhgstöds Sprooch-, a Interwiki-Kyrzel óder enthoitt oah óder mererne Zeichen, dé in d' Seitennaumen néd vawendt wern derffm.",
        "allpages-bad-ns": "Dén Naumensraum „$1“ gibts in {{SITENAME}} néd.",
+       "allpages-hide-redirects": "Weidaloatunga ausblendn",
        "categories": "Kategorina",
        "special-categories-sort-count": "Sortiarung noch da Auhzoi",
        "special-categories-sort-abc": "Sortiarung noch 'm Alfabet",
        "listgrouprights-addgroup-self-all": "Kauh olle Gruppm zum oagern Kóntó dazuadoah",
        "mailnologin": "Du bist néd auhgmödt",
        "emailuser": "Mail an den Nutza",
-       "emailpage": "E-Mail aun Benutzer",
-       "noemailtitle": "Koah E-Mail-Adress",
+       "emailpage": "E-Mail an Nutza",
+       "noemailtitle": "Koa Mail-Adress",
        "emailfrom": "Voh:",
        "emailto": "Aun:",
        "emailsubject": "Bedreff:",
        "ipbreason-dropdown": "* Oigmoahne Sperrgrynd\n** Eihfyng voh voische Informaziónen\n** Laarn voh Seiten\n** Massenweiss Eihfyng voh externe Links\n** Eihstön voh unsinnige Inhoite auf Seiten\n** néd åbrochts Vahoiden\n** Missbrauch mid mererne Benutzerkontós\n** néd geigneter Benutzernåm",
        "ipb-hardblock": "Auhgmödte Benutzer dodrauh hindern, daas Beorweitungen unter derer IP-Adress vurgnummer wern",
        "ipbcreateaccount": "D' Erstöung voh Benutzerkóntós vahindern",
-       "ipbemailban": "E-Mail-Vasånd sperrn",
+       "ipbemailban": "E-Mail-Vasand spean",
        "ipbenableautoblock": "Sperr dé aktuö voh dém Benutzer gnutzde IP-Adress sówia autómaatisch olle fóiganden, voh dénen aus er Beorweitungen óder 's Auhléng voh Benutzerkóntós vasuacht.",
        "ipbsubmit": "IP-Adress/Benutzer sperrn",
        "ipbother": "Åndre Dauer (auf englisch):",
        "ipusubmit": "Freigem",
        "unblocked": "[[User:$1|$1]] is freigem worn",
        "unblocked-id": "Sperr-ID $1 is fraigeem worn",
+       "blocklist": "Gspeade Nutza",
        "ipblocklist": "Gsperrte Nutza",
        "ipblocklist-legend": "Suach noch am gsperrden Benytzer",
        "createaccountblock": "'s erstön voh Benutzerkóntós is gsperrd",
        "unblocklink": "Freigebm",
        "change-blocklink": "Sperr endan",
        "contribslink": "Beidreg",
-       "emaillink": "E-Póst schicker",
+       "emaillink": "E-Mail vaschicka",
        "autoblocker": "Autómaatische Sperr, wei du a gmoahsaume IP-Adress mim [[User:$1|$1]] bnutzd. Grund voh da Benutzersperrn: „$2“.",
        "blocklogpage": "Sperrlogbuach",
        "blocklog-showlog": "{{GENDER:$1|Der Benutzer|Dé Benutzerrin|Der Benutzer}} do is schoh friarer gsperrd worn. Es fóigt a Eihtrog aus'm Benutzersperrlogbiaché:",
        "block-log-flags-anononly": "netter Anónyme",
        "block-log-flags-nocreate": "Es Olegn vo Nutzakontn is gsperrt",
        "block-log-flags-noautoblock": "Autóblóck deaktivierd",
-       "block-log-flags-noemail": "E-Post vaschicka gspead",
+       "block-log-flags-noemail": "Mail vaschicka gspead",
        "unlockdb": "Daatenbaunk freigeem",
        "unlockconfirm": "Ja, i mecht de Datenbank freigem.",
        "unlockbtn": "Datenbank freigem",
        "movepagebtn": "Seitn vaschiam",
        "pagemovedsub": "s'Vaschiam håd highaud",
        "movepage-moved": "'''D'Seitn „$1“ is nåch „$2“ vaschom woan.'''",
-       "movepage-moved-redirect": "Es is a Weiderloatung erstöd worn.",
+       "movepage-moved-redirect": "A Weidaloatung eigricht worn.",
+       "movepage-moved-noredirect": "De Eirichtung vo oana Weidaloatung is vahindat worn.",
        "articleexists": "Unter dém Naum existierd schoh a Seiten. Bittscheh nimm an aundern Naumen her.",
        "movetalk": "Waunns geet, d' Dischkrierseiten aa midvaschiam",
        "movelogpage": "Vaschiabungs-Logbuach",
        "lastmodifiedatby": "Dé Seiten is zletzt am $1 um $2 voh $3 gänderd worn.",
        "othercontribs": "Basiard auf da Orweid voh $1",
        "creditspage": "Seiteninformaziónen",
+       "pageinfo-redirects-name": "Ozoi vo de Weidaloatunga zua dea Seitn",
+       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|Weidaloatung|Weidaloatunga}}; $3 {{PLURAL:$3|Untaseitn|Untaseitn}})",
+       "pageinfo-redirectsto": "Weidaloatunga af",
        "markedaspatrollederrortext": "Du muasst a Seitenänderrung auswön",
        "deletedrevision": "Oide Version $1 glöscht.",
        "filedelete-missing": "De Datei „$1“ ko net glöscht wern, weils es net gibt.",
        "htmlform-submit": "Speichern",
        "htmlform-reset": "Änderrungen ryckgängég mochen",
        "htmlform-selectorother-other": "Åndre",
+       "logentry-move-move_redir": "$1 hod de Seitn $3 af $4 {{GENDER:$2|verschom}} und hod dabei a Weidaloatung ibaschriem",
+       "logentry-move-move_redir-noredirect": "$1 hod de Seitn $3 af $4 {{GENDER:$2|verschom}} und dabei a Weidaloatung ibaschriem, ohne a neiche ozlegn",
        "searchsuggest-search": "Suach",
        "searchsuggest-containing": "Voitextsuach noch ..."
 }
index dec808c..8f0e7d1 100644 (file)
@@ -8,7 +8,8 @@
                        "Reedy",
                        "ZxxZxxZ",
                        "아라",
-                       "RigiMahnoor"
+                       "RigiMahnoor",
+                       "Oldstoneage"
                ]
        },
        "tog-underline": ":لینکانآ خط کش",
        "talkpagelinktext": "گپ کن",
        "specialpage": "حاصین صفحه",
        "personaltools": "شخصی وسایل",
-       "postcomment": "نوکین بخش",
        "articlepage": "محتوا صفحه به گند",
        "talk": "بحث",
        "views": "چارگان",
        "externaldberror": "یک حطا دیتابیس تصدیق هویت دراییگی هست یا شما را اجازت نیست وتی حساب درایی په روچ کنیت.",
        "login": "ورود",
        "nav-login-createaccount": "ورود/شرکتن حساب",
-       "loginprompt": "شما بایدن په وارد بیگ ته {{SITENAME}} کوکی فعال کنیت",
        "userlogin": "ورود/شرکتن حساب",
        "userloginnocreate": "لاگین",
        "logout": "در بیگ",
        "hebrew-calendar-m12-gen": "الول",
        "unknown_extension_tag": "ناشناس برجسب الحاق  \"$1\"",
        "duplicate-defaultsort": "هژاری: ترتیب پیش فرض «$2» ترتیب پیش فرض پیشگین «$1» را باطل کنت.",
-       "version": "نسخه",
+       "version": "نسخة",
        "version-extensions": "نصب بوتگیت الحاق آن",
        "version-specialpages": "حاصین صفحات",
        "version-parserhooks": "تجزیه کنوک گیر کت",
index 7edefda..5030c0d 100644 (file)
@@ -12,9 +12,9 @@
                ]
        },
        "tog-underline": "Linyahan an kilyawan:",
-       "tog-hideminor": "Tagóon an mga saradít na paghirá sa nakakaági pa sanáng pagbabàgo",
+       "tog-hideminor": "Tagoon an saradít na paghira sa nakakaagi pa sanang pagbabàgo",
        "tog-hidepatrolled": "Tagóa an patrolyadong mga paghirá sa nakakaági pa sanáng pagbabàgo",
-       "tog-newpageshidepatrolled": "Tagóa an patrolyadong mga pahina gikan sa listahan kan bàgong pahina",
+       "tog-newpageshidepatrolled": "Tagoon an patrolyadong mga pahina gikan sa listahan kan bàgong pahina",
        "tog-extendwatchlist": "Palakbanga an bantay-listahan (watchlist) na maipahiling an gabos na pinagbago, bako sana an pinakahurihang binago",
        "tog-usenewrc": "Pangrupong mga kaliwatan sa kada pahina kan mga dae pa sana nahaloy na mga kaliwatan asin bantay-listahan",
        "tog-numberheadings": "Tolos-bilang na mga pamayohán",
@@ -27,7 +27,7 @@
        "tog-watchdeletion": "Idagdag an mga pahina asin mga sagunson na ako an nagpura sa sakong bantay-listahan",
        "tog-minordefault": "Markahán gabos na saradit na pagliwat sa paaging panugmad",
        "tog-previewontop": "Ipahilíng an patànaw bàgo an kahon nin paghirá",
-       "tog-previewonfirst": "Ipahilíng an patànaw sa enot na paghirá",
+       "tog-previewonfirst": "Ipahiling an patànaw sa inot na paghira",
        "tog-enotifwatchlistpages": "E-suratan mo ako kunsoarin an sarong pahina o sagunson na yaon sa sakong bantay-listahan pinagliwat",
        "tog-enotifusertalkpages": "E-koreohan ako pag pigribáyan an pahina kan sakóng olay",
        "tog-enotifminoredits": "E-suratan man ako para sa saraditon na mga pagliwat kan mga pahina asin mga sagunson",
@@ -49,8 +49,8 @@
        "tog-norollbackdiff": "Omidohon an diff matapos himoon an pagbalikot",
        "tog-useeditwarning": "Patanidan ako kunsoarin na ako nagbaya sa pahinang pigliliwat na dae naitatagama an mga kaliwatan",
        "tog-prefershttps": "Pirmeng gumamit nin sarong seguradong koneksyon kunsoarin na ika nakalaog na",
-       "underline-always": "Pirmi",
-       "underline-never": "Nungka",
+       "underline-always": "Parati",
+       "underline-never": "Dai lamang",
        "underline-default": "Kublit o kilyaw na panugmad",
        "editfont-style": "Baguhon an estilo nin kalwig sa sinasakupan",
        "editfont-default": "Kilyawang tugmad",
        "june-date": "Hunyo $1",
        "july-date": "Hulyo $1",
        "august-date": "Agosto $1",
-       "september-date": "Septiyembre $1",
-       "october-date": "Oktubre $1",
+       "september-date": "Setyembre $1",
+       "october-date": "Oktobre $1",
        "november-date": "Nobyembre $1",
-       "december-date": "Disyembre $1",
+       "december-date": "Desyembre $1",
        "pagecategories": "{{PLURAL:$1|Kategorya|Mga kategorya}}",
        "category_header": "Mga pahina sa kategoryang \"$1\"",
        "subcategories": "Mga sub-kategorya",
        "category-media-header": "Media sa kategoryang \"$1\"",
-       "category-empty": "''Ining kategorya sa presente mayong laog na mga pahina o media.\"",
+       "category-empty": "''Ining kategorya mayong laog na mga pahina o media sa ngunyan.''",
        "hidden-categories": "{{PLURAL:$1|Nakatagong kategorya|Mga nakatagong kategorya}}",
        "hidden-category-category": "Mga nakatagong kategorya",
        "category-subcat-count": "{{PLURAL:$2|Ining kategorya igwa sana kan minasunod na sub-kategorya.|Ining kategorya igwa kan minasunod {{PLURAL:$1|subcategory|$1 subcategories}}, out of $2 total.}}",
        "category-article-count-limited": "An minasunod na {{PLURAL:$1|pahina|$1 mga pahina}} yaon sa presenteng kategorya.",
        "category-file-count": "{{PLURAL:$2|Ining kategorya naglalaman sana kan minasunod na sagunson.|An minasunod {{PLURAL:$1|sagunson iyo|$1 na mga sagunson iyo}} sa kategoryang ini, na ginahi sa $2 sa kabilogan.}}",
        "category-file-count-limited": "An minasunod {{PLURAL:$1|na sagunson|$1 na mga sagunson}} yaon sa presenteng kategorya.",
-       "listingcontinuesabbrev": "sunód",
-       "index-category": "Hinukdoang mga pahina",
-       "noindex-category": "Bakong hinukdoang mga pahina",
+       "listingcontinuesabbrev": "sunod",
+       "index-category": "Panhinukdong mga pahina",
+       "noindex-category": "Bakong panhinukdong mga pahina",
        "broken-file-category": "Mga pahina na igwang nagkaparasa na sagunsong kilyawan",
        "about": "Manonongod",
        "article": "Laog na pahina",
        "newwindow": "(minabukas sa bàgong bintanà)",
-       "cancel": "Kanselaron",
+       "cancel": "Pondohon",
        "moredotdotdot": "Kadagdagan...",
-       "morenotlisted": "Ining listahan bako pang kumpleto.",
-       "mypage": "An Pahina",
-       "mytalk": "Orolayan",
-       "anontalk": "Olay para kaining IP address",
-       "navigation": "Nabigasyon",
+       "morenotlisted": "Kulang ining listahan.",
+       "mypage": "Pahina",
+       "mytalk": "Mag-ulay",
+       "anontalk": "Urulay para kaining IP address",
+       "navigation": "Paglibotlibot",
        "and": "&#32;asin",
        "qbfind": "Maghanap",
-       "qbbrowse": "Halungkáta",
-       "qbedit": "Liwata",
+       "qbbrowse": "Maghalungkat",
+       "qbedit": "Liwaton",
        "qbpageoptions": "Ining pahina",
        "qbmyoptions": "Sakong mga pahina",
-       "faq": "PPK (Pirmihang Pighahapot na mga kahaputan)",
-       "faqpage": "Project:PPK (Pirmihang Pighahapot na mga Kahaputan)",
-       "actions": "Mga aksyon",
+       "faq": "PH (Parating Hapot)",
+       "faqpage": "Proyekto:PH (Parating Hapot)",
+       "actions": "Mga paghiro",
        "namespaces": "Mga espasyong ngaran",
-       "variants": "Mga pinalaen",
-       "navigation-heading": "Listahan sa Nabigasyon",
+       "variants": "Mga lain pa",
+       "navigation-heading": "Hihilngan nin paglibotlibot",
        "errorpagetitle": "Salâ",
        "returnto": "Magbalik sa $1.",
        "tagline": "Gikan sa {{SITENAME}}",
-       "help": "Katabangan",
+       "help": "Tabang",
        "search": "Maghanap",
        "searchbutton": "Maghanap",
        "go": "Dumani",
        "searcharticle": "Lakaw",
-       "history": "Historiya kan pahina",
-       "history_short": "Historiya",
+       "history": "Uusipon kan pahina",
+       "history_short": "Uusipon",
        "updatedmarker": "dinagdagan poon kan sakong huring pagbisita",
-       "printableversion": "Puwede maimprintang bersyon",
+       "printableversion": "Nalilimbag na bersyon",
        "permalink": "Permanenteng kilyawan",
-       "print": "Imprintaron",
-       "view": "Tanawon",
-       "view-foreign": "Hilngon sa $1",
-       "edit": "Liwatón",
+       "print": "Ilimbag",
+       "view": "Tànawon",
+       "view-foreign": "Hilingon sa $1",
+       "edit": "Liwaton",
        "edit-local": "Liwaton an lokal na deskripsyon",
        "create": "Muknaon",
        "create-local": "Idugang an lokal na deskripsyon",
-       "editthispage": "Liwata ining pahina",
+       "editthispage": "Liwaton ining pahina",
        "create-this-page": "Muknaon ining pahina",
        "delete": "Puraon",
        "deletethispage": "Puraon ining pahina",
        "undeletethispage": "Balikon sa pagkapura ining pahina",
-       "undelete_short": "Bawia an pagpurà kan {{PLURAL:$1|sarong pagliwat|$1 mga pagliwat}}",
-       "viewdeleted_short": "Hilngon {{PLURAL:$1|sarong pinara na pagliwat|$1 mga pinara na pagliwat}}",
+       "undelete_short": "Bawion an {{PLURAL:$1|sarong pagliwat|$1 mga pagliwat}}",
+       "viewdeleted_short": "Hilingon {{PLURAL:$1|sarong pinara na pagliwat|$1 mga pinara na pagliwat}}",
        "protect": "Protektari",
        "protect_change": "Ribayan",
        "protectthispage": "Protektaran ining pahina",
-       "unprotect": "Ribayi an proteksyon",
-       "unprotectthispage": "Ribayi an proteksyon kaining pahina",
-       "newpage": "Bàguhong pahina",
-       "talkpage": "Orolayan ining pahina",
-       "talkpagelinktext": "Olay",
-       "specialpage": "Espesyal na Pahina",
-       "personaltools": "Personal na mga kagamitan",
-       "postcomment": "Baguhong seksyon",
-       "articlepage": "Tanawon an laog kan pahina",
-       "talk": "Orolayan",
-       "views": "Mga Tanawon",
-       "toolbox": "Mga gagamiton:",
-       "userpage": "Tanawon an pahina kan parágamit",
-       "projectpage": "Tanawon an pahina kan proyekto",
-       "imagepage": "Hilngón an pahina nin sagunson (file)",
-       "mediawikipage": "Tanawon an pahina kan mensahe",
-       "templatepage": "Tanawon an pahina kan panguyog",
-       "viewhelppage": "Tanawon an pahina nin katabangan",
-       "categorypage": "Tanawon an pahina nin kategorya",
-       "viewtalkpage": "Tanawon an orolayan",
-       "otherlanguages": "Sa ibang mga lengguwahe",
-       "redirectedfrom": "(Redirektado gikan sa $1)",
-       "redirectpagesub": "Redirektang pahina",
+       "unprotect": "Ribayan an proteksyon",
+       "unprotectthispage": "Ribayan an proteksyon kaining pahina",
+       "newpage": "Bàgong pahina",
+       "talkpage": "Urulayan ining pahina",
+       "talkpagelinktext": "Mag-ulay",
+       "specialpage": "Sadyang Pahina",
+       "personaltools": "Pansadiring mga kagamitan",
+       "articlepage": "Tànawon an laog kan pahina",
+       "talk": "Urulay",
+       "views": "Mga tànaw",
+       "toolbox": "Mga gamit:",
+       "userpage": "Tànawon an pahina kan paragamit",
+       "projectpage": "Tànawon an pahina kan proyekto",
+       "imagepage": "Hilingon an pahina nin sagunson (file)",
+       "mediawikipage": "Tànawon an pahina kan mensahe",
+       "templatepage": "Tànawon an pahina kan panguyog",
+       "viewhelppage": "Tànawon an pahina nin pagtabang",
+       "categorypage": "Tànawon an pahina nin kategorya",
+       "viewtalkpage": "Tànawon an urulay",
+       "otherlanguages": "Sa ibang mga tataramon",
+       "redirectedfrom": "(Inilikay gikan sa $1)",
+       "redirectpagesub": "Likay na pahina",
        "lastmodifiedat": "Ining pahina huring pinagbago kan $1, mga alas $2.",
        "viewcount": "Ining pahina pinaglaog nin {{PLURAL:$1|sarong beses|nin $1 beses}}.",
        "protectedpage": "Protektadong pahina",
-       "jumpto": "Magluksó sa:",
-       "jumptonavigation": "nabigasyon",
+       "jumpto": "Maglukso sa:",
+       "jumptonavigation": "paglibotlibot",
        "jumptosearch": "hanapon",
        "view-pool-error": "Sori tabi, an mga server kargado sa oras na ini.\nGrabe kadakol an mga paragamit na pinagprubaran mahiling an pahinang ini.\nMakihalat tabi nin kadikit na panahon bago ka magprubara na makapaglaog sa pahinang ini.\n\n$1",
        "generic-pool-error": "Sori tabi, an mga serbidor grabe kakargado sa oras na ini. Kadakulon na gayo an mga paragamit na minaprubar na hilngon ining kaggikanan. Tabi pakihalat kadikit bago ka magprubar otro na makapaglaog sa kaggikanang ini.",
        "pool-queuefull": "An grupong panproseso panoon",
        "pool-errorunknown": "Bakong bistadong sala",
        "aboutsite": "Dapít sa {{SITENAME}}",
-       "aboutpage": "Project:Mapanonongód",
+       "aboutpage": "Project:Mapanonongod",
        "copyright": "An kalamnan manunumpungan sa laog kan $1 o baya notado na ining laen.",
        "copyrightpage": "{{ns:project}}:Mga Katanosang pansurat",
        "currentevents": "Sa ngunyan na mga pangyayari",
        "newmessageslinkplural": "{{PLURAL:$1|sarong baguhong mensahe|999=baguhong mga mensahe}}",
        "newmessagesdifflinkplural": "kahurihan na {{PLURAL:$1|kaliwatan|999=mga kaliwatan}}",
        "youhavenewmessagesmulti": "Igwa ka nin mga bàgong mensahe sa $1",
-       "editsection": "liwatón",
-       "editold": "Liwatón",
-       "viewsourceold": "hilingón an ginikánan",
-       "editlink": "liwatón",
-       "viewsourcelink": "tanawon an ginikanan",
-       "editsectionhint": "Liwatón an seksyon: $1",
-       "toc": "Mga laóg",
-       "showtoc": "ipahilíng",
-       "hidetoc": "tagóon",
-       "collapsible-collapse": "Pinahalipot",
-       "collapsible-expand": "Pinahalawig",
-       "thisisdeleted": "Hilingón o isulít an $1?",
-       "viewdeleted": "Hilingón an $1?",
+       "editsection": "liwaton",
+       "editold": "liwaton",
+       "viewsourceold": "hilingon an ginikanan",
+       "editlink": "liwaton",
+       "viewsourcelink": "tànawon an ginikanan",
+       "editsectionhint": "Liwaton an seksyon: $1",
+       "toc": "Mga laog",
+       "showtoc": "ipahiling",
+       "hidetoc": "tagoon",
+       "collapsible-collapse": "Ibagsak",
+       "collapsible-expand": "Ibuka",
+       "thisisdeleted": "Hilingon o isulit an $1?",
+       "viewdeleted": "Hilingon an $1?",
        "restorelink": "{{PLURAL:$1|sarong pinagpurang pagliwat|$1 na pinagpurang mga pagliwat}}",
        "feedlinks": "Hungit:",
        "feed-invalid": "Imbalidong tipo nin hungit sa subkripsyon.",
        "filereadonlyerror": "Dae kinayang baguhon an sagunson (file) \"$1$ nin huli ta an repositoryo kan sagunson \"$2\" yaon sa kamugtakan na basahon sana.\n\nAn administrador na iyo an nagkandado kaini nagpahayag kaining kapaliwanagan: \"$3\".",
        "invalidtitle-knownnamespace": "Imbalidong titulo na igwang espasyadong ngaran na \"$2\" asin teksto na \"$3\"",
        "invalidtitle-unknownnamespace": "Imbalidong titulo na igwang nin bakong bistado na bilang kan espasyadong ngaran na $1 asin teksto na \"$2\"",
-       "exception-nologin": "Dae ka nakalaog",
+       "exception-nologin": "Dai ka nakalaog",
        "exception-nologin-text": "Tabi man [[Special:Userlogin|maglaog]]na tanganing makalangkay sa pahinang ini o aksyon.",
        "exception-nologin-text-manual": "Tabi man $1 na tanganing makalangkay sa pahinang ini o aksyon.",
        "virus-badscanner": "Raot na kasalansanan: Bakong bistadong virus scanner: ''$1''",
        "userlogin-yourname": "Paragamit-na-Ngaran",
        "userlogin-yourname-ph": "Ikaag an saimong paragamit-na-ngaran",
        "createacct-another-username-ph": "Ikaag an paragamit-na-ngaran",
-       "yourpassword": "Pasa-taramon:",
-       "userlogin-yourpassword": "Sikretong panlaog",
+       "yourpassword": "Sekretong Panlaog",
+       "userlogin-yourpassword": "Sekretong Panlaog",
        "userlogin-yourpassword-ph": "Ikaag an saimong sekretong panlaog",
        "createacct-yourpassword-ph": "Ikaag an sekretong panlaog",
        "yourpasswordagain": "Pakilaog giraray kan sekretong panlaog:",
        "externaldberror": "Igwa gayod sala sa arinman kan patunay sa datos-sarayan o ika dae pinagtugutan na bâgohon an saimong panluwas na panindog.",
        "login": "Maglaog",
        "nav-login-createaccount": "Maglaog / magmukna nin panindog",
-       "loginprompt": "Ika kaipong paganahon an mga cookies tanganing makalaog sa {{SITENAME}}.",
        "userlogin": "Maglaog / magmukna nin panindog",
        "userloginnocreate": "Maglaog ka",
        "logout": "Magluwas",
-       "userlogout": "Magluwás",
+       "userlogout": "Magluwas",
        "notloggedin": "Dae ka nakalaog",
        "userlogin-noaccount": "Mayo ka nin panindog?",
        "userlogin-joinproject": "Mag-ayon{{SITENAME}}",
        "resettokens-resetbutton": "Pakibaguha an pinagpiling mga paduos",
        "bold_sample": "Mahìbog na teksto",
        "bold_tip": "Mahìbog na teksto",
-       "italic_sample": "Itálikong teksto",
-       "italic_tip": "Tekstong Itáliko",
+       "italic_sample": "Italikong teksto",
+       "italic_tip": "Tekstong Italiko",
        "link_sample": "Titulo nin sugpon",
        "link_tip": "Panlaog na sugpon",
        "extlink_sample": "http://www.example.com títulong sugpon",
        "editpage-notsupportedcontentformat-text": "An pormat nin kalamnan na $1 bakong suportado kan modelong kalamnan na $2.",
        "content-model-wikitext": "wiki-teksto",
        "content-model-text": "yanong-teksto",
-       "content-model-javascript": "Java-Kurit",
+       "content-model-javascript": "JavaScript",
        "content-model-css": "CSS",
        "expensive-parserfunction-warning": "'''Patanid tabi:''' Ining pahina naglalaman nin grabe kadakulon na ekspensibong programang pambaranga sa punksyon nin mga pag-aapod.\n\nIni dapat magkaigwa nin menos sanang $2 {{PLURAL:$2|apod|mga apod}}, igwa na {{PLURAL:$1|ngunyan nin $1 apod|ngunyan nin $1 mga apod}}.",
        "expensive-parserfunction-category": "Mga pahina na igwa nin grabe kadakulon na mga ekspensibong programang pambaranga sa punksyon nin mga pag-aapod",
        "cantcreateaccount-text": "An pagbukas nin account halì sa IP na ('''$1''') binágat ni [[User:$3|$3]].\n\n''$2'' an rason na pigtao ni $3",
        "viewpagelogs": "\nHilingon an mga katalaanan para sa pahinang ini",
        "nohistory": "Mayong paghirá nin uusipón sa pahinang ini.",
-       "currentrev": "Sa ngonyan na pagpakarháy",
-       "currentrev-asof": "Pinakahuring pagbabago kan $1",
-       "revisionasof": "Rebisyon poon kan $1",
+       "currentrev": "Ppagpakarhay sa ngunyan",
+       "currentrev-asof": "Pinakahuring pagpakarhay kan $1",
+       "revisionasof": "Pagpakarhay poon kan $1",
        "revision-info": "Rebisyon poon kan $1 ni $2",
-       "previousrevision": "←Lumàon na rebisyon",
-       "nextrevision": "Mas bàguhon na rebisyon→",
+       "previousrevision": "← Dating pagpakarhay",
+       "nextrevision": "Bagong pagpakarhay →",
        "currentrevisionlink": "Sa ngunyan na rebisyon",
-       "cur": "sa ngunyán",
+       "cur": "sa ngunyan",
        "next": "sunod",
-       "last": "sa nakaagi",
-       "page_first": "enot",
+       "last": "dati",
+       "page_first": "inot",
        "page_last": "huri",
-       "histlegend": "Kalaenan sa pilian: Markahan an mga kahon nin radyo kan mga rebisyon tanganing komapararon asin pinduta an \"enter\" o an pindutan na yaon sa irarom.<br />\nKabalaynan: '''({{int:cur}})''' = kalaenan sa pinakahuring rebisyon, '''({{int:last}})''' = kalaenan sa sinundan na rebisyon, '''{{int:minoreditletter}}''' = dikiton na pagliwat.",
-       "history-fieldset-title": "Historiya nin kinilyawan",
+       "histlegend": "Lain sa pilian: Markahan an mga kahon nin radyo kan mga pagpakarhay tanganing komapararon asin pinduta an \"enter\" o an pindutan na yaon sa irarom.<br />\nKabalaynan: '''({{int:cur}})''' = kalaenan sa pinakahuring rebisyon, '''({{int:last}})''' = kalaenan sa sinundan na rebisyon, '''{{int:minoreditletter}}''' = dikiton na pagliwat.",
+       "history-fieldset-title": "Uusipon nin paghalungkat",
        "history-show-deleted": "Pinagpura sana",
        "histfirst": "pinakalumaon",
        "histlast": "pinakabaguhon",
        "historysize": "({{PLURAL:$1|sarong byte|$1 mga bytes}})",
        "historyempty": "(mayong laog)",
-       "history-feed-title": "Uusipón kan pagpakaraháy",
-       "history-feed-description": "Uusipón kan pagpakaraháy para sa pahinang ini sa wiki",
+       "history-feed-title": "Uusipon kan pagpakarhay",
+       "history-feed-description": "Uusipon kan pagpakarahay para sa pahinang ini sa wiki",
        "history-feed-item-nocomment": "$1 sa $2",
-       "history-feed-empty": "Mayò man an hinágad na pahina.\nPwedeng pigparà na ini sa wiki, o tinàwan nin bàgong pangaran.\nProbaran tabì an [[Special:Search|pighahanap sa wiki]] para sa mga pahinang dapít.",
+       "history-feed-empty": "Mayò man an hinagad na pahina.\nPwedeng pigparà na ini sa wiki, o tinàwan nin bàgong pangaran.\nProbaran tabì an [[Special:Search|pighahanap sa wiki]] para sa mga pahinang dapít.",
        "rev-deleted-comment": "(pagliwat na sumaryo pinaghale)",
        "rev-deleted-user": "(hinalì an parágamit)",
        "rev-deleted-event": "(talaan kan aksyon pinaghale)",
        "rclistfrom": "Ipahiling an baguhon na mga kaliwatan magpoon kan $3 $2",
        "rcshowhideminor": "$1 saradit na mga pagliwat",
        "rcshowhideminor-show": "Ipatanaw",
-       "rcshowhideminor-hide": "Tagoa",
+       "rcshowhideminor-hide": "Itago",
        "rcshowhidebots": "$1 mga gantaw",
        "rcshowhidebots-show": "Ipatanaw",
-       "rcshowhidebots-hide": "Tagoa",
+       "rcshowhidebots-hide": "Itago",
        "rcshowhideliu": "$1 rehistradong mga paragamit",
        "rcshowhideliu-show": "Ipatanaw",
-       "rcshowhideliu-hide": "Tagoa",
+       "rcshowhideliu-hide": "Itago",
        "rcshowhideanons": "$1 mga dae bistong paragamit",
        "rcshowhideanons-show": "Ipatanaw",
-       "rcshowhideanons-hide": "Tagoa",
+       "rcshowhideanons-hide": "Itago",
        "rcshowhidepatr": "$1 patrolyadong mga pagliwat",
        "rcshowhidepatr-show": "Ipatanaw",
        "rcshowhidepatr-hide": "Tagoa",
        "rcshowhidemine": "$1 sakong mga pagliliwat",
        "rcshowhidemine-show": "Ipatanaw",
-       "rcshowhidemine-hide": "Tagoa",
+       "rcshowhidemine-hide": "Itago",
        "rclinks": "Ipahilíng an $1 huring mga kaliwatan sa laog nin huring $2 na mga aldaw<br />$3",
        "diff": "kalaenan",
        "hist": "sagaysay",
        "duplicate-defaultsort": "'''Patanid tabi:''' An susing panugmad kan salansan na \"$2\" minasalimbaw sa dating susing panugmad kan salansan na \"$1\".",
        "version": "Bersyon",
        "version-extensions": "Instaladong mga ekstensyon",
+       "version-skins": "Mga kublit",
        "version-specialpages": "Espesyal na mga pahina",
        "version-parserhooks": "Mga pangawil kan parser",
        "version-variables": "Mga kabalanggayahan",
        "version-antispam": "Pan-spam na pangataman",
-       "version-skins": "Mga kublit",
        "version-other": "An iba pa",
        "version-mediahandlers": "Mga Midyang Tagakapot",
        "version-hooks": "Mga pangawil",
index 6ff5b6c..16385c7 100644 (file)
        "talkpagelinktext": "гутаркі",
        "specialpage": "Спэцыяльная старонка",
        "personaltools": "Асабістыя прылады",
-       "postcomment": "Новая сэкцыя",
        "articlepage": "Паказаць старонку зьместу",
        "talk": "Абмеркаваньне",
        "views": "Рэжымы",
        "externaldberror": "Адбылася памылка аўтэнтыфікацыі з дапамогай вонкавай базы зьвестак, ці Вам не дазволена абнаўляць свой рахунак.",
        "login": "Увайсьці",
        "nav-login-createaccount": "Уваход / стварэньне рахунку",
-       "loginprompt": "Вы павінны дазволіць cookie для ўваходу ў {{GRAMMAR:вінавальны|{{SITENAME}}}}.",
        "userlogin": "Увайсьці ў сыстэму",
        "userloginnocreate": "Увайсьці",
        "logout": "Выйсьці",
        "revdelete-text-text": "Выдаленыя вэрсіі будуць па-ранейшаму бачныя ў гісторыі старонкі, але некаторыя часткі іх зьместу будуць недаступныя для ўдзельнікаў.",
        "revdelete-text-file": "Выдаленыя вэрсіі файла будуць па-ранейшаму бачныя ў гісторыі старонкі, але часткі іх зьместу будуць недаступныя для ўдзельнікаў.",
        "logdelete-text": "Выдаленыя падзеі ў журнале будуць па-ранейшаму даступныя ў журналах, але часткі іх зьместу будуць недаступныя ўдзельнікам.",
-       "revdelete-text-others": "Іншыя адмністратары {{GRAMMAR:родны|{{SITENAME}}}} па-ранейшаму будуць мець магчымасьць пабачыць і аднавіць схаваны зьмест праз гэты ж інтэрфэйс, калі ня будуць усталяваныя дадатковыя абмежаваньні.",
+       "revdelete-text-others": "Іншыя адмністратары па-ранейшаму будуць мець магчымасьць пабачыць і аднавіць схаваны зьмест, калі ня будуць усталяваныя дадатковыя абмежаваньні.",
        "revdelete-confirm": "Калі ласка, пацьвердзіце, што Вы сапраўды жадаеце зрабіць гэта, разумееце наступствы і робіце гэта ў адпаведнасьці з [[{{MediaWiki:Policy-url}}|правіламі]].",
        "revdelete-suppress-text": "Скрываньне можа выкарыстоўвацца '''толькі''' ў наступных выпадках:\n* патэнцыйна паклёпніцкая інфармацыя\n* раскрыцьцё асабістых зьвестак\n*: ''хатнія адрасы, тэлефонныя нумары, нумары пашпартоў і г. д.''",
        "revdelete-legend": "Усталяваць абмежаваньні бачнасьці",
        "right-deletedtext": "прагляд выдаленага тэксту і зьменаў паміж выдаленымі вэрсіямі старонак",
        "right-browsearchive": "пошук выдаленых старонак",
        "right-undelete": "аднаўленьне старонак",
-       "right-suppressrevision": "прагляд і аднаўленьне вэрсіяў, схаваных ад адміністратараў",
+       "right-suppressrevision": "праглядаць, хаваць і аднаўляць пэўныя вэрсіі старонак, зробленыя любым удзельнікам",
+       "right-viewsuppressed": "праглядаць вэрсіі старонак, схаваныя ад усіх удзельнікаў",
        "right-suppressionlog": "прагляд прыватных журналаў",
        "right-block": "блякаваньне іншых удзельнікаў ад рэдагаваньняў",
        "right-blockemail": "блякаваньне іншых ўдзельнікаў ад дасылкі электроннай пошты",
        "license": "Ліцэнзія:",
        "license-header": "Ліцэнзія",
        "nolicense": "Ня выбраная",
+       "licenses-edit": "Рэдагаваць парамэтры ліцэнзіі",
        "license-nopreview": "(Прагляд недаступны)",
        "upload_source_url": " (слушны, агульнадаступны URL-адрас)",
        "upload_source_file": " (файл на Вашым кампутары)",
+       "listfiles-delete": "выдаліць",
        "listfiles-summary": "На гэтай спэцыяльнай старонцы паказаныя ўсе загружаныя файлы.",
        "listfiles_search_for": "Пошук па назьве файла:",
        "imgfile": "файл",
        "wantedpages-badtitle": "Няслушная назва сярод вынікаў: $1",
        "wantedfiles": "Запатрабаваныя файлы",
        "wantedfiletext-cat": "Наступныя файлы выкарыстоўваюцца, але іх няма. Файлы са зьнешніх сховішчаў могуць знаходзіцца ў сьпісе без уліку іх існаваньня. Любыя такія няслушныя ўваходжаньні будуць <del>выкрасьленыя</del>. Дадаткова, старонкі, якія ўбудоўваюць неіснуючыя файлы прыведзеныя на [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Наступныя файлы ўжваюцца, але не існуюць. Дадаткова, старонкі, у якія ўключаныя няісныя файлы, прыведзеныя ў [[:$1]].",
        "wantedfiletext-nocat": "Наступныя файлы выкарыстоўваюцца, але іх няма. Файлы са зьнешніх сховішчаў могуць знаходзіцца ў сьпісе без уліку іх існаваньня. Любыя такія няслушныя ўваходжаньні будуць <del>выкрасьленыя</del>.",
+       "wantedfiletext-nocat-noforeign": "Наступныя файлы выкарыстоўваюцца, але іх няма.",
        "wantedtemplates": "Запатрабаваныя шаблёны",
        "mostlinked": "Старонкі, на якія найчасьцей спасылаюцца",
        "mostlinkedcategories": "Катэгорыі з найбольшай колькасьцю старонак",
        "timezone-utc": "UTC",
        "unknown_extension_tag": "Невядомы тэг пашырэньня «$1»",
        "duplicate-defaultsort": "Папярэджаньне: Ключ сартыроўкі па змоўчваньні «$2» замяняе папярэдні ключ сартыроўкі па змоўчваньні «$1».",
+       "duplicate-displaytitle": "<strong>Папярэджаньне:</strong> назва для адлюстраваньня «$2» перапісвае ранейшую назву для адлюстраваньня «$1».",
        "version": "Вэрсія",
        "version-extensions": "Усталяваныя пашырэньні",
        "version-skins": "Усталяваныя тэмы афармленьня",
        "expand_templates_generate_xml": "Паказаць дрэва аналізу XML",
        "expand_templates_generate_rawhtml": "Паказаць HTML",
        "expand_templates_preview": "Папярэдні прагляд",
-       "pagelanguage": "Выбар мовы старонкі"
+       "pagelanguage": "Выбар мовы старонкі",
+       "pagelang-name": "Старонка",
+       "pagelang-language": "Мова",
+       "pagelang-use-default": "Ужываць мову па змоўчаньні",
+       "pagelang-select-lang": "Абярыце мову",
+       "right-pagelang": "Зьмяніць мову старонкі",
+       "action-pagelang": "зьмену мовы старонкі",
+       "log-name-pagelang": "Журнал зьменаў мовы",
+       "log-description-pagelang": "Гэта журнал зьменаў мовы старонак.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|зьмяніў|зьмяніла}} мову старонкі $3 з $4 на $5."
 }
index 3de60fa..cfae5f8 100644 (file)
        "talkpagelinktext": "Размовы",
        "specialpage": "Адмысловая старонка",
        "personaltools": "Асабістыя прылады",
-       "postcomment": "Новы раздзел",
        "articlepage": "Паказаць старонку змесціва",
        "talk": "Размовы",
        "views": "Віды",
        "pool-timeout": "Выйшаў час чакання блакіроўкі",
        "pool-queuefull": "Чарга запытаў перапоўнена",
        "pool-errorunknown": "Невядомая памылка",
+       "pool-servererror": "Служба лічыльніка пулу недаступная ($1).",
        "aboutsite": "Пра {{GRAMMAR:вінавальны|{{SITENAME}}}}",
        "aboutpage": "Project:Пра {{GRAMMAR:вінавальны|{{SITENAME}}}}",
        "copyright": "Матэрыял даступны на ўмовах $1 (калі не пазначана іншае).",
        "nospecialpagetext": "<strong>Вы звярнуліся па няправільную адмысловую старонку.</strong>\n\nПералік правільных адмысловых старонак ёсць на [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Памылка",
        "databaseerror": "Памылка базы дадзеных",
+       "databaseerror-text": "Здарылася памылка запыту да базы звестак.\nГэта можа ўказваць на няспраўнасць у праграме.",
+       "databaseerror-textcl": "Здарылася памылка запыту да базы звестак.",
        "databaseerror-query": "Запыт: $1",
        "databaseerror-function": "Функцыя: $1",
        "databaseerror-error": "Памылка: $1",
        "externaldberror": "Або памылка вонкавай аўтэнтыкацыі ў базе дадзеных, або вам не дазволена абнаўляць свой вонкавы рахунак.",
        "login": "Увайсці ў сістэму",
        "nav-login-createaccount": "Увайсці ў сістэму / стварыць рахунак",
-       "loginprompt": "Каб уваходзіць у сістэму {{SITENAME}}, трэба дазволіць у браўзеры квіткі (кукі).",
        "userlogin": "Увайсці ў сістэму / стварыць рахунак",
        "userloginnocreate": "Увайсці",
        "logout": "Выйсці з сістэмы",
        "resetpass-submit-cancel": "Нічога",
        "resetpass-wrong-oldpass": "Недапушчальны тымчасовы ці актуальны пароль.\nМагчыма, вы ўжо змянілі свой пароль ці папрасілі новы тымчасовы.",
        "resetpass-recycled": "Калі ласка, змяніце свой пароль на нешта іншае, чым ваш цяперашні пароль.",
+       "resetpass-temp-emailed": "Вы ўвайшлі ў сістэму з дапамогаю тымчасовага коду, дасланага па эл.пошце.\nКаб завершыць уваход, неабходна ўстанавіць новы пароль:",
        "resetpass-temp-password": "Тымчасовы пароль:",
+       "resetpass-abort-generic": "Змяненне пароля было спынена прыстаўкаю.",
        "resetpass-expired": "Ваш пароль пратэрмінаваны. Калі ласка, устанавіце новы пароль для ўваходу ў сістэму.",
        "resetpass-expired-soft": "Ваш пароль пратэрмінаваны, яго трэба замяніць. Калі ласка, выберыце новы пароль зараз, ці націсніце \"{{int:resetpass-submit-cancel}}\", каб змяніць яго пазней.",
        "resetpass-validity-soft": "Ваш пароль недапушчальны: $1\n\nКалі ласка, выберыце новы пароль зараз, або націсніце \"{{int:resetpass-submit-cancel}}\", каб скінуць яго пазней.",
        "changeemail-submit": "Змяніць адрас электроннай пошты:",
        "changeemail-cancel": "Адмена",
        "changeemail-throttled": "Надта штмат спробаў увайсці пад гэтым рахункам. Пачакайце $1 перад тым, як спрабаваць ізноў.",
+       "resettokens": "Скінуць токены",
+       "resettokens-text": "Вы можаце пераўстанавіць токены, якія дазваляюць атрымліваць доступ да пэўных прыватных звестак, звязаных з вашым уліковым запісам.\n\nВы мусіце скінуць токены, калі выпадкова падзяліліся імі з кім-небудзь, ці ваш уліковы запіс быў скампраметаваны.",
+       "resettokens-no-tokens": "Няма чаго скідваць.",
+       "resettokens-legend": "Скідванне токенаў",
+       "resettokens-tokens": "Токены:",
        "resettokens-token-label": "$1 (актуальнае значэнне: $2)",
+       "resettokens-watchlist-token": "Токен струменя (Atom/RSS) [[Special:Watchlist|зменаў старонак у вашым спісе назірання]]",
+       "resettokens-done": "Токены скінуты.",
+       "resettokens-resetbutton": "Скінуць выбраныя токены",
        "bold_sample": "Цёмны тэкст",
        "bold_tip": "Цёмны тэкст",
        "italic_sample": "Курсіўны тэкст",
        "showdiff": "Розніца",
        "anoneditwarning": "Вы не ўвайшлі ў сістэму. Таму, калі вы запішаце старонку, у яе гісторыю трапіць ваш адрас IP.",
        "anonpreviewwarning": "''Вы не прайшлі ідэнтыфікацыю Захаванне будзе запісана з вашым IP адрасам у гісторыі правак гэтай старонкі.''",
-       "missingsummary": "'''Нагадваем''': вы не ўпісалі тлумачэння для сваёй праўкі. Калі націснуць Запісаць яшчэ раз, праўка будзе замацавана без тлумачэння.",
+       "missingsummary": "<strong>Нагадваем:</strong> вы не ўпісалі тлумачэння для сваёй праўкі. Калі націснуць \"{{int:savearticle}}\" яшчэ раз, праўка будзе замацавана без тлумачэння.",
        "missingcommenttext": "Калі ласка, увядзіце ніжэй каментарый.",
        "missingcommentheader": "'''Увага:''' вы нічога не ўпісалі ў тэму/загаловак гэтай заўвагі. Націсканне '{{int:savearticle}}' замацуе вашую праўку з пустой тэмай/загалоўкам.",
        "summary-preview": "Перадпаказ апісання:",
        "accmailtitle": "Быў адасланы пароль",
        "accmailtext": "На адрас $2 быў дасланы згенераваны пароль для [[User talk:$1|$1]]. Ён можа быць зменены на <em>[[Special:ChangePassword|старонцы змены пароля]]</em> пасля ўваходу ў сістэму.",
        "newarticle": "(Новы)",
-       "newarticletext": "Вы перайшлі да старонкі, якой яшчэ няма, і таму трапілі сюды. Каб пачаць новую старонку, пішыце яе тэкст у ніжэйпаказаным акне рэдагавання (падрабязнасці бач у [$1 даведцы]). Калі вы тут выпадкова, проста націсніце \"назад\" у браўзеры.",
+       "newarticletext": "Вы перайшлі да старонкі, якой яшчэ няма, і таму трапілі сюды. \nКаб пачаць новую старонку, пішыце яе тэкст у ніжэйпаказаным акне рэдагавання (падрабязнасці бач у [$1 даведцы]). \nКалі вы тут выпадкова, проста націсніце <strong>назад</strong> у браўзеры.",
        "anontalkpagetext": "----''Гэта старонка размовы з ананімным удзельнікам, які або не мае свайго рахунку, або ім не карыстаўся. Таму дзеля яго ці яе ідэнтыфікацыі мы мусім выкарыстаць лічбавы Адрас IP. Такі адрас IP могуць дзяліць між сабою некалькі асоб. Калі вы ананімны ўдзельнік, і лічыце, што атрымліваеце няслушныя заўвагі,[[Special:UserLogin/signup|стварыце рахунак]] або [[Special:UserLogin|акажыцеся]], каб вас больш не блыталі з іншымі ананімнымі ўдзельнікамі.''",
        "noarticletext": "Старонка не ўтрымлівае тэксту. Вы можаце [[Special:Search/{{PAGENAME}}|пашукаць гэткую назву]] ў іншых старонках ці <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>, але вы не маеце дазволу на стварэнне гэтай старонкі.",
        "revdelete-text-text": "Сцёртыя версіі будуць па-ранейшаму паказвацца ў гісторыі старонкі, але частка іх зместу будзе недаступна для грамадскасці.",
        "revdelete-text-file": "Сцёртыя версіі файла будуць па-ранейшаму паказвацца ў гісторыі файла, але частка іх зместу будзе недаступна для грамадскасці.",
        "logdelete-text": "Сцёртыя запісы журнала будуць па-ранейшаму паказвацца ў журналах, але частка іх зместу будзе недаступна для грамадскасці.",
-       "revdelete-text-others": "Ð\86нÑ\88Ñ\8bÑ\8f Ð°Ð´Ð¼Ñ\96нÑ\96Ñ\81Ñ\82Ñ\80аÑ\82аÑ\80Ñ\8b Ð¿Ð»Ñ\8fÑ\86оÑ\9eкÑ\96 {{SITENAME}} Ð±Ñ\83дÑ\83Ñ\86Ñ\8c Ð¿Ð°-Ñ\80анейÑ\88амÑ\83 Ð¼ÐµÑ\86Ñ\8c Ð´Ð¾Ñ\81Ñ\82Ñ\83п Ð´Ð° Ñ\81Ñ\85аванага Ð·Ð¼ÐµÑ\81Ñ\82Ñ\83 Ñ\96 Ð·Ð¼Ð¾Ð³Ñ\83Ñ\86Ñ\8c Ð°Ð´Ð½Ð°Ð²Ñ\96Ñ\86Ñ\8c Ñ\8fго Ð¿Ñ\80аз Ð³Ñ\8dÑ\82Ñ\8b Ñ\81амÑ\8b Ñ\96нÑ\82Ñ\8dÑ\80Ñ\84ейÑ\81, калі не ўстанавіць дадатковыя абмежаванні.",
+       "revdelete-text-others": "Ð\86нÑ\88Ñ\8bÑ\8f Ð°Ð´Ð¼Ñ\96нÑ\96Ñ\81Ñ\82Ñ\80аÑ\82аÑ\80Ñ\8b Ð±Ñ\83дÑ\83Ñ\86Ñ\8c Ð¿Ð°-Ñ\80анейÑ\88амÑ\83 Ð¼ÐµÑ\86Ñ\8c Ð´Ð¾Ñ\81Ñ\82Ñ\83п Ð´Ð° Ñ\81Ñ\85аванага Ð·Ð¼ÐµÑ\81Ñ\82Ñ\83 Ñ\96 Ð·Ð¼Ð¾Ð³Ñ\83Ñ\86Ñ\8c Ð°Ð´Ð½Ð°Ð²Ñ\96Ñ\86Ñ\8c Ñ\8fго, калі не ўстанавіць дадатковыя абмежаванні.",
        "revdelete-confirm": "Пацвердзіце, што вы жадаеце гэта зрабіць, што вы разумееце наступствы, і што вы робіце гэта ў адпаведнасці з [[{{MediaWiki:Policy-url}}|арганізацыйнымі правіламі]].",
        "revdelete-suppress-text": "Заглушэнне належыць ужываць <strong>выключна</strong> ў наступных выпадках:\n* патэнцыяльна паклёпніцкія звесткі\n* недапушчальная асабістая інфармацыя\n*: <em>хатнія адрасы і тэлефоны, нумары страхавання і г.д.</em>",
        "revdelete-legend": "Настроіць абмежаванні бачнасці",
        "diff-multi-sameuser": "(Не паказана{{PLURAL:$1|адна прамежкавая версія|$1 прамежкавыя версіі|$1 прамежкавых версій}} таго ж удзельніка)",
        "diff-multi-otherusers": "(Не паказана {{PLURAL:$1|адна прамежкавая версія|$1 прамежкавыя версіі|$1 прамежкавых версій}} {{PLURAL:$2|яшчэ аднаго ўдзельніка|$2 удзельнікаў}})",
        "diff-multi-manyusers": "({{PLURAL:$1|не паказана $1 прамежкавая версія|не паказаны $1 прамежкавыя версіі|не паказаны $1 прамежкавых версій}}, зробленыя больш чым {{PLURAL:$2|$1 удзельнікам|$2 удзельнікамі}})",
+       "difference-missing-revision": "{{PLURAL:$2|$2 версія|$2 версіі|$2 версій}} гэтай розніцы ($1) {{PLURAL:$2|не знойдзена|не знойдзены}}.\n\nЗвычайна такое здараецца з-за пераходу па састарэлай спасылцы на розніцу ў старонцы, якая была сцёрта.\nПадрабязнасці могуць быць у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журнале сціранняў].",
        "searchresults": "Вынікі пошуку",
        "searchresults-title": "Вынікі пошуку «$1»",
        "titlematches": "Знойдзена ў назвах",
        "recentchangesdays-max": "(найбольш $1 {{PLURAL:$1|дзень|дзён}})",
        "recentchangescount": "Прадвызначаная колькасць правак дзеля паказу:",
        "prefs-help-recentchangescount": "Гэта ўключае ў сябе апошнія змены, гісторыі старонак, журналы.",
+       "prefs-help-watchlist-token2": "Гэта сакрэтны ключ к сеціўнай стужцы з вашага спісу назірання.\nКожны, хто ведае гэты ключ, будзе мець магчымасць чытаць ваш спіс назірання, таму не дзяліцеся ім.\nКалі трэба, можна [[Special:ResetTokens|скінуць яго]].",
        "savedprefs": "Настройкі замацаваныя.",
        "timezonelegend": "Часавы пояс:",
        "localtime": "Мясцовы час:",
        "right-deletedtext": "Адкрыць выдалены тэкст і ўсе змены паміж выдаленымі версіямі",
        "right-browsearchive": "Шукаць у сцёртых старонках",
        "right-undelete": "Аднаўляць старонкі",
-       "right-suppressrevision": "Бачыць і аднаўляць версіі, схаваныя ад адміністратараў",
+       "right-suppressrevision": "Бачыць, хаваць і адкрываць схаваныя асобныя версіі ад усіх удзельнікаў",
+       "right-viewsuppressed": "Бачыць версіі, схаваныя ад усіх удзельнікаў",
        "right-suppressionlog": "Чытаць прыватныя журналы",
        "right-block": "Забараняць праўкі іншым удзельнікам",
        "right-blockemail": "Забараняць удзельніку адсыланне эл.пошты",
        "right-userrights-interwiki": "Правіць дазволы ўдзельнікаў на іншых вікі",
        "right-siteadmin": "Замыкаць і адмыкаць базу даных",
        "right-override-export-depth": "Экспартаваць старонкі, у тым ліку звязаныя, да глыбіні спасылак 5.",
-       "right-sendemail": "Адправіць па электроннай пошце іншым карыстальнікам",
-       "right-passwordreset": "пÑ\80аглÑ\8fд Ñ\8dлекÑ\82Ñ\80оннÑ\8bÑ\85 Ð»Ñ\96Ñ\81Ñ\82оÑ\9e Ñ\81а Ð·Ð¼Ñ\8fненнем пароля",
+       "right-sendemail": "Адпраўляць электронныя лісты іншым удзельнікам",
+       "right-passwordreset": "Ð\91аÑ\87Ñ\8bÑ\86Ñ\8c Ñ\8dлекÑ\82Ñ\80оннÑ\8bÑ\8f Ð»Ñ\96Ñ\81Ñ\82Ñ\8b Ð°Ð± Ð·Ð¼Ñ\8fненнÑ\96 пароля",
        "newuserlogpage": "Журнал рэгістрацыі ўдзельнікаў",
        "newuserlogpagetext": "Гэта журнал рэгістрацыі новых удзельнікаў.",
        "rightslog": "Журнал правоў удзельнікаў",
        "lockmanager-fail-releaselock": "Не ўдалося разблакіраваць \"$1\"",
        "lockmanager-fail-db-bucket": "Не атрымалася звязацца з дастатковай колькасцю баз блакаванняў у сегменце $1.",
        "lockmanager-fail-db-release": "Не атрымалася зняць блакаванне базы дадзеных $1.",
+       "lockmanager-fail-svr-acquire": "Не ўдалося атрымаць блакаванні на серверы $1.",
        "lockmanager-fail-svr-release": "Не атрымалася зняць блакаванні на серверы $1.",
        "zip-file-open-error": "Адбылася памылка пры адкрыцці файла для праверкі архіва.",
        "zip-wrong-format": "Указаны файл не з'яўляецца файлам ZIP.",
        "http-invalid-url": "Памылковы URL: $1",
        "http-invalid-scheme": "Не падтрымліваюцца адрасы са схемай \"$1\"",
        "http-request-error": "Не атрымалася выканаць HTTP-запыт з-за невядомай памылкі",
-       "http-read-error": "Памылка чытання HTTP",
+       "http-read-error": "Памылка чытання HTTP.",
        "http-timed-out": "Мінуў час чакання HTTP-запыту.",
        "http-curl-error": "Памылка звароту да URL: $1",
        "http-bad-status": "Пад час апрацоўкі HTTP-запыту выяўлена праблема: $1 $2",
        "license": "Ліцэнзіяванне:",
        "license-header": "Ліцэнзіяванне",
        "nolicense": "Нішто не выбрана",
+       "licenses-edit": "Правіць параметры ліцэнзіі",
        "license-nopreview": "(без перадпаказу)",
        "upload_source_url": " (сапраўдны, публічна дасягальны URL)",
        "upload_source_file": " (файл на вашай машыне)",
+       "listfiles-delete": "сцерці",
        "listfiles-summary": "Гэтая службовая старонка паказвае ўсе загружаныя файлы.",
        "listfiles_search_for": "Знайсці назву выявы:",
        "imgfile": "файл",
        "sharedupload-desc-there": "Гэты файл з $1 і можа выкарыстоўвацца ў іншых праектах.\nДадатковую інфармацыю можна знайсці на [$2 старонцы апісання файла].",
        "sharedupload-desc-here": "Гэты файл з $1 і можа выкарыстоўвацца іншымі праектамі. Апісанне на яго [$2 старонцы размоў] прыведзена ніжэй",
        "sharedupload-desc-edit": "Гэты файл з $1 і можа выкарыстоўвацца ў іншых праектах.\nМажліва, вы хочаце правіць апісанне на [$2 старонцы апісання файла] там.",
+       "sharedupload-desc-create": "Гэты файл з $1 і можа выкарыстоўвацца ў іншых праектах.\nПравіць яго апісанне можна на гэнай [$2 старонцы апісання файла].",
        "filepage-nofile": "Не знойдзены файл з такой назвай.",
        "filepage-nofile-link": "Не знойдзены файл з такой назвай, але можна [$1 яго ўкласці].",
        "uploadnewversion-linktext": "Укласці новую версію гэтага файла",
        "wantedpages-badtitle": "Недапушчальная назва ў выніках: $1",
        "wantedfiles": "Патрэбныя файлы",
        "wantedfiletext-cat": "Наступныя файлы выкарыстоўваюцца, але іх няма. Файлы са знешніх сховішчаў могуць знаходзіцца ў спісе без уліку іх існавання. Любыя такія няслушныя ўваходжанні будуць <del>выкрасленыя</del>. Дадаткова, старонкі, якія ўбудоўваюць неіснуючыя файлы прыведзеныя на [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Наступныя файлы выкарыстоўваюцца, хаця іх няма. Дадаткова, старонкі, што ўключаюць файлы, каторых няма, пералічаны ў [[:$1]].",
        "wantedfiletext-nocat": "Наступныя файлы выкарыстоўваюцца, але іх няма. Файлы са знешніх сховішчаў могуць знаходзіцца ў спісе без уліку іх існавання. Любыя такія няслушныя ўваходжанні будуць <del>выкрасленыя</del>.",
+       "wantedfiletext-nocat-noforeign": "Наступныя файлы выкарыстоўваюцца, хоць іх няма.",
        "wantedtemplates": "Патрэбныя шаблоны",
        "mostlinked": "Старонкі, на якія найчасцей спасылаюцца",
        "mostlinkedcategories": "Катэгорыі з найбольшай колькасцю складнікаў",
        "trackingcategories-msg": "Катэгорыя для асочвання",
        "trackingcategories-name": "Назва паведамлення",
        "trackingcategories-desc": "Крытэрый уключэння ў катэгорыю",
+       "noindex-category-desc": "Старонка не індэксуецца пошукавымі робатамі, таму што на ёй ёсць магічнае слова <code><nowiki>__NOINDEX__</nowiki></code> і яна знаходзіцца ў прасторы назваў, дзе гэты сцяг дазволены.",
+       "index-category-desc": "На старонцы ёсць магічнае слова <code><nowiki>__INDEX__</nowiki></code> (і старонка знаходзіцца ў прасторы назваў, дзе гэты сцяг дазволены), таму яна індэксуецца пошукавымі робатамі у выпадках, калі гэтага звычайна не адбываецца.",
+       "post-expand-template-inclusion-category-desc": "Пасля разгортвання ўсіх шаблонаў памер старонкі перавышае <code>$wgMaxArticleSize</code>, таму некаторыя шаблоны пакінуты неразгорнутымі.",
+       "post-expand-template-argument-category-desc": "Пасля разгортвання аргумента шаблона (штосьці ў патройных фігурных дужках, напрыклад, <code>{{{Foo}}}</code>), памер старонкі перавышае <code>$wgMaxArticleSize</code>.",
+       "expensive-parserfunction-category-desc": "Занадта шмат працаёмкіх зваротаў да функцый парсера (напрыклад, <code>#ifexist</code>) уключана ў старонку. Гл. [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit].",
+       "broken-file-category-desc": "Катэгорыя дадаецца, калі старонка ўтрымлівае няспраўную спасылку на файл (спасылку на ўкладзены файл, якога няма).",
+       "hidden-category-category-desc": "Гэта катэгорыя змяшчае <code><nowiki>__HIDDENCAT__</nowiki></code>, што паводле прадвызначэння засцерагае яе ад паказу ў спісе катэгорый на старонках.",
        "trackingcategories-nodesc": "Апісанне адсутнічае.",
        "trackingcategories-disabled": "Катэгорыя адключана",
        "mailnologin": "Няма эл.адрасу",
        "protect-badnamespace-title": "Прастора імёнаў без аховы",
        "protect-badnamespace-text": "Старонкі ў гэтай прасторы імёнаў не могуць знаходзіцца пад аховай.",
        "protect-norestrictiontypes-text": "Старонка не можа ахоўвацца, таму што недаступны тыпы абмежавання.",
+       "protect-norestrictiontypes-title": "Неахоўвальная старонка",
        "protect-legend": "Пацверджанне пачатку аховы",
        "protectcomment": "Прычына:",
        "protectexpiry": "Канчаецца:",
        "immobile-target-namespace-iw": "Нельга пераносіць старонку на месца спасылкі інтэрвікі.",
        "immobile-source-page": "Нельга пераносіць гэтую старонку.",
        "immobile-target-page": "Нельга пераносіць пад гэтую назву.",
+       "bad-target-model": "Пажаданая мэта ўжывае іншую мадэль змесціва. Немагчыма пераўтварыць $1 у $2.",
        "imagenocrossnamespace": "Нельга пераносіць у не-файлавую прастору назваў",
        "nonfile-cannot-move-to-file": "Немагчыма пераназываць старонкі ў выявы",
        "imagetypemismatch": "Новы канчатак назвы файла не адпавядае яго тыпу",
        "thumbnail_image-type": "Дадзены тып выявы не падтрымліваецца",
        "thumbnail_gd-library": "Няпоўная канфігурацыя бібліятэкі GD, адсутнічае функцыя $1",
        "thumbnail_image-missing": "Хутчэй за ўсё, адсутнічае файл $1",
+       "thumbnail_image-failure-limit": "Занадта шмат няўдалых спробаў ($1 ці болей) стварыць гэту мініяцюру, за апошні час. Калі ласка, паспрабуйце пазней.",
        "import": "Імпартаваць старонкі",
        "importinterwiki": "Імпарт Transwiki",
        "import-interwiki-text": "Выбар вікі і назвы старонкі дзеля імпарту.\nДаты версій і імёны аўтараў будуць захаваныя.\nУсе транс-вікавыя імпарты запісваюцца ў [[Special:Log/import|журнале імпартаў]].",
        "import-interwiki-templates": "Разам з усімі шаблонамі",
        "import-interwiki-submit": "Імпартаваць",
        "import-interwiki-namespace": "У прастору назваў:",
+       "import-interwiki-rootpage": "Мэтавая каранёвая старонка (неабавязкова):",
        "import-upload-filename": "Назва файла:",
        "import-comment": "Каментарый:",
        "importtext": "Калі ласка, экспартуйце файл з крынічнай вікі з дапамогай [[Special:Export|прылады экспарту]].\nЗахавайце яго на свой камп'ютар, а потым загрузіце сюды.",
        "import-error-interwiki": "Старонка «$1» не была імпартаваная, таму што гэтая назва зарэзерваваная для інтэрвікі.",
        "import-error-special": "Старонка «$1» не была імпартаваная, таму што яна належыць да спецыяльнай прасторы назваў, старонкі ў якой не дазволеныя.",
        "import-error-invalid": "Старонка «$1» не была імпартаваная з-за няслушнасці назвы.",
+       "import-error-unserialize": "Немагчыма дэсерыялізаваць версію $2 старонкі \"$1\". Меркавалася, што версія выкарыстоўвае мадэль змесціва $3, серыялізавана як $4.",
+       "import-error-bad-location": "Версія $2, якая выкарыстоўвае мадэль змесціва $3, не можа быць запісана на старонцы \"$1\" гэтай вікі, паколькі такая мадэль не падтрымліваецца на гэтай старонцы.",
+       "import-options-wrong": "{{PLURAL:$2|1=Няправільны параметр|Няправільныя параметры}}: <nowiki>$1</nowiki>",
+       "import-rootpage-invalid": "Пазначаная назва каранёвай старонкі недапушчальная.",
+       "import-rootpage-nosubpage": "У прастора назваў \"$1\" каранёвай старонкі падстаронкі не дазволены.",
        "importlogpage": "Журнал імпартаванняў",
        "importlogpagetext": "Адміністрацыйныя імпартаванні старонак з іншых вікі, разам з гісторыямі правак.",
        "import-logentry-upload": "імпартавана [[$1]] праз файлавы ўклад",
        "spambot_username": "Чыстка спаму MediaWiki",
        "spam_reverting": "Вяртаемся да апошняй версіі без спасылак на $1",
        "spam_blanking": "Усе версіі ўтрымлівалі спасылкі на $1, чысцім",
+       "spam_deleting": "Усе версіі ўтрымлівалі спасылкі на $1, сціраем",
+       "simpleantispam-label": "Праверка анты-спаму.\n<strong>НЕ</strong> ўпісвайце тут нічога!",
        "pageinfo-title": "Інфармацыя для \"$1\"",
+       "pageinfo-not-current": "Выбачайце, немагчыма даць гэтыя звесткі для старых версій.",
        "pageinfo-header-basic": "Агульныя звесткі",
        "pageinfo-header-edits": "Гісторыя правак",
        "pageinfo-header-restrictions": "Ахова старонкі",
        "pageinfo-header-properties": "Уласцівасці старонкі",
        "pageinfo-display-title": "Паказаная назва",
        "pageinfo-default-sort": "Прадвызначаны ключ парадкавання",
-       "pageinfo-length": "Ð\94аÑ\9eжÑ\8bнÑ\8f старонкі (у байтах)",
+       "pageinfo-length": "Ð\90б'Ñ\91м старонкі (у байтах)",
        "pageinfo-article-id": "Ідэнтыфікатар старонкі",
        "pageinfo-language": "Мова змесціва старонкі",
        "pageinfo-content-model": "Мадэль змесціва старонкі",
        "pageinfo-authors": "Агульная колькасць розных аўтараў",
        "pageinfo-recent-edits": "Колькасць нядаўніх правак (за апошнія $1)",
        "pageinfo-recent-authors": "Колькасць аўтараў за апошні час",
+       "pageinfo-magic-words": "{{PLURAL:$1|1=Магічнае слова|Магічныя словы}} ($1)",
        "pageinfo-hidden-categories": "Схаван{{PLURAL:$1|ая катэгорыя|ыя катэгорыі}} ($1)",
        "pageinfo-templates": "Выкарыстаны {{PLURAL:$1|шаблон|шаблоны}} ($1)",
        "pageinfo-transclusions": "Выкарыстаны на {{PLURAL:$1|старонцы|старонках}} ($1)",
        "file-info-size-pages": "$1 × $2 пікселяў, памер файла: $3, MIME-тип: $4, $5 {{PLURAL:$5|старонка|старонкі|старонак}}",
        "file-nohires": "Без версіі ў лепшым разрозненні.",
        "svg-long-desc": "файл SVG, намінальна $1 × $2 кропак, аб'ём файла: $3",
+       "svg-long-desc-animated": "Анімаваны файл SVG, намінальна $1 × $2 кропак, аб'ём файла: $3",
        "svg-long-error": "Няспраўны файл SVG: $1",
        "show-big-image": "Арыгінальны файл",
        "show-big-image-preview": "Памер пры папярэднім праглядзе: $1.",
        "file-info-png-looped": "бясконца",
        "file-info-png-repeat": "паўтараецца $1 {{PLURAL:$1|раз|разоў}}",
        "file-info-png-frames": "$1 {{PLURAL:$1|кадр|кадраў}}",
+       "file-no-thumb-animation": "<strong>Заўвага: З-за тэхнічных абмежаванняў мініяцюры гэтага файла не будуць анімаванымі.</strong>",
+       "file-no-thumb-animation-gif": "<strong>Заўвага: З-за тэхнічных абмежаванняў мініяцюры файлаў GIF высокага разрознення, такіх як гэты, ствараюцца без анімацыі.</strong>",
        "newimages": "Новыя файлы",
        "imagelisttext": "Ніжэй даецца спіс з '''$1''' {{PLURAL:$1|файла|файлаў}} у парадку $2.",
        "newimages-summary": "Тут паказаныя нядаўна ўкладзеныя файлы.",
        "imgmultigo": "Пераход!",
        "imgmultigoto": "На старонку $1",
        "img-lang-default": "(прадвызначаная мова)",
+       "img-lang-info": "Паказаць гэту выяву на мове $1. $2",
+       "img-lang-go": "Перайсці",
        "ascending_abbrev": "да больш.",
        "descending_abbrev": "да менш.",
        "table_pager_next": "Наступная старонка",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|размовы]])",
        "unknown_extension_tag": "Невядомая метка пашырэння \"$1\"",
        "duplicate-defaultsort": "Увага: прадвызначаная клавіша ўпарадкавання \"$2\" замяніла ранейшую такую клавішу \"$1\".",
+       "duplicate-displaytitle": "<strong>Папярэджанне:</strong> Паказаная назва \"$2\" перасягае ранейшую назву \"$1\".",
        "version": "Версія",
        "version-extensions": "Устаноўленыя прыстаўкі",
        "version-skins": "Устаноўленыя вокладкі",
        "version-ext-colheader-credits": "Аўтары",
        "version-license-title": "Ліцэнзія $1",
        "version-license-not-found": "Не знойдзена падрабязнай інфармацыі аб ліцэнзіі для гэтай прыстаўкі.",
+       "version-credits-title": "Спіс аўтараў $1",
+       "version-credits-not-found": "Для гэтай прыстаўкі не знойдзена падрабязных звестак пра аўтараў.",
        "version-poweredby-credits": "Пляцоўка працуе на '''[https://www.mediawiki.org/ MediaWiki]''', капірайт © 2001-$1 $2.",
        "version-poweredby-others": "іншыя",
        "version-poweredby-translators": "перакладчыкі translatewiki.net",
+       "version-credits-summary": "Мы хацелі б адзначыць наступных асоб, якія зрабілі ўнёсак у [[Special:Version|MediaWiki]].",
        "version-license-info": "MediaWiki з'яўляецца свабодным праграмным забеспячэннем. Такім чынам, вы можаце паўторна распаўсюджваць прадукт і(або) змяняць яго на ўмовах пагаднення GNU General Public License у тым выглядзе, у якім яно публікуецца фондам Free Software Foundation; сілу мае версія (выпуск) 2 гэтага пагаднення або, на ваш выбар, навейшая версія (выпуск) пагаднення.\n\nMediaWiki распаўсюджваецца, спадзеючыся на прыдатнасць прадукта, але БЕЗ ЯКІХ-НЕБУДЗЬ ГАРАНТЫЙ, у тым ліку, без імплікаваных гарантый СПАЖЫВЕЦКАЙ ВАРТАСЦІ або ПРЫДАТНАСЦІ ДЛЯ ЯКОЙ-НЕБУДЗЬ МЭТЫ. Больш падрабязна гл. пагадненне GNU General Public License.\n\nРазам з гэтым праграмным забеспячэннем вы павінны былі атрымаць [{{SERVER}}{{SCRIPTPATH}}/COPYING копію пагаднення GNU General Public License]. Калі гэта не так, паведамце аб гэтым у фонд Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA або [//www.gnu.org/licenses/old-licenses/gpl-2.0.html атрымайце яе з Інтэрнэту].",
        "version-software": "Устаноўленыя праграмныя прадукты",
        "version-software-product": "Прадукт",
        "version-software-version": "Версія",
+       "version-entrypoints": "Уваходныя адрасы",
        "version-entrypoints-header-entrypoint": "Кропка ўваходу",
        "version-entrypoints-header-url": "URL",
        "redirect": "Перасылка да файла, ID удзельніка, старонкі ці версіі",
        "htmlform-selectorother-other": "Рознае",
        "htmlform-no": "Не",
        "htmlform-yes": "Так",
+       "htmlform-chosen-placeholder": "Выберыце параметр",
        "htmlform-cloner-create": "Дадаць яшчэ",
        "htmlform-cloner-delete": "Сцерці",
        "htmlform-cloner-required": "Неабходна хаця б адно значэнне.",
        "duration-millennia": "$1 {{PLURAL:$1|тысячагоддзе|тысячагоддзі|тысячагоддзяў}}",
        "rotate-comment": "Выява павернута на $1 {{PLURAL:$1|градус|градусы|градусаў}} па гадзіннікавай стрэлцы",
        "limitreport-title": "Звесткі прафілявання парсера:",
+       "limitreport-cputime": "Выкарыстанне часу ЦП",
        "limitreport-cputime-value": "$1 {{PLURAL:$1|секунда|секунды|секундаў}}",
+       "limitreport-walltime": "Выкарыстанне рэальнага часу",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|секунда|секунды|секундаў}}",
+       "limitreport-ppvisitednodes": "Колькасць вузлоў, наведаных прэпрацэсарам",
+       "limitreport-ppgeneratednodes": "Колькасць вузлоў, створаных прэпрацэсарам",
+       "limitreport-postexpandincludesize": "Памер уключэнняў па разгортванні",
        "limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|байт|байты|байтаў}}",
        "limitreport-templateargumentsize": "Памер аргументаў шаблона",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|байт|байты|байтаў}}",
        "limitreport-expensivefunctioncount": "Колькасць працаёмкіх зваротаў да функцый парсера",
        "expandtemplates": "Разгортванне шаблонаў",
        "expand_templates_intro": "Гэта адмысловая старонка бярэ тэкст і разгортвае ў ім усе шаблоны рэкурсіўна.\nТаксама разгортвае падтрыманыя функцыі парсера кшталту\n<code><nowiki>{{</nowiki>#language:…}}</code> і зменныя віду\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nФактычна, яна разгортвае ў пэўнай ступені ўсё ў двайных фігурных дужках.",
+       "expand_templates_title": "Загаловак старонкі, для {{FULLPAGENAME}} і г.д.:",
        "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> з выніку",
+       "expand_templates_generate_xml": "Паказаць дрэва сінтаксічнага аналізу XML",
        "expand_templates_generate_rawhtml": "Паказаць зыходны код HTML",
        "expand_templates_preview": "Перадпаказ",
+       "pagelanguage": "Выбар мовы старонкі",
        "pagelang-name": "Старонка",
        "pagelang-language": "Мова",
        "pagelang-use-default": "Прадвызначаная мова",
        "pagelang-select-lang": "Выберыце мову",
        "right-pagelang": "Змяняць мову старонкі",
        "action-pagelang": "змяняць мову старонкі",
+       "log-name-pagelang": "Журнал змянення мовы",
        "log-description-pagelang": "Гэта журнал змяненняў у мовах старонкі.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|змяніў|змяніла}} мову старонкі $3 з $4 на $5."
 }
index 2231bd2..8767a1b 100644 (file)
        "tog-hidepatrolled": "हाल के परिवर्तन में मामूली संपादन छुपाईं",
        "tog-newpageshidepatrolled": "नयका पृष्ठ के सूची में से जाँचल पृष्क के छुपाँई",
        "tog-extendwatchlist": "मात्र हाल के परिवर्तन ही नाही,बल्कि सब परिवर्तन के देखावे खातिर ध्यान सूची के विस्तारित करीं",
-       "tog-usenewrc": "तà¥\81रà¤\82त à¤­à¤\88ल à¤ªà¤°à¤¿à¤µà¤°à¥\8dतन à¤\86 à¤§à¥\8dयानसà¥\82à¤\9aà¥\80 à¤ªà¤°à¤¿à¤µà¤°à¥\8dतनà¥\8bà¤\82 à¤\95à¥\87 à¤ªà¤¨à¥\8dना à¤\95à¥\87 à¤\85नà¥\81सार à¤¸à¤®à¥\82ह à¤®à¥\87à¤\82 à¤¬à¤¾à¤\81à¤\9fà¥\80 (à¤\9cावासà¥\8dà¤\95à¥\8dरिपà¥\8dà¤\9f à¤\86वशà¥\8dयà¤\95)",
+       "tog-usenewrc": "तà¥\81रà¤\82त à¤­à¤\88ल à¤ªà¤°à¤¿à¤µà¤°à¥\8dतन à¤®à¥\87à¤\82 à¤\86 à¤§à¥\8dयानसà¥\82à¤\9aà¥\80 à¤®à¥\87à¤\82 à¤­à¤\88ल à¤ªà¤°à¤¿à¤µà¤°à¥\8dतनन à¤\95à¥\87 à¤ªà¤¨à¥\8dना à¤\85नà¥\81सार à¤¸à¤®à¥\82ह à¤®à¥\87à¤\82 à¤¬à¤¾à¤\82à¤\9fà¥\80",
        "tog-numberheadings": "स्वयं-सांख्यिकी शिर्षक",
-       "tog-showtoolbar": "समà¥\8dपादन à¤\94à¤\9cारà¥\8d à¤¬à¤\95à¥\8dसा à¤\95à¥\87 à¤¦à¤¿à¤\96ाà¤\87लà¥\8d à¤\9cाà¤\8f",
-       "tog-editondblclick": "दà¥\81à¤\88 à¤\95à¥\8dलिà¤\95 à¤ªà¤° à¤ªà¥\83षà¥\8dठ à¤¸à¤\82पादित à¤\95रà¥\80à¤\82 (à¤\9cावासà¥\8dà¤\95à¥\8dरिपà¥\8dà¤\9f à¤\86वशà¥\8dयà¤\95 à¤¬à¤¾)",
-       "tog-editsectiononrightclick": "अनुभाग शीर्षक पर दायाँ क्लिक कर अनुभाग सम्पादित करीं (जावास्क्रिप्ट आवश्यक बा)",
+       "tog-showtoolbar": "समà¥\8dपादन à¤\94à¤\9cारपà¤\9fà¥\8dà¤\9fà¥\80 à¤\95à¥\87 à¤¦à¤¿à¤\96ावल à¤\9cाव",
+       "tog-editondblclick": "दà¥\81à¤\88 à¤\95à¥\8dलिà¤\95 à¤ªà¤° à¤ªà¤¨à¥\8dना à¤¸à¤\82पादन à¤\95रà¥\80à¤\82",
+       "tog-editsectiononrightclick": "अनुभाग शीर्षक पर दायाँ क्लिक कर अनुभाग सम्पादित करीं",
        "tog-watchcreations": "हमरा द्वारा निर्मित पृष्ठ आ हमरा द्वारा लादल फ़ाइलन के हमार ध्यानसूची में जोड़ी",
        "tog-watchdefault": "हमरा द्वारा निर्मित पृष्ठ आ हमरा द्वारा लादल फ़ाइलन के हमार ध्यानसूची में जोड़ी",
        "tog-watchmoves": "हमरा द्वारा स्थानांतरित पृष्ठ आ लादल फाईल के हमरा ध्यानसूची में जोड़ी",
@@ -31,7 +31,7 @@
        "tog-shownumberswatching": "ध्यान रखे वालन सदस्यन के देखावल जाव",
        "tog-oldsig": "वर्तमान हस्ताक्षर:",
        "tog-fancysig": "हस्ताक्षर के विकी पाठ के रुप में उपयोग करीं (बिना स्वचालित कड़ी के)",
-       "tog-uselivepreview": "लाà¤\88व à¤ªà¥\81रà¥\8dवालà¥\8bà¤\95न à¤\95à¥\87 à¤ªà¥\8dरयà¥\8bà¤\97 à¤\95रà¥\80à¤\82 (à¤\9cावासà¥\8dà¤\95à¥\8dरिपà¥\8dà¤\9f à¤¹à¥\8bà¤\96à¥\87 à¤\95à¥\87 à¤\9aाहà¥\80à¤\82) (पà¥\8dरयà¥\8bà¤\97à¤\95à¥\8dषम)",
+       "tog-uselivepreview": "लाà¤\87व à¤ªà¥\81रà¥\8dवालà¥\8bà¤\95न à¤\95à¥\87 à¤ªà¥\8dरयà¥\8bà¤\97 à¤\95रà¥\80à¤\82 (पà¥\8dरयà¥\8bà¤\97ातà¥\8dमà¤\95)",
        "tog-forceeditsummary": "यदि सम्पादन सारांश ना दिहल होखे त हमके सूचित करब",
        "tog-watchlisthideown": "हमार ध्यान दिहल पन्ना के सूची से हमरा खातिर परिवर्तन छिपाईं",
        "tog-watchlisthidebots": "हमार ध्यान सूची से बोट द्वारा करल गईल परिवर्तन के छिपाईं",
        "category-empty": "''इ श्रेणी में इ समय कउनो पन्ना या मीडिया नइखे।''",
        "hidden-categories": "{{PLURAL:$1|छुपावल गईल श्रेणी|छुपावल गईल श्रेणीं}}",
        "hidden-category-category": "छुपावल गइल श्रेणीं",
-       "category-subcat-count": "{{PLURAL:$2|à¤\87 à¤¶à¥\8dरà¥\87णà¥\80 à¤®à¥\87à¤\82 à¤®à¤¾à¤¤à¥\8dर à¤¨à¤¿à¤®à¥\8dनलिà¤\96ित à¤\89पशà¥\8dरà¥\87णà¥\80 à¤¬à¤¾|à¤\87 à¤¶à¥\8dरà¥\87णà¥\80 à¤®à¥\87à¤\82 à¤¨à¤¿à¤®à¥\8dनलिà¤\96ित {{PLURAL:$1|à¤\89पशà¥\8dरà¥\87णà¥\80|$1 à¤\89पशà¥\8dरà¥\87णà¥\80याà¤\82}} à¤¬à¤¾à¤¡à¤¼à¥\87, à¤\95à¥\81ल à¤\89पशà¥\8dरà¥\87णà¥\80याà¤\82 $2 à¤¬à¤¾à¤¡à¤¼à¥\87।}}",
+       "category-subcat-count": "{{PLURAL:$2|à¤\87 à¤¶à¥\8dरà¥\87णà¥\80 à¤®à¥\87à¤\82 à¤®à¤¾à¤¤à¥\8dर à¤¨à¤¿à¤®à¥\8dनलिà¤\96ित à¤\89पशà¥\8dरà¥\87णà¥\80 à¤¬à¤¾|à¤\87 à¤¶à¥\8dरà¥\87णà¥\80 à¤®à¥\87à¤\82 à¤¨à¤¿à¤®à¥\8dनलिà¤\96ित {{PLURAL:$1|à¤\89पशà¥\8dरà¥\87णà¥\80|$1 à¤\89पशà¥\8dरà¥\87णियाà¤\82}} à¤¬à¤¾à¤¡à¤¼à¥\87, à¤\95à¥\81ल à¤\89पशà¥\8dरà¥\87णियाà¤\81$2}}",
        "category-subcat-count-limited": "इ श्रेणी में निम्नलिखित {{PLURAL:$1|उपश्रेणी बा|$1 उपश्रेणीं बाड़े}}।",
-       "category-article-count": "{{PLURAL:$2|इ श्रेणी में मात्र निम्नलिखित पन्ना बा।|इ श्रेणी में निम्नलिखित {{PLURAL:$1|पन्ना बा|$1 पन्नें}}, कुल पन्नें $2 बाड़े।}}",
+       "category-article-count": "{{PLURAL:$2|इ श्रेणी में मात्र निम्नलिखित पन्न बा।|इ श्रेणी में निम्नलिखित {{PLURAL:$1|पन्ना बा|$1 पन्ना बाड़े}, कुल पन्ना $2}}",
        "category-article-count-limited": "निम्नलिखित {{PLURAL:$1|पन्ना|$1 पन्ना}} इ श्रेणीं में बा।",
        "category-file-count": "{{PLURAL:$2|इ श्रेणी में मात्र निम्नलिखित फ़ाइल बा।|इ श्रेणी में निम्नलिखित {{PLURAL:$1|फ़ाइल|$1 फ़ाइलं}} बाड़े, कुल फ़ाइलं $2}}",
        "category-file-count-limited": "वर्तमान में निम्नलिखित {{PLURAL:$1|पन्ना|$1 पन्नां}} इ श्रेणीं में बाड़े।",
        "newwindow": "(नया विंडो में खोलीं)",
        "cancel": "निरस्त",
        "moredotdotdot": "अउर...",
-       "morenotlisted": "à¤\85धिà¤\95 à¤¸à¥\82à¤\9aà¥\80बदà¥\8dध à¤¨à¤\87à¤\96à¥\87...",
+       "morenotlisted": "à¤\87 à¤¸à¥\82à¤\9aà¥\80 à¤ªà¥\82रà¥\8dण à¤¨à¤\87à¤\96à¥\87।",
        "mypage": "पन्ना",
        "mytalk": "राउर बात",
        "anontalk": "इ आइ॰पी खातिर वार्ता",
        "permalink": "स्थायी लिंक",
        "print": "छापीं",
        "view": "देखीं",
+       "view-foreign": "$1 पर देखीं",
        "edit": "सम्पादन",
+       "edit-local": "क्षेत्रीय विवरण देखीं",
        "create": "बनाईं",
+       "create-local": "क्षेत्रीय विवरण जोड़ीं",
        "editthispage": "ई पन्ना के सम्पादन करीं",
        "create-this-page": "ई पन्ना के निर्माण करीं",
        "delete": "मिटाईं",
        "talkpagelinktext": "बात-चीत",
        "specialpage": "ख़ाश पन्ना",
        "personaltools": "ब्यक्तिगत औजार",
-       "postcomment": "नया खण्ड",
        "articlepage": "सामग्री पन्ना देखीं",
        "talk": "बात-चीत",
        "views": "विचारसूची",
-       "toolbox": "à¤\94à¤\9cार-पà¥\87à¤\9fà¥\80",
+       "toolbox": "à¤\89पà¤\95रण",
        "userpage": "प्रयोगकर्ता पन्ना देखीं",
        "projectpage": "परियोजना पन्ना देखीं",
        "imagepage": "फाईल पन्ना देखीँ",
        "jumptonavigation": "परिभ्रमण",
        "jumptosearch": "खोजीं",
        "view-pool-error": "क्षमा करीं, ई समय सर्वर पर बहुत ज्यादा लोड बढ़ गईल बा।\nई पन्ना के बहुते प्रयोगकर्ता लोग देखे के कोशिश कर रहल बानी।\nई पन्ना के फिर से देखे से पहिले कृपया कुछ देर तक इन्तजार करीं।\n\n$1",
+       "generic-pool-error": "क्षमा करीं, ई समय सर्वर पर बहुत ज्यादा लोड बढ़ गईल बा।\nई संसाधन के बहुते प्रयोगकर्ता लोग देखे के कोशिश कर रहल बानी।\nई संसाधन तक पहुँच बनावे के कोशिश से पहिले कृपया कुछ देर तक इन्तजार करीं।",
        "pool-timeout": "तालाबन्दी खातिर प्रतीक्षा समय समाप्त",
        "pool-queuefull": "पूल पंक्ति भर गइल",
        "pool-errorunknown": "अज्ञात त्रुटि",
+       "pool-servererror": "पूल काउंटर सेवा उपलब्ध नाही बा ($1)।",
        "aboutsite": "{{SITENAME}} के बारे में",
        "aboutpage": "Project:बारे में",
-       "copyright": "सामà¤\97à¥\8dरà¥\80 $1 à¤\95à¥\87 à¤¤à¤¹à¤¤ à¤\89पलबà¥\8dध à¤¬à¤¾।",
+       "copyright": "à¤\89पलबà¥\8dध à¤¸à¤¾à¤®à¤\97à¥\8dरà¥\80 $1 à¤\95à¥\87 à¤\85धà¥\80न à¤\89पलबà¥\8dध à¤¬à¤¾ à¤\9cब à¤¤à¤\95 à¤\95à¥\80 à¤\85लà¤\97 à¤¸à¥\87 à¤\89लà¥\8dलà¥\87à¤\96 à¤¨à¤¾ à¤\95रल à¤\97à¤\88ल à¤¹à¥\8bà¤\96à¥\87 ।",
        "copyrightpage": "{{ns:project}}:लेखाधिकार",
        "currentevents": "हाल के घटना",
        "currentevents-url": "Project:हाल के घटना",
        "youhavenewmessages": "रउआ लगे बा $1 ($2).",
        "youhavenewmessagesfromusers": "रउआ खातिर {{PLURAL:$3|एगो अन्य सदस्य|$3 अन्य सदस्यन}} के $1 बा। ($2)",
        "youhavenewmessagesmanyusers": "रउआ खातिर कई सदस्यन द्वारा $1 बा। ($2)",
-       "newmessageslinkplural": "{{PLURAL:$1|à¤\8fà¤\97à¥\8b à¤¨à¤¯à¤¾ à¤¸à¤¨à¥\8dदà¥\87श à¤¬à¤¾|नया à¤¸à¤¨à¥\8dदà¥\87श à¤¬à¤¾à¤¡à¤¼à¤¨}}",
-       "newmessagesdifflinkplural": "{{PLURAL:$1|पिछला|पिछलका}} बदलाव",
+       "newmessageslinkplural": "{{PLURAL:$1|à¤\8fà¤\95 à¤¨à¤¯à¤¾ à¤¸à¤¨à¥\8dदà¥\87श|999=नयà¤\95ा à¤¸à¤¨à¥\8dदà¥\87श}}",
+       "newmessagesdifflinkplural": "पिछला {{PLURAL:$1|बदलाव|999=बदलावं}}",
        "youhavenewmessagesmulti": "रउआ लगे $1 पर नया सन्देश बा",
        "editsection": "सम्पादन",
        "editold": "सम्पादन",
        "nospecialpagetext": "<strong>रउआ एगो अवैद्य विशेष पन्ना के अनुरोध कईले बानी।</strong>\n\nवैद्य विशेष पन्ना के सूची मिल सकत बा [[Special:SpecialPages|{{int:specialpages}}]] पर।",
        "error": "त्रुटी",
        "databaseerror": "डेटाबेस त्रुटी",
+       "databaseerror-text": "डाटाबेस अनुरोध त्रुटि  भइल बा।\nसंभवतः सॉफ़्टवेयर में गड़बड़ी बा।",
+       "databaseerror-textcl": "डाटाबेस अनुरोध त्रुटि उत्त्पन्न हो गईल बा।",
+       "databaseerror-query": "अनुरोध: $1",
+       "databaseerror-function": "फ़ंक्शन: $1",
+       "databaseerror-error": "त्रुटि: $1",
        "laggedslavemode": "'''चेतावनी:''' इ पन्ना पर हाल के बदलाव ना होखे के आशंका बा।",
        "readonly": "डेटाबेस लॉक बा",
        "enterlockreason": "लॉक करे के कारण दिहीं, साथे लॉक खुले के समय के लगभग आकलन दिहीं।",
        "invalidtitle-knownnamespace": "\"$2\" नामस्थान आ \"$3\" पाठ्य वाला गलत शीर्षक",
        "invalidtitle-unknownnamespace": "अज्ञात नामस्थान संख्या $1 आ नाम \"$2\" वाला गलत शीर्षक",
        "exception-nologin": "खाता में प्रवेश नईखीं भईल",
-       "exception-nologin-text": "इ पन्ना अथवा कार्य खातिर रउआ विकि प्रवेश (लॉग इन) होना आवश्यक है।",
+       "exception-nologin-text": "इ पन्ना अथवा कार्य के सक्षम करे खातिर कृपया [[Special:Userlogin|लॉग इन]] करीं।",
+       "exception-nologin-text-manual": "इ पन्ना अथवा कार्य के सक्षम करे खातिर कृपया $1 करीं।",
        "virus-badscanner": "गलत जमाव: अज्ञात वायरस जाँचक: ''$1''",
        "virus-scanfailed": "जाँच विफल (कोड $1)",
        "virus-unknownscanner": "अज्ञात ऐंटीवायरस:",
        "externaldberror": "या त प्रमाणिकरण डाटाबेस में भइल बा या फिर रउआ के आपन बाह्य खाता अपडेट करे के अनुमति नइखे।",
        "login": "खाता में प्रवेश",
        "nav-login-createaccount": "खाता प्रवेश / खाता बनाईं",
-       "loginprompt": "{{SITENAME}} में प्रवेश खातिर राउर कुकिज चालू होवे के चाहीं",
        "userlogin": "खाता प्रवेश / खाता बनाईं",
        "userloginnocreate": "खाता में प्रवेश",
        "logout": "खाता से बाहर",
        "gotaccount": "का पहिले से एगो खाता बा? $1.",
        "gotaccountlink": "खाता में प्रवेश",
        "userlogin-resetlink": "का रउआ आपन प्रवेश जानकारी भूला गइल बानी?",
-       "userlogin-resetpassword-link": "आपन गुप्तशब्द के फिर से बहाल करीं",
+       "userlogin-resetpassword-link": "आपन गुप्तशब्द भूला गईनी का?",
+       "userlogin-helplink2": "खाता प्रवेश साथ मदद",
+       "userlogin-loggedin": "रउआ {{GENDER:$1|$1}} के रूप में पहिले से लॉग्ड इन बानीं।\nकौनो अन्य सदस्य के रूप में लॉग इन करे खातिर निम्नलिखित फ़ॉर्म के प्रयोग करीं।",
+       "userlogin-createanother": "एगो दोसर खाता बनाईं",
        "createacct-emailrequired": "ई-मेल पता",
        "createacct-emailoptional": "ई-मेल पता (वैकल्पिक)",
        "createacct-email-ph": "आपन ई-मेल पता लिखीं",
        "passwordtooshort": "गुप्त-शब्द कम से कम {{PLURAL:$1|1 अक्षर|$1 अक्षर}} के होवे के चाहीं।",
        "password-name-match": "राउर गुप्त-शब्द राउर प्रयोगकर्ता नाम से अलग होवे के चाहीं।",
        "password-login-forbidden": "इस सदस्यनाम आ गुप्तशब्द के प्रयोग वर्जित बा।",
-       "mailmypassword": "नया à¤\97à¥\81पà¥\8dत-शबà¥\8dद à¤\88-मà¥\87ल à¤ªà¤° à¤­à¥\87à¤\9cीं",
+       "mailmypassword": "à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤°à¤¿à¤¸à¥\87à¤\9f à¤\95रीं",
        "passwordremindertitle": "{{SITENAME}} खातिर नया अस्थायी गुप्त-शब्द",
        "passwordremindertext": "केहु (शायद रउए, $1 आइ॰पी पता से) {{SITENAME}} ($4) पर प्रयोग खातिर नया गुप्तशब्द के निवेदन कईले बानी। सदस्य \"$2\" खातिर एगो अस्थायी गुप्तशब्द बना दिहल गईल बा, आ ई अभी \"$3\" बा। यदि ई राउरे आशय रहल, त अब रउआ खाता प्रवेश खातिर एगो नया गुप्तशब्द चुने के पड़ी।\nराउर अस्थायी गुप्तशब्द के अवधि {{PLURAL:$5|एक दिन|$5 दिनं}} में समाप्त हो जाई।\n\nयदि इ निवेदन केहु अउर कइले रहल, या रउआ आपन पुरान गुप्तशब्द अब नइखी बदले के चाहत काहे कि रउआ राउर पुरनका गुप्तशब्द के स्मरण हो आइल बा, त रउआ इ संदेश के अनदेखा कर सकत बानी, आ आपन पुरान गुप्तशब्द के प्रयोग पहिले हि जइसन कर सकत बानी।",
        "noemail": "\"$1\" सदस्य खातिर कउनो भी ई-मेल पता दर्ज नइखे करल गइल।",
        "noemailcreate": "रउआ एगो जायज ई-मेल पता उपलब्ध करावे के पड़ी।",
        "passwordsent": "\"$1\" के ई-मेल पता पर एगो नया गुप्तशब्द भेज दिहल गइल बा।\nई-मेल पावे के बाद कृपया दुबारा खाता में प्रवेश करब।",
        "blocked-mailpassword": "राउर आइ॰पी पता के सम्पादन करे से वंचित कर दिहल गइल बा, आ गलत प्रयोग रोके खातिर गुप्तशब्द पुनः प्राप्ति के सुविधा इ आइ॰पी पर बंद कर दिहल गइल बा।",
-       "eauthentsent": "दरà¥\8dà¤\9c à¤\95रावल à¤\97à¤\87ल à¤\88-मà¥\87ल à¤ªà¤¤à¤¾ à¤ªà¤° à¤\8fà¤\97à¥\8b à¤ªà¥\81षà¥\8dà¤\9fिà¤\95रण à¤\88-मà¥\87ल à¤­à¥\87à¤\9c à¤¦à¤¿à¤¹à¤² à¤\97à¤\87ल à¤¬à¤¾à¥¤\nरà¤\89à¤\86 à¤\89 à¤\88-मà¥\87ल à¤ªà¤° à¤¦à¤¿à¤¹à¤² à¤\97à¤\87ल à¤¨à¤¿à¤°à¥\8dदà¥\87श à¤\95à¥\87 à¤\85नà¥\81सरण à¤\95र à¤\95à¥\87 à¤\88-मà¥\87ल à¤ªà¤¤à¤¾ à¤\95à¥\87 à¤ªà¥\81षà¥\8dà¤\9fिà¤\95रण à¤\95रावà¥\87 à¤\95à¥\87 à¤ªà¤¡à¤¼à¥\80, à¤\93à¤\95रा à¤¬à¤¾à¤¦à¥\87 à¤\85हिà¤\9cा à¤¸à¥\87 à¤\95à¤\89नà¥\8b à¤¦à¥\82सर à¤\88-मà¥\87ल à¤­à¥\87à¤\9cल à¤\9cाà¤\88।",
+       "eauthentsent": "दरà¥\8dà¤\9c à¤\95रावल à¤\97à¤\87ल à¤\88-मà¥\87ल à¤ªà¤¤à¤¾ à¤ªà¤° à¤\8fà¤\97à¥\8b à¤ªà¥\81षà¥\8dà¤\9fिà¤\95रण à¤\88-मà¥\87ल à¤­à¥\87à¤\9c à¤¦à¤¿à¤¹à¤² à¤\97à¤\87ल à¤¬à¤¾à¥¤\nà¤\89 à¤\96ाता à¤ªà¤° à¤\95à¥\8cनà¥\8b à¤¦à¥\81सर à¤\88मà¥\87ल à¤­à¥\87à¤\9cल à¤\9cाà¤\93 à¤\89 à¤¸à¥\87 à¤ªà¤¹à¤¿à¤²à¥\87, à¤°à¤\89à¤\86 à¤­à¥\87à¤\9cल à¤\97à¤\88ल à¤\88-मà¥\87ल à¤ªà¤° à¤¦à¤¿à¤¹à¤² à¤\97à¤\87ल à¤¨à¤¿à¤°à¥\8dदà¥\87श à¤\95à¥\87 à¤\85नà¥\81सरण à¤\95र à¤\95à¥\87 à¤\88-मà¥\87ल à¤ªà¤¤à¤¾ à¤\95à¥\87 à¤ªà¥\81षà¥\8dà¤\9fिà¤\95रण à¤\95रावà¥\87 à¤\95à¥\87 à¤ªà¤¡à¤¼à¥\80 à¤¤à¤¾à¤\95ि à¤ªà¤¤à¤¾ à¤\9aलà¥\87 à¤\95à¥\80 à¤¸à¤¹à¥\80 à¤®à¥\87à¤\82 à¤\89 à¤°à¤¾à¤\89रà¥\87 à¤\96ाता à¤¹।",
        "throttled-mailpassword": "पिछला {{PLURAL:$1|एक घंटा|$1 घंटा}} के अंदर एगो गुप्तशब्द पुनर्स्थापन ई-मेल भेजल जा चुकल बा।\nदुरुपयोग से बचावे खातिर {{PLURAL:$1|एक घंटा|$1 घंटा}} में सिर्फ एगो गुप्तशब्द पुनर्स्थापन ई-मेल भेजल जाई।",
        "mailerror": "ई-मेल भेजे में त्रुटि: $1",
        "acct_creation_throttle_hit": "राउर आइ॰पी पता से आईल आगंतुक पिछला चौबीस घंटा में इ विकि पर {{PLURAL:$1|एक खाता|$1 खाता}} बना चुकल बानी, इ समयावधि में इहे अधिकतम सीमा बा।\nअतः इ समय इ आइ॰पी पता के प्रयोग करे वाला आगंतुक अउर अधिक खाता नइखन बना सकत।",
-       "emailauthenticated": "राउर ई-मेल पता के पुष्ट दिनांक $2 के $3 बजे हो चुकल रहे।",
-       "emailnotauthenticated": "राउर ई-मेल पता के अभी तक प्रमाणिकरण नइखे भईल।\nनिम्नलिखित कउनो भी सुविधा खातिर रउआ ई-मेल ना भेजल जाई।",
+       "emailauthenticated": "$2 के $3 पर राउर ई-मेल पता के पुष्टीकरण हो चुकल बा।",
+       "emailnotauthenticated": "राà¤\89र à¤\88-मà¥\87ल à¤ªà¤¤à¤¾ à¤\95à¥\87 à¤\85भà¥\80 à¤¤à¤\95 à¤ªà¥\8dरमाणिà¤\95रण à¤¨à¤\87à¤\96à¥\87 à¤­à¤\88ल।\nनिमà¥\8dनलिà¤\96ित à¤\95à¤\89नà¥\8b à¤­à¥\80 à¤¸à¥\81विधा à¤\96ातिर à¤°à¤\89à¤\86 à¤\95à¥\87 à¤\95à¥\8cनà¥\8b à¤­à¥\80 à¤\88-मà¥\87ल à¤¨à¤¾ à¤­à¥\87à¤\9cल à¤\9cाà¤\88।",
        "noemailprefs": "इ सुविधा के प्रयोग करे खातिर आपन वरियता में एगो ई-मेल पता दिहीं।",
        "emailconfirmlink": "अपना ई-मेल पता कन्फर्म करीं",
        "invalidemailaddress": "राउर ई-मेल पता स्वीकार करल नइखे जा सकत काहे कि ई-मेल के जउन रुप दिखाई दे रहल बा उ गलत लागत बा।\nकृपया एगो सहि ई-मेल पता उपलब्ध कराईं या उ जगह के खाली छोड़ दिहीं।",
        "loginlanguagelabel": "भाषा: $1",
        "suspicious-userlogout": "राउर खाता से बाहर जाये के अनुरोध अस्वीकृत कर दिहल गइल बा काहे कि  अइसन लग रहल बा कि इ कउनो खराब ब्राउज़र या कैश करे वाली प्रॉक्सी द्वारा भेजल गईल रहल।",
        "createacct-another-realname-tip": "असली नाम वैकल्पिक बा।\nयदि रउआ इ के उपलब्ध करावे के चुनत बानी त, एकर प्रयोग सदस्य के ओकरा काम के अधिकार देवे खातिर होखी।",
+       "pt-login": "खाता में प्रवेश",
+       "pt-login-button": "खाता में प्रवेश",
+       "pt-createaccount": "खाता बनाईं",
+       "pt-userlogout": "खाता से बाहर",
        "php-mail-error-unknown": "PHP के mail() फ़ंक्शन में अज्ञात त्रुटि बा।",
        "user-mail-no-addy": "बिना कउनो ई-मेल पता के ई-मेल भेजे के प्रयत्न भईल बा।",
        "user-mail-no-body": "एगो खाली अथवा बहुत छोट ई-मेल भेजे के प्रयत्न भईल बा।",
        "changepassword": "गुप्त शब्द बदलीं",
-       "resetpass_announce": "रà¤\89à¤\86 à¤\88-मà¥\87ल à¤¸à¥\87 à¤ªà¥\8dरापà¥\8dत à¤\85सà¥\8dथायà¥\80 à¤\95à¥\8bड à¤¸à¥\87 à¤\96ाता à¤®à¥\87à¤\82 à¤ªà¥\8dरवà¥\87श à¤­à¤\88ल à¤¬à¤¾à¤¨à¥\80।\nà¤\96ाता à¤ªà¥\8dरवà¥\87श à¤\95à¥\87 à¤ªà¥\82रा à¤\95रà¥\87 à¤\96ातिर à¤°à¤\89à¤\86 à¤\87हाà¤\81 à¤\8fà¤\97à¥\8b à¤¨à¤¯à¤¾ à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤¦à¥\87वà¥\87 à¤\95à¥\87 à¤ªà¤¡à¤¼à¥\80:",
+       "resetpass_announce": "लà¥\89à¤\97 à¤\87न à¤¸à¤®à¥\8dपà¥\82रà¥\8dण à¤\95रà¥\87 à¤\96ातिर à¤°à¤\89à¤\86 à¤\8fà¤\97à¥\8b à¤¨à¤¯à¤¾ à¤ªà¤¾à¤¸à¤µà¤°à¥\8dड à¤¦à¥\87वà¥\87 à¤\95à¥\87 à¤¹à¥\8bà¤\88।",
        "resetpass_header": "खाता के गुप्तशब्द बदलीं",
        "oldpassword": "पुराना गुप्त-शब्द:",
        "newpassword": "नया गुप्त-शब्द:",
        "retypenew": "नया गुप्त-शब्द पुन: डालीं:",
        "resetpass_submit": "गुप्तशब्द बनाईं आ खाता में प्रवेश करीं",
        "changepassword-success": "राउर गुप्तशब्द सफलतापुर्वक बदल दिहल गईल बा!",
+       "changepassword-throttled": "रउआ हाले में कईयन बार खाता में प्रवेश करे के कोशिश कर चुकल बानी।\nकृपया $1 प्रतिक्षा करला के बाद फिर से प्रयास करब।",
        "resetpass_forbidden": "गुप्तशब्द बदलल नइखे जा सकत",
        "resetpass-no-info": "इ पन्ना के सिधे प्रयोग करे खातिर रउआ पहिले खाता में प्रवेश करे के पड़ी।",
        "resetpass-submit-loggedin": "गुप्त शब्द बदलीं",
        "resetpass-submit-cancel": "रद्द करीं",
        "resetpass-wrong-oldpass": "अवैद्य अस्थायी या वर्तमान गुप्तशब्द।\nरउआ पहिले हिं सफलतापूर्वक आपन गुप्तशब्द बदल चुकल बानी, या रउआ एगो अस्थायी गुप्तशब्द के अनुरोध कइले होखब।",
+       "resetpass-recycled": "रीसेट करे खातिर नया पासवर्ड में कृपया आपन वर्तमान पासवर्ड के अलावा कौनो अन्य पासवर्ड के प्रयोग करीं।",
+       "resetpass-temp-emailed": "अस्थाई ईमेल कोड के द्वारा रउआ लॉग इन भइल बानी।\nलॉग इन पूरा करे खातिर, रउआ एगो नया पासवर्ड सेट करे के पड़ी:",
        "resetpass-temp-password": "अस्थायी गुप्तशब्द:",
        "resetpass-abort-generic": "कउनो एक्सटेंशन द्वारा गुप्तशब्द में बदलाव रोक दिहल गईल बा।",
+       "resetpass-expired": "राउर पासवर्ड की वैधता अवधि समाप्त हो चुकल बा। कृपया लॉग इन करे खातिर एगो नया पासवर्ड सेट करीं।",
+       "resetpass-validity-soft": "राउर पासवर्ड मान्य नईखे: $1 \n\nकृपया अब एक नया पासवर्ड चुनीं, या उ के बाद में पुनर्स्थापित करे खातिर \"{{int:resetpass-submit-cancel}}\" पर क्लिक करीं।",
        "passwordreset": "गुप्तशब्द रिसेट करीं",
        "passwordreset-text-one": "आपन गुप्तशब्द के पुनर्स्थापित करे खातिर इ फॉर्म भरीं।",
-       "passwordreset-text-many": "{{PLURAL:$1|à¤\86पन à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤ªà¥\81नरà¥\8dसà¥\8dथापित à¤\95रे खातिर निम्न में से कउनो एगो स्थान भरीं।}}",
+       "passwordreset-text-many": "{{PLURAL:$1|à¤\88मà¥\87ल à¤¦à¥\8dवारा à¤\85सà¥\8dथाà¤\88 à¤ªà¤¾à¤¸à¤µà¤°à¥\8dड à¤ªà¤¾à¤µे खातिर निम्न में से कउनो एगो स्थान भरीं।}}",
        "passwordreset-legend": "गुप्तशब्द रिसेट करीं",
        "passwordreset-disabled": "इ विकी पर पासवर्ड पुनर्स्थापन अक्षम बा।",
        "passwordreset-emaildisabled": "इ विकि पर ई-मेल सुविधा अक्षम कर दिहल गईल बा।",
        "changeemail-password": "राउर {{SITENAME}} गुप्तशब्द:",
        "changeemail-submit": "ई-मेल बदलीं",
        "changeemail-cancel": "रद्द करीं",
+       "changeemail-throttled": "रउआ हाले में कईयन बार खाता में प्रवेश करे के कोशिश कर चुकल बानी।\nकृपया $1 प्रतिक्षा करला के बाद फिर से प्रयास करब।",
+       "resettokens": "टोकन रीसेट करीं",
+       "resettokens-text": "जौन टोकन राउर खाता से सम्बद्ध कुछ विशिष्ट व्यक्तिगत जानकारी प्रदान करेला, आप उ के अहिजा रीसेट कर सकत बानी।\n\nयदि रउआ ई के गलती से केहू के दिखा देले बानी या फिर राउर खाता हैक हो गईल बा त रउआ ई के रीसेट कर देवे के चाहीं।",
        "bold_sample": "मोट पाठ्य",
        "bold_tip": "मोट पाठ्य",
        "italic_sample": "इटालिक पाठ्य",
        "permissionserrors": "अनुमति त्रुटी",
        "log-fulllog": "पूरा लॉग देखीं",
        "edit-conflict": "संपादन अंतर्विरोध",
+       "postedit-confirmation-created": "पन्ना बना दिहल गईल।",
        "postedit-confirmation-saved": "राउर सम्पादन सुरक्षित कर दिहल गईल।",
        "invalid-content-data": "अवैध डाटा सामग्री",
        "content-model-wikitext": "विकीपाठ्य",
        "prefs-editing": "संपादन",
        "searchresultshead": "खोज",
        "savedprefs": "राउर वरीयताएँ सुरक्षित कर दिहल गईल।",
+       "timezoneregion-africa": "अफ़्रीका",
+       "timezoneregion-america": "अमेरिका",
+       "timezoneregion-antarctica": "अंटार्कटिका",
+       "timezoneregion-arctic": "आर्कटिक",
        "timezoneregion-asia": "एशिया",
+       "timezoneregion-atlantic": "एटलांटिक महासागर",
        "timezoneregion-australia": "अस्ट्रेलिया",
        "timezoneregion-europe": "यूरोप",
        "timezoneregion-indian": "हिंद महासागर",
        "yourrealname": "असली नाम",
        "yourlanguage": "भाषा:",
        "prefs-preview": "पूर्वावलोकन",
+       "action-move": "ई पन्ना के स्थांतरण करीं",
+       "action-delete": "ई पन्ना के मिटाईं",
        "recentchanges": "तुरंत भईल परिवर्तन",
        "recentchanges-legend": "हाल के परिवर्तन संबंधी विकल्प",
        "recentchanges-label-newpage": "ई सम्पादन से एगो नवका पृष्ठ तैयार हो गइल बा",
        "recentchanges-label-minor": "ई एगो छोटा सम्पाद बा",
+       "recentchanges-legend-heading": "'''कुंजी:'''",
        "rcshowhideminor": "$1 छोट सम्पादन",
+       "rcshowhideminor-show": "दिखाईं",
+       "rcshowhideminor-hide": "छुपाँई",
        "diff": "अन्तर",
        "hist": "इति",
        "hide": "छुपाँई",
        "recentchangeslinked": "सम्बन्धित बदलाव",
        "recentchangeslinked-feed": "सम्बन्धित बदलाव",
        "recentchangeslinked-toolbox": "सम्बन्धित बदलाव",
+       "recentchangeslinked-page": "पन्ना नाम:",
        "upload": "फाईल लादीं",
+       "filedesc": "सारांश",
+       "fileuploadsummary": "सारांश:",
+       "filesource": "स्रोत:",
+       "unknown-error": "अज्ञात त्रुटि उत्पन्न हो गईल बा।",
        "file-anchor-link": "फ़ाइल",
        "filehist": "पन्ना के इतिहास",
        "filehist-deleteall": "सब मिटाईं",
index 434cf28..07a5a29 100644 (file)
        "talkpagelinktext": "আলোচনা",
        "specialpage": "বিশেষ পাতা",
        "personaltools": "নিজস্ব সরঞ্জামসমূহ",
-       "postcomment": "নতুন অনুচ্ছেদ",
        "articlepage": "নিবন্ধ দেখুন",
        "talk": "আলোচনা",
        "views": "দৃষ্টিকোণ",
        "externaldberror": "হয় কোন বহিঃস্থ যাচাইকরণ ডাটাবেজ ত্রুটি ঘটেছে অথবা আপনার বহিঃস্থ অ্যাকাউন্ট হালনাগাদ করার অনুমতি নেই।",
        "login": "প্রবেশ",
        "nav-login-createaccount": "প্রবেশ/নতুন অ্যাকাউন্ট",
-       "loginprompt": "{{SITENAME}}-তে প্রবেশ করতে হলে আপনার ব্রাউজারের কুকি অবশ্যই সক্রিয় করতে হবে।",
        "userlogin": "প্রবেশ/নতুন অ্যাকাউন্ট",
        "userloginnocreate": "প্রবেশ",
        "logout": "প্রস্থান করুন",
        "license-nopreview": "(প্রাকদর্শন লভ্য নয়)",
        "upload_source_url": " (একটি বৈধ, উন্মুক্ত URL)",
        "upload_source_file": " (আপনার কম্পিউটারের একটি ফাইল)",
+       "listfiles-delete": "অপসারণ",
        "listfiles-summary": "এই বিশেষ পাতাটি আপলোড করা সকল ফাইল প্রদর্শন করে।",
        "listfiles_search_for": "ছবির নাম অনুসন্ধান:",
        "imgfile": "ফাইল",
        "expand_templates_remove_nowiki": "ফলাফলে <nowiki> ট্যাগগুলো বাতিল করো",
        "expand_templates_generate_xml": "XML পার্স বৃক্ষ দেখাও",
        "expand_templates_generate_rawhtml": "এইচটিএমএল দেখাও",
-       "expand_templates_preview": "প্রাকদর্শন"
+       "expand_templates_preview": "প্রাকদর্শন",
+       "pagelanguage": "পাতার ভাষা নির্বাচক",
+       "pagelang-name": "পাতা",
+       "pagelang-language": "ভাষা",
+       "pagelang-use-default": "ডিফল্ট ভাষা ব্যবহার করুন",
+       "pagelang-select-lang": "ভাষা নির্বাচন করুন",
+       "right-pagelang": "পাতার ভাষা পরিবর্তন করুন",
+       "action-pagelang": "পাতার ভাষা পরিবর্তন করুন",
+       "log-name-pagelang": "ভাষা পরিবর্তন লগ",
+       "log-description-pagelang": "এটি পাতার ভাষা পরিবর্তনের লগ।",
+       "logentry-pagelang-pagelang": "$1 পাতার ভাষা $3 এর জন্য $4 থেকে $5 এ {{GENDER:$2|পরিবর্তন}} করেছেন।"
 }
index 926aad5..98a8f98 100644 (file)
        "hidden-category-category": "Sakrivene kategorije",
        "category-subcat-count": "{{PLURAL:$2|Ova kategorija ima sljedeću podkategoriju.|Ova kategorija ima {{PLURAL:$1|sljedeću podkategoriju|sljedeće $1 podkategorije|sljedećih $1 podkategorija}}, od $2 ukupno.}}",
        "category-subcat-count-limited": "Ova kategorija sadrži {{PLURAL:$1|slijedeću $1 podkategoriju|slijedeće $1 podkategorije|slijedećih $1 podkategorija}}.",
-       "category-article-count": "{{PLURAL:$2|U ovoj kategoriji se nalazi $1 članak.|{{PLURAL:$1|Prikazan je $1 članak|Prikazana su $1 članka|Prikazano je $1 članaka}} od ukupno $2 u ovoj kategoriji.}}",
+       "category-article-count": "{{PLURAL:$2|U ovoj kategoriji nalazi se $1 članak.|{{PLURAL:$1|Prikazan je $1 članak|Prikazana su $1 članka|Prikazano je $1 članaka}} od ukupno $2 u ovoj kategoriji.}}",
        "category-article-count-limited": "{{PLURAL:$1|Slijedeća $1 stranica je|Slijedeće $1 stranice su|Slijedećih $1 stranica je}} u ovoj kategoriji.",
        "category-file-count": "{{PLURAL:$2|Ova kategorija ima slijedeću $1 datoteku.|{{PLURAL:$1|Prikazana je $1 datoteka|Prikazane su $1 datoteke|Prikazano je $1 datoteka}} u ovoj kategoriji, od ukupno $2.}}",
        "category-file-count-limited": "{{PLURAL:$1|Slijedeća $1 datoteka je|Slijedeće $1 datoteke su|Slijedećih $1 datoteka je}} u ovoj kategoriji.",
        "talkpagelinktext": "Razgovor",
        "specialpage": "Posebna Stranica",
        "personaltools": "Lični alati",
-       "postcomment": "Nova sekcija",
        "articlepage": "Pogledaj članak",
        "talk": "Razgovor",
        "views": "Pregledi",
        "readonly": "Baza je zaključana",
        "enterlockreason": "Unesite razlog za zaključavanje, uključujući procjenu vremena otključavanja",
        "readonlytext": "Baza je trenutno zaključana za nove unose i ostale izmjene, vjerovatno zbog rutinskog održavanja, posle čega će biti vraćena u uobičajeno stanje.\n\nAdministrator koji ju je zaključao je ponudio ovo objašnjenje: $1",
-       "missing-article": "U bazi podataka nije pronađen tekst stranice tražen pod nazivom \"$1\" $2.\n\nDo ovoga dolazi kada se prati pomjeranje ili historija linka za stranicu koja je pobrisana.\n\n\nU slučaju da se ne radi o gore navedenom, moguće je da ste pronašli grešku u programu.\nMolimo Vas da ovo prijavite [[Special:ListUsers/sysop|administratoru]] sa navođenjem tačne adrese stranice",
+       "missing-article": "U bazi podataka nije pronađen tekst stranice tražen pod nazivom \"$1\" $2.\n\nDo ovoga dolazi kad se prati pomjeranje ili historija linka za stranicu koja je pobrisana.\n\n\nU slučaju da se ne radi o gore navedenom moguće je da ste pronašli grešku u programu.\nMolimo Vas da ovo prijavite [[Special:ListUsers/sysop|administratoru]] s navođenjem tačne adrese stranice.",
        "missingarticle-rev": "(revizija#: $1)",
        "missingarticle-diff": "(Razlika: $1, $2)",
        "readonly_lag": "Baza podataka je zaključana dok se sekundarne baze podataka na serveru ne sastave sa glavnom.",
        "unexpected": "Neočekivana vrijednost: \"$1\"=\"$2\".",
        "formerror": "Greška: ne može se poslati upitnik",
        "badarticleerror": "Ova akcija ne može biti izvršena na ovoj stranici.",
-       "cannotdelete": "Ne može se obrisati stranica ili datoteka \"$1\".\nMoguće je da ju je neko drugi već obrisao.",
+       "cannotdelete": "Ne može se obrisati stranica ili datoteka \"$1\".\nMoguće je da ju je neko već obrisao.",
        "cannotdelete-title": "Ne mogu izbrisati stranicu \"$1\"",
        "delete-hook-aborted": "Brisanje je prekinuo softverski priključak.\nNije ponuđeno nikakvo objašnjenje.",
        "badtitle": "Loš naslov",
        "externaldberror": "Došlo je do greške pri vanjskoj autorizaciji baze podataka ili vam nije dopušteno osvježavanje Vašeg vanjskog korisničkog računa.",
        "login": "Prijavi se",
        "nav-login-createaccount": "Prijavi se / Registruj se",
-       "loginprompt": "Morate imati kolačiće ('''cookies''') omogućene da biste se prijavili na {{SITENAME}}.",
        "userlogin": "Prijavi se / Registruj se",
        "userloginnocreate": "Prijavi se",
        "logout": "Odjavi me",
        "noname": "Niste izabrali ispravno korisničko ime.",
        "loginsuccesstitle": "Prijavljivanje uspješno",
        "loginsuccess": "'''Sad ste prijavljeni na {{SITENAME}} kao \"$1\".'''",
-       "nosuchuser": "Ne postoji korisnik sa imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite vaše kucanje ili [[Special:UserLogin/signup|napravite novi korisnički račun]].",
-       "nosuchusershort": "Ne postoji korisnik sa imenom \"$1\".\nProvjerite da li ste dobro ukucali.",
+       "nosuchuser": "Ne postoji korisnik s imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite Vaš unos ili [[Special:UserLogin/signup|napravite novi korisnički račun]].",
+       "nosuchusershort": "Ne postoji korisnik s imenom \"$1\".\nProvjerite jeste li dobro ukucali.",
        "nouserspecified": "Morate izabrati korisničko ime.",
        "login-userblocked": "Ovaj korisnik je blokiran. Prijava nije dopuštena.",
        "wrongpassword": "Unijeli ste neispravnu šifru.\nMolimo Vas da pokušate ponovno.",
        "userjspreview": "'''Zapamtite ovo je samo izgled vaše JavaScript-e, još uvijek nije sačuvan!'''",
        "sitecsspreview": "'''Zapamtite ovo je samo izgled ovog CSS-a.'''\n'''Još uvijek nije sačuvan!'''",
        "sitejspreview": "'''Zapamtite ovo je samo izgled ovog koda JavaScripte.'''\n'''Još uvijek nije sačuvan!'''",
-       "userinvalidcssjstitle": "'''Upozorenje:''' Ne postoji interfejs pod imenom \"$1\".\nNe zaboravite da imena stranica s .css i .js kodom počinju malim slovom, npr. {{ns:user}}:Foo/vector.css, a ne {{ns:user}}:Foo/Vector.css.",
+       "userinvalidcssjstitle": "'''Upozorenje:''' Ne postoji interfejs pod imenom \"$1\".\nNe zaboravite da imena stranica s .css i .js kodom počinju malim slovom, npr, {{ns:user}}:Foo/vector.css, a ne {{ns:user}}:Foo/Vector.css.",
        "updated": "(Osvježeno)",
        "note": "'''Pažnja:'''",
        "previewnote": "'''Ne zaboravite da je ovo samo pregled'''\nIzmjene stranice nisu još sačuvane!",
        "continue-editing": "Idi na područje uređivanja",
-       "previewconflict": "Ovaj pregled reflektuje tekst u gornjem polju\nkako će izgledati ako pritisnete \"Sačuvaj članak\".",
+       "previewconflict": "Ovaj pregled prikazuje kako će tekst u gornjem polju\nizgledati ako kliknete \"Sačuvaj članak\".",
        "session_fail_preview": "'''Izvinjavamo se! Nismo mogli obraditi vašu izmjenu zbog gubitka podataka o prijavi. Molimo pokušajte ponovno. Ako i dalje ne bude radilo, pokušajte se [[Special:UserLogout|odjaviti]] i ponovno prijaviti.'''",
        "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.'''",
        "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.'''",
        "editingsection": "Uređujete $1 (dio)",
        "editingcomment": "Uređujete $1 (nova sekcija)",
        "editconflict": "Sukobljenje izmjene: $1",
-       "explainconflict": "Neko drugi je promjenio ovu stranicu otkad ste Vi počeli da je mjenjate.\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\npritisnete \"{{int:savearticle}}\".",
+       "explainconflict": "Neko drugi je promijenio ovu stranicu otkad ste je Vi počeli mijenjati.\nGornje tekstualno polje sadrži tekst stranice koji trenutno postoji.\nVaše izmjene prikazane su u donjem tekstu.\nMorat ćete unijeti svoje promjene u postojeći tekst.\n'''Samo''' tekst u gornjem tekstualnom polju bit će sačuvan kad\nkliknete \"{{int:savearticle}}\".",
        "yourtext": "Vaš tekst",
        "storedversion": "Uskladištena verzija",
        "nonunicodebrowser": "'''UPOZORENJE: Vaš preglednik ne podržava Unicode zapis znakova.\nMolimo Vas promijenite ga prije sljedećeg uređivanja članaka. Znakovi koji nisu po ASCII standardu će se u prozoru za izmjene pojaviti kao heksadecimalni kodovi.'''",
        "right-createtalk": "Pravljenje stranica za razgovor",
        "right-createaccount": "Pravljenje korisničkog računa",
        "right-minoredit": "Označavanje izmjena kao malih",
-       "right-move": "Pomjeranje stranica",
-       "right-move-subpages": "Pomjeranje stranica sa svim podstranicama",
+       "right-move": "Preusmjeravanje stranica",
+       "right-move-subpages": "Preusmjeravanje stranica sa svim podstranicama",
        "right-move-rootuserpages": "Premještanje stranica osnovnih korisnika",
        "right-movefile": "Premještanje datoteka",
        "right-suppressredirect": "Ne pravi preusmjeravanje sa starog imena pri preusmjeravanju stranica",
        "upload_directory_missing": "Folder za postavljanje ($1) nedostaje i webserver ga ne može napraviti.",
        "upload_directory_read_only": "Folder za postavljanje ($1) na webserveru je postavljen samo za čitanje.",
        "uploaderror": "Greška pri slanju",
-       "upload-recreate-warning": "'''Upozorenje: Datoteka s tim imenom je obrisana ili pomjerena.'''\nZapisnik brisanja i pomjeranja za ovu stranicu je dostupan ovdje na uvid:",
+       "upload-recreate-warning": "'''Upozorenje: Datoteka s tim imenom je obrisana ili preusmjerena.'''\nZapisnik brisanja i preusmjeravanja za ovu stranicu dostupan je ovdje:",
        "uploadtext": "Koristite formu ispod za postavljanje datoteka.\nDa bi ste vidjeli ili pretražili ranije postavljene datoteke, pogledajte [[Special:FileList|spisak postavljenih datoteka]], ponovna postavljanja su također zapisana u [[Special:Log/upload|zapisnik postavljanja]], a brisanja u [[Special:Log/delete|zapisnik brisanja]].\n\nDa bi ste prikazali datoteku na stranici, koristite link na jedan od slijedećih načina:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Datoteka.jpg]]</nowiki></code>''' da upotrijebite potpunu veziju datoteke\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Datoteka.png|200px|thumb|lijevo|opis slike]]</nowiki></code>''' da upotrijebite smanjeni prikaz širine 200 piksela unutar okvira, s lijevim poravnanjem i ''opisom slike''.\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Datoteka.ogg]]</nowiki></code>''' za direkno povezivanje datoteke bez njenog prikazivanja",
        "upload-permitted": "Podržane vrste datoteka: $1.",
        "upload-preferred": "Preferirane vrste datoteka: $1.",
        "fileexists-extension": "Datoteka sa sličnim nazivom postoji: [[$2|thumb]]\n* Naziv datoteke koja se postavlja: <strong>[[:$1]]</strong>\n* Naziv postojeće datoteke: <strong>[[:$2]]</strong>\nMolimo Vas da izaberete drugačiji naziv.",
        "fileexists-thumbnail-yes": "Izgleda da je datoteka slika smanjene veličine ''(\"thumbnail\")''. [[$1|thumb]]\nMolimo provjerite datoteku <strong>[[:$1]]</strong>.\nAko je provjerena datoteka ista slika originalne veličine, nije potrebno postavljati dodatnu sliku.",
        "file-thumbnail-no": "Naziv datoteke počinje sa <strong>$1</strong>.\nIzgleda da se radi o smanjenoj slici ''(\"thumbnail\")''.\nAko imate ovu sliku u punoj rezoluciji, postavite nju; ili promijenite naslov ove datoteke.",
-       "fileexists-forbidden": "Datoteka sa ovim imenom već postoji i ne može biti prepisana.\nAko i dalje želite da postavite ovu datoteku, molimo Vas da se vratite i pošaljete ovu datoteku pod novim imenom. [[File:$1|thumb|center|$1]]",
-       "fileexists-shared-forbidden": "Datoteka sa ovim imenom već postoji u zajedničkoj ostavi; molimo Vas da se vratite i pošaljete ovu datoteku pod novim imenom. [[File:$1|thumb|center|$1]]",
+       "fileexists-forbidden": "Datoteka s ovim imenom već postoji i ne može biti prepisana.\nAko i dalje želite postaviti ovu datoteku, molimo Vas da se vratite i pošaljete ovu datoteku pod novim imenom. [[File:$1|thumb|center|$1]]",
+       "fileexists-shared-forbidden": "Datoteka s ovim imenom već postoji u zajedničkoj ostavi. Molimo Vas da se vratite i pošaljete ovu datoteku pod novim imenom. [[File:$1|thumb|center|$1]]",
        "file-exists-duplicate": "Ova datoteka je dvojnik {{PLURAL:$1|slijedećoj datoteci|slijedećim datotekama}}:",
        "file-deleted-duplicate": "Datoteka koje je identična ovoj datoteci ([[:$1]]) je ranije bila obrisana. Trebate provjeriti historiju brisanja te datoteke prije nego što nastavite sa njenim ponovnim postavljanjem.",
        "uploadwarning": "Upozorenje pri slanju",
        "upload-description": "Opis datoteke",
        "upload-options": "Opcije postavljanja",
        "watchthisupload": "Prati ovu datoteku",
-       "filewasdeleted": "Datoteka s ovim nazivom je ranije postavljana i nakon toga obrisana.\nPrije nego što nastavite da je ponovno postavite trebate provjeriti $1.",
+       "filewasdeleted": "Datoteka s ovim nazivom je ranije postavljana i nakon toga obrisana.\nPrije no što nastavite da je ponovo postavite trebate provjeriti $1.",
        "filename-bad-prefix": "Naziv datoteke koju postavljate počinje sa '''\"$1\"''', što je naziv koji obično automatski dodjeljuju digitalni fotoaparati i kamere.\nMolimo Vas da odaberete naziv datoteke koji opisuje njen sadržaj.",
        "filename-prefix-blacklist": " #<!-- ostavite ovu liniju onakvom kakva jeste --> <pre>\n# Sintaksa je slijedeća:\n#   * Sve od karaktera \"#\" pa do kraja je komentar\n#   * Svaka neprazna linija je prefiks za tipična imena datoteka koja automatski dodjeljuje digitalna kamera\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # neki mobilni telefoni\nIMG # generic\nJD # Jenoptik\nMGP # Pentax\nPICT # razni\n #</pre> <!-- ostavite ovu liniju onakvom kakva jeste -->",
        "upload-success-subj": "Uspješno slanje",
        "protectedpages-indef": "Samo neograničena zaštićenja",
        "protectedpages-cascade": "Samo prenosive zaštite",
        "protectedpages-noredirect": "Sakrij preusmjerenja",
-       "protectedpagesempty": "Trenutno nijedna stranica nije zaštićena ovim parametrima.",
+       "protectedpagesempty": "Trenutno nijedna stranica nije zaštićena ovim parametrima.",
        "protectedpages-page": "Stranica",
        "protectedpages-expiry": "Istječe",
        "protectedpages-reason": "Razlog",
        "protectedpages-unknown-timestamp": "Nepoznato",
        "protectedtitles": "Zaštićeni naslovi",
-       "protectedtitlesempty": "Nema naslova zaštićenih članaka sa ovim parametrima.",
+       "protectedtitlesempty": "Nijedan naslov članka trenutno nije zaštićen ovim parametrima.",
        "listusers": "Spisak korisnika",
        "listusers-editsonly": "Pokaži samo korisnike koji su uređivali",
        "listusers-creationsort": "Sortiraj po datumu pravljenja",
        "move": "Preusmjeri",
        "movethispage": "Premjesti ovu stranicu",
        "unusedimagestext": "Slijedeće datoteke postoje ali nisu uključene ni u jednu stranicu.\nMolimo obratite pažnju da druge web stranice mogu biti povezane s datotekom putem direktnog URLa, tako da i pored toga mogu biti prikazane ovdje pored aktivne upotrebe.",
-       "unusedcategoriestext": "Slijedeće stranice kategorija postoje iako ih ni jedan drugi članak ili kategorija ne koriste.",
+       "unusedcategoriestext": "Sljedeće stranice kategorija postoje iako ih nijedan drugi članak ili kategorija ne koriste.",
        "notargettitle": "Nema cilja",
        "notargettext": "Niste naveli ciljnu stranicu ili korisnika\nna kome bi se izvela ova funkcija.",
        "nopagetitle": "Ne postoji takva stranica",
        "all-logs-page": "Svi javni registri",
        "alllogstext": "Zajednički prikaz svih dostupnih zapisa sa {{SITENAME}}.\nMožete specificirati prikaz izabiranjem specifičnog spiska, korisničkog imena ili promjenjenog članka (razlikovati velika slova).",
        "logempty": "Ne postoji takav zapis.",
-       "log-title-wildcard": "Traži naslove koji počinju ovim tekstom",
+       "log-title-wildcard": "Traži naslove koji počinju ovim tekstom",
        "showhideselectedlogentries": "Pokaži/sakrij izabrane zapise u evidenciji",
        "allpages": "Sve stranice",
        "nextpage": "Sljedeća strana ($1)",
        "confirmdeletetext": "Brisanjem ćete obrisati stranicu ili sliku zajedno sa historijom iz baze podataka, ali će se iste moći vratiti kasnije.\nMolim potvrdite svoju namjeru, da razumijete posljedice i da ovo radite u skladu sa [[{{MediaWiki:Policy-url}}|pravilima]].",
        "actioncomplete": "Akcija završena",
        "actionfailed": "Akcija nije uspjela",
-       "deletedtext": "Članak \"$1\" je obrisan.\nPogledajte $2 za zapis o skorašnjim brisanjima.",
+       "deletedtext": "Članak \"$1\" je obrisan.\nPogledajte $2 za zapisnik nedavnih brisanja.",
        "dellogpage": "Protokol brisanja",
        "dellogpagetext": "Ispod je spisak najskorijih brisanja.",
        "deletionlog": "zapis brisanja",
        "rollbacklinkcount-morethan": "vrati više od $1 {{PLURAL:$1|izmjene|izmjene|izmjena}}",
        "rollbackfailed": "Vraćanje nije uspjelo",
        "cantrollback": "Ne može se vratiti izmjena; posljednji autor je ujedno i jedini.",
-       "alreadyrolled": "Ne može se vratiti posljednja izmjena [[:$1]] od korisnika [[User:$2|$2]] ([[User talk:$2|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); neko drugi je već izmjenio ili vratio članak.\n\nPosljednja izmjena je bila od korisnika [[User:$3|$3]] ([[User talk:$3|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
+       "alreadyrolled": "Ne može se vratiti posljednja izmjena [[:$1]] od korisnika [[User:$2|$2]] ([[User talk:$2|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); neko je već izmijenio ili vratio članak na prethodnu provjerenu verziju.\n\nPosljednju izmjenu napravio je korisnik [[User:$3|$3]] ([[User talk:$3|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Sažetak izmjene je bio: \"''$1''\".",
        "revertpage": "Vraćene izmjene korisnika [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]]) na posljednju izmjenu koju je napravio [[User:$1|$1]]",
        "revertpage-nouser": "Vraćene izmjene skrivenog korisnika na posljednju reviziju, koju je {{GENDER:$1|napravio|napravila}} [[User:$1|$1]]",
        "lockfilenotwritable": "Datoteka zaključavanja baze je zaštićena za pisanje.\nAko želite otključati ili zaključati bazu, ova datoteka mora biti omogućena za pisanje od strane web servera.",
        "databasenotlocked": "Baza podataka nije zaključana.",
        "lockedbyandtime": "(od $1 dana $2 u $3)",
-       "move-page": "Pomjeranje $1",
+       "move-page": "Preusmjeravanje $1",
        "move-page-legend": "Premjestite stranicu",
-       "movepagetext": "Korištenjem ovog formulara možete preimenovati stranicu, premještajući cijelu historiju na novo ime.\nČlanak pod starim imenom će postati stranica koja preusmjerava na članak pod novim imenom. \nMožete automatski izmjeniti preusmjerenje do izvornog naslova.\nAko se ne odlučite na to, provjerite [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|neispravna preusmjeravanja]].\nDužni ste provjeriti da svi linkovi i dalje nastave voditi na prave stranice.\n\nImajte na umu da članak '''neće''' biti preusmjeren ukoliko već postoji članak pod imenom na koje namjeravate da preusmjerite osim u slučaju stranice za preusmjeravanje koja nema nikakvih starih izmjena.\nTo znači da možete vratiti stranicu na prethodno mjesto ako pogriješite, ali ne možete zamijeniti postojeću stranicu.\n\n'''Pažnja!'''\nOvo može biti drastična i neočekivana promjena kad su u pitanju popularne stranice;\nMolimo dobro razmislite prije nego što preimenujete stranicu.",
-       "movepagetext-noredirectfixer": "Koristeći obrazac ispod ćete preimenovati stranicu i premjestiti cijelu njenu historiju na novi naziv.\nStari naziv će postati preusmjerenje na novi naziv.\nMolimo provjerite da li postoje [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|nedovršena preusmjerenja]].\nVi ste za to odgovorni te morate provjeriti da li su linkovi ispravni i da li vode tamo gdje bi trebali.\n\nImajte na umu da stranica '''neće''' biti premještena ako već postoji stranica s tim imenom, osim ako je prazna ili je preusmjerenje ili nema ranije historije.\nOvo znali da možete preimenovati stranicu nazad gdje je ranije bila preimenovana ako ste pogriješili a ne možete ponovo preimenovati postojeću stranicu.\n\n'''Pažnja!'''\nImajte na umu da preusmjeravanje popularnog članka može biti\ndrastična i neočekivana promjena za korisnike; molimo budite sigurni da ste shvatili posljedice prije nego što nastavite.",
+       "movepagetext": "Korištenjem ovog formulara možete preimenovati stranicu, premještajući cijelu historiju na novo ime.\nČlanak pod starim imenom postat će stranica koja preusmjerava na članak pod novim imenom. \nMožete automatski izmijeniti preusmjerenje do izvornog naslova.\nAko se ne odlučite na to, provjerite [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|neispravna preusmjeravanja]].\nDužni ste provjeriti da svi linkovi i dalje nastave voditi na prave stranice.\n\nImajte na umu da članak '''neće''' biti preusmjeren ako već postoji članak pod imenom na koje ga namjeravate preusmjeriti osim u slučaju stranice za preusmjeravanje koja nema nikakvih starih izmjena.\nTo znači da možete vratiti stranicu na prethodno mjesto ako pogriješite, ali ne možete zamijeniti postojeću stranicu.\n\n'''Pažnja!'''\nOvo može biti drastična i neočekivana promjena kad su u pitanju popularne stranice.\nMolimo da dobro razmislite prije no što preimenujete stranicu.",
+       "movepagetext-noredirectfixer": "Koristeći donji obrazac, preimenovat ćete stranicu i premjestiti cijelu njenu historiju na novi naziv.\nStari naziv postat će preusmjerenje na novi naziv.\nMolimo da provjerite postoje li [[Special:DoubleRedirects|dvostruka]] ili [[Special:BrokenRedirects|nedovršena preusmjerenja]].\nVi ste za to odgovorni te morate provjeriti jesu li linkovi ispravni i vode li tamo kamo bi trebali voditi.\n\nImajte na umu da stranica '''neće''' biti premještena ako već postoji stranica s tim imenom, osim ako je prazna ili je preusmjerenje ili nema ranije historije.\nOvo znači da možete preimenovati stranicu nazad gdje je ranije bila preimenovana ako ste pogriješili, ali ne možete ponovo preimenovati postojeću stranicu.\n\n'''Pažnja!'''\nImajte na umu da preusmjeravanje popularnog članka može biti\ndrastična i neočekivana promjena za korisnike; molimo da budete sigurni da ste shvatili posljedice prije no što nastavite.",
        "movepagetalktext": "Odgovarajuća stranica za razgovor, ako postoji, će automatski biti premještena istovremeno '''osim:'''\n*Ako premještate stranicu preko imenskih prostora,\n*Neprazna stranica za razgovor već postoji pod novim imenom, ili\n*Odčekirajte donju kutiju.\n\nU tim slučajevima, moraćete ručno da premjestite stranicu ukoliko to želite.",
        "movearticle": "Premjestite stranicu",
        "moveuserpage-warning": "'''Upozorenje:''' Premještate korisničku stranicu. Molimo da zapamtite da će se samo stranica premjestiti a korisnik se ''neće'' preimenovati.",
        "movepagebtn": "pomjerite stranicu",
        "pagemovedsub": "Premještanje uspjelo",
        "movepage-moved": "'''\"$1\" je premještena na \"$2\"'''",
-       "movepage-moved-redirect": "Pomjeranje je napravljeno.",
+       "movepage-moved-redirect": "Preusmjerenje je napravljeno.",
        "movepage-moved-noredirect": "Pravljenje preusmjerenja je onemogućeno.",
-       "articleexists": "Stranica pod tim imenom već postoji, ili je ime koje ste izabrali neispravno.  Molimo Vas da izaberete drugo ime.",
+       "articleexists": "Stranica pod tim imenom već postoji ili je ime koje ste izabrali neispravno. Molimo Vas da izaberete drugo ime.",
        "cantmove-titleprotected": "Ne možete premjestiti stranicu na ovu lokaciju, jer je novi naslov zaštićen od pravljenja",
        "movetalk": "Premjestite \"stranicu za razgovor\" takođe, ako je moguće.",
        "move-subpages": "Premjesti sve podstranice (do $1)",
        "tooltip-pt-login": "Predlažemo da se prijavite, ali nije obvezno.",
        "tooltip-pt-logout": "Odjava sa projekta {{SITENAME}}",
        "tooltip-ca-talk": "Razgovor o sadržaju",
-       "tooltip-ca-edit": "Možete da uređujete ovaj članak. Molimo Vas, koristite dugme \"Prikaži izgled",
+       "tooltip-ca-edit": "Možete uređivati ovaj članak. Molimo Vas, koristite dugme \"Prikaži izgled\" prije spašavanja izmjena.",
        "tooltip-ca-addsection": "Započnite novu sekciju.",
        "tooltip-ca-viewsource": "Ovaj članak je zaključan. Možete ga samo vidjeti ili kopirati kod.",
        "tooltip-ca-history": "Prethodne verzije ove stranice.",
        "tooltip-ca-watch": "Dodajte stranicu u listu praćnih članaka",
        "tooltip-ca-unwatch": "Izbrišite stranicu sa liste praćnih članaka",
        "tooltip-search": "Pretraži projekat {{SITENAME}}",
-       "tooltip-search-go": "Idi na stranicu sa tačno ovim imenom ako postoji",
-       "tooltip-search-fulltext": "Pretraga stranica sa ovim tekstom",
+       "tooltip-search-go": "Idi na stranicu s tačno ovim imenom ako postoji",
+       "tooltip-search-fulltext": "Pretražite stranice s ovim tekstom",
        "tooltip-p-logo": "Glavna stranica",
        "tooltip-n-mainpage": "Posjetite početnu stranicu",
        "tooltip-n-mainpage-description": "Posjetite početnu stranicu",
        "tooltip-n-recentchanges": "Spisak nedavnih izmjena na wiki.",
        "tooltip-n-randompage": "Otvorite slučajan članak",
        "tooltip-n-help": "Mjesto gdje možete nešto da naučite.",
-       "tooltip-t-whatlinkshere": "Spisak svih članaka koji su povezani sa ovim",
+       "tooltip-t-whatlinkshere": "Spisak svih članaka koji su povezani s ovim",
        "tooltip-t-recentchangeslinked": "Nedavne izmjene na stranicama koje su povezane sa ovom",
        "tooltip-feed-rss": "RSS za ovu stranicu",
        "tooltip-feed-atom": "Atom za ovu stranicu",
        "anonymous": "{{PLURAL:$1|Anonimni korisnik|$1 anonimna korisnika|$1 anonimnih korisnika}} projekta {{SITENAME}}",
        "siteuser": "{{SITENAME}} korisnik $1",
        "anonuser": "{{SITENAME}} anonimni korisnik $1",
-       "lastmodifiedatby": "Ovu stranicu je posljednji put promjenio $3, u $2, $1",
+       "lastmodifiedatby": "Ovu stranicu posljednji je put promijenio $3, u $2, $1",
        "othercontribs": "Bazirano na radu od strane korisnika $1.",
        "others": "ostali",
        "siteusers": "{{SITENAME}} {{PLURAL:$2|korisnik|korisnika}} $1",
        "pageinfo-lasttime": "Datum posljednje izmjene",
        "pageinfo-edits": "Ukupan broj izmjena",
        "pageinfo-authors": "Ukupan broj različitih autora",
-       "pageinfo-recent-edits": "Broj nedavnih izmjena (u poslednjih $1)",
+       "pageinfo-recent-edits": "Broj nedavnih izmjena (u posljednjih $1)",
        "pageinfo-recent-authors": "Broj nedavnih različitih autora",
        "pageinfo-magic-words": "{{PLURAL:$1|Čarobna riječ|Čarobne riječi}} ($1)",
        "pageinfo-hidden-categories": "{{PLURAL:$1|Sakrivena kategorija|Sakrivene kategorije}} ($1)",
        "scarytranscludefailed-httpstatus": "[Preuzimanje šablona nije uspjelo za $1: HTTP $2]",
        "scarytranscludetoolong": "[URL je predugačak]",
        "deletedwhileediting": "'''Upozorenje''': Ova stranica je obrisana prije nego što ste počeli uređivati!",
-       "confirmrecreate": "Korisnik [[User:$1|$1]] ([[User talk:$1|razgovor]]) je obrisao ovaj članak pošto ste počeli uređivanje sa razlogom:\n: ''$2''\n\nMolimo Vas da potvrdite da stvarno želite da ponovo napravite ovaj članak.",
-       "confirmrecreate-noreason": "Korisnik [[User:$1|$1]] ([[User talk:$1|razgovor]]) je obrisao ovaj članak pošto ste ga počeli uređivati. Molimo Vas da potvrdite da stvarno želite da ponovo napravite ovaj članak.",
+       "confirmrecreate": "Korisnik [[User:$1|$1]] ([[User talk:$1|razgovor]]) obrisao je ovaj članak pošto ste počeli uređivanje s razlogom:\n: ''$2''\n\nMolimo Vas da potvrdite da stvarno želite ponovo napraviti ovaj članak.",
+       "confirmrecreate-noreason": "Korisnik [[User:$1|$1]] ([[User talk:$1|razgovor]]) obrisao je ovaj članak nakon što ste ga počeli uređivati. Molimo Vas da potvrdite da stvarno želite ponovo napraviti ovaj članak.",
        "recreate": "Ponovno napravi",
        "unit-pixel": "px",
        "confirm_purge_button": "U redu",
        "version-poweredby-credits": "Ova wiki je zasnovana na '''[https://www.mediawiki.org/ MediaWiki]''', autorska prava zadržana © 2001-$1 $2.",
        "version-poweredby-others": "ostali",
        "version-credits-summary": "Željeli bismo se zahvaliti sljedećim ljudima na njihovom doprinosu [[Special:Version|MediaWikiju]].",
-       "version-license-info": "Mediawiki je slobodni softver, možete ga redistribuirati i/ili mijenjati pod uslovima GNU opće javne licence kao što je objavljeno od strane Fondacije Slobodnog Softvera, bilo u verziji 2 licence, ili (po vašoj volji) nekoj od kasniji verzija.\n\nMediawiki se distriburia u nadi da će biti korisna, ali BEZ IKAKVIH GARANCIJA, čak i bez ikakvih posrednih garancija o KOMERCIJALNOSTI ili DOSTUPNOSTI ZA ODREĐENU SVRHU. Pogledajte GNU opću javnu licencu za više detalja.\n\nTrebali biste dobiti [{{SERVER}}{{SCRIPTPATH}}/KOPIJU GNU opće javne licence] zajedno s ovim programom, ako niste, pišite Fondaciji Slobodnog Softvera na adresu  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA ili je pročitajte [//www.gnu.org/licenses/old-licenses/gpl-2.0.html online].",
+       "version-license-info": "Mediawiki je slobodni softver; možete ga redistribuirati i(li) mijenjati pod uvjetima opće javne GNU licence kao što je objavljeno od strane \"Free Software Foundationa\", bilo u verziji 2 licence ili (po Vašoj volji) nekoj od kasnijih verzija.\n\nMediawiki se distribuira u nadi da će biti korisna, ali BEZ IKAKVIH GARANCIJA, čak i bez ikakvih posrednih garancija o KOMERCIJALNOSTI ili DOSTUPNOSTI ZA ODREĐENU SVRHU. Pogledajte opću javnu GNU licencu za više detalja.\n\nTrebali biste dobiti [{{SERVER}}{{SCRIPTPATH}}/KOPIJU opće javne GNU licence] zajedno s ovim programom. Ako niste, pišite \"Free Software Foundationu\" na adresu: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA ili je pročitajte [//www.gnu.org/licenses/old-licenses/gpl-2.0.html ovdje].",
        "version-software": "Instalirani softver",
        "version-software-product": "Proizvod",
        "version-software-version": "Verzija",
        "fileduplicatesearch-info": "$1 × $2 piksel<br />Veličina datoteke: $3<br />MIME vrsta: $4",
        "fileduplicatesearch-result-1": "Datoteka \"$1\" nema identičnih dvojnika.",
        "fileduplicatesearch-result-n": "Datoteka \"$1\" ima {{PLURAL:$2|1 identičnog|$2 identična|$2 identičnih}} dvojnika.",
-       "fileduplicatesearch-noresults": "Nije pronađena datoteka sa imenom \"$1\".",
+       "fileduplicatesearch-noresults": "Nije pronađena datoteka s imenom \"$1\".",
        "specialpages": "Posebne stranice",
        "specialpages-note-top": "Legenda",
        "specialpages-note": "* Normalne posebne stranice.\n* <strong class=\"mw-specialpagerestricted\">Zaštićene posebne stranice.</strong>",
        "logentry-rights-rights-legacy": "$1 je {{GENDER:$2|promijenio|promijenila|promijenio}} članstvo grupe za $3",
        "logentry-rights-autopromote": "$1 {{GENDER:$1|je automatski promijenjeno članstvo|su automatski promijenjena članstva}} iz $4 u $5",
        "rightsnone": "(nema)",
-       "feedback-bugornote": "Ako ste spremni detaljno opisati tehnički problem molimo [$1 prijavite \"bug\" (grešku)].\nInače, možete ispuniti jednostavan obrazac ispod. Vaš komentar biti će dodan na stranicu \"[$3 $2]\", zajedno s vašim korisničkim imenom i internetskog preglednika koji koristite.",
+       "feedback-bugornote": "Ako ste spremni detaljno opisati tehnički problem, molimo [$1 prijavite \"bug\" (grešku)].\nInače, možete ispuniti jednostavan obrazac ispod. Vaš komentar bit će dodan na stranicu \"[$3 $2]\" zajedno s Vašim korisničkim imenom.",
        "feedback-subject": "Tema:",
        "feedback-message": "Poruka:",
        "feedback-cancel": "Odustani",
        "api-error-empty-file": "Datoteka koju ste poslali je bila prazna.",
        "api-error-emptypage": "Stvaranje novih praznih stranica nije dozvoljeno.",
        "api-error-fetchfileerror": "Unutrašnja greška: pojavio se neki problem pri dobijanju podataka o datoteci.",
-       "api-error-fileexists-forbidden": "Datoteka s imenom \"$1\" već postoji, i ne može biti zamijenjena.",
+       "api-error-fileexists-forbidden": "Datoteka s imenom \"$1\" već postoji i ne može biti zamijenjena.",
        "api-error-fileexists-shared-forbidden": "Datoteka s imenom \"$1\" već postoji u zajedničkom spremištu i ne može biti prepisana.",
        "api-error-file-too-large": "Datoteka koju ste poslali je bila prevelika.",
        "api-error-filename-tooshort": "Ime datoteke je prekratko.",
index 4876c6d..25ce027 100644 (file)
        "talkpagelinktext": "Discussió",
        "specialpage": "Pàgina especial",
        "personaltools": "Eines de l'usuari",
-       "postcomment": "Nova secció",
        "articlepage": "Mostra la pàgina",
        "talk": "Discussió",
        "views": "Vistes",
        "externaldberror": "Hi ha hagut una fallida en el servidor d'autenticació externa de la base de dades i no teniu permís per a actualitzar el vostre compte d'accès extern.",
        "login": "Inici de sessió",
        "nav-login-createaccount": "Inicia una sessió / crea un compte",
-       "loginprompt": "Heu de tenir les galetes habilitades per a poder iniciar una sessió a {{SITENAME}}.",
        "userlogin": "Inicia una sessió / crea un compte",
        "userloginnocreate": "Inici de sessió",
        "logout": "Finalitza la sessió",
        "token_suffix_mismatch": "'''S'ha rebutjat la vostra modificació perquè el vostre client ha fet malbé els caràcters de puntuació en el testimoni d'edició. S'ha rebutjat la modificació per a evitar la corrupció del text de la pàgina. Açò passa a vegades quan s'utilitza un servei web de servidor intermediari anònim amb problemes.'''",
        "edit_form_incomplete": "'''Certes parts del formulari de modificació no han arribat al servidor, verifiqueu que les vostres modificacions estan intactes i proveu-ho de nou.'''",
        "editing": "Edició de la pàgina «$1»",
-       "creating": "S'està creant $1",
-       "editingsection": "Edició de «$1» (secció)",
-       "editingcomment": "Edició de «$1» (secció nova)",
+       "creating": "Creació de la pàgina «$1»",
+       "editingsection": "Edició de la pàgina «$1» (secció)",
+       "editingcomment": "Edició de la pàgina «$1» (secció nova)",
        "editconflict": "Conflicte d'edició: $1",
        "explainconflict": "Algú més ha canviat aquesta pàgina des que l'heu editada.\nL'àrea de text superior conté el text de la pàgina com existeix actualment.\nEls vostres canvis es mostren en l'àrea de text inferior.\nHaureu de fusionar els vostres canvis en el text existent.\n'''Només''' el text de l'àrea superior es desarà quan premeu el botó «{{int:savearticle}}».",
        "yourtext": "El vostre text",
        "currentrev": "Revisió actual",
        "currentrev-asof": "Revisió de $1",
        "revisionasof": "Revisió de $1",
-       "revision-info": "Revisió de $1; $2",
+       "revision-info": "La revisió el $1 per {{GENDER:$6|$2}}$7",
        "previousrevision": "←Versió més antiga",
        "nextrevision": "Versió més nova→",
        "currentrevisionlink": "Versió actual",
        "mergehistory-empty": "No pot fusionar-se cap revisió.",
        "mergehistory-success": "$3 {{PLURAL:$3|revisió|revisions}} de [[:$1]] s'han fusionat amb èxit a [[:$2]].",
        "mergehistory-fail": "No s'ha pogut realitzar la fusió de l'historial, comproveu la pàgina i els paràmetres horaris.",
+       "mergehistory-fail-toobig": "No s'ha pogut realitzar la fusió de l'historial perquè es mourien més del limit de $1 {{PLURAL:$1|revisió|revisions}}.",
        "mergehistory-no-source": "La pàgina d'origen $1 no existeix.",
        "mergehistory-no-destination": "La pàgina de destinació $1 no existeix.",
        "mergehistory-invalid-source": "La pàgina d'origen ha de tenir un títol vàlid.",
        "largefileserver": "Aquest fitxer és més gran del que el servidor permet.",
        "emptyfile": "El fitxer que heu carregat sembla estar buit.\nAçò por ser degut a un mal caràcter en el nom del fitxer.\nComproveu si realment voleu carregar aquest fitxer.",
        "windows-nonascii-filename": "Aquest wiki no permet noms de fitxer amb caràcters especials.",
-       "fileexists": "Ja hi existeix un fitxer amb aquest nom, si us plau, verifiqueu <strong>[[:$1]]</strong> si no esteu segurs de voler substituir-lo.\n[[$1|thumb]]",
+       "fileexists": "Ja existeix un fitxer amb aquest nom. Comproveu <strong>[[:$1]]</strong> si no esteu {{GENDER:|segur|segura}} de voler substituir-lo.\n[[$1|thumb]]",
        "filepageexists": "La pàgina de descripció d'aquest fitxer ja ha estat creada (<strong>[[:$1]]</strong>), però de moment no hi ha cap fitxer amb aquest nom. La descripció que heu posat no apareixerà a la pàgina de descripció. Si voleu que hi aparegui haureu d'editar-la manualment.\n[[$1|thumb]]",
        "fileexists-extension": "Ja existeix un fitxer amb un nom semblant: [[$2|thumb]]\n* Nom del fitxer que es puja: <strong>[[:$1]]</strong>\n* Nom del fitxer existent: <strong>[[:$2]]</strong>\nPotser voleu fer servir un nom més fàcil de distingir?",
        "fileexists-thumbnail-yes": "Aquest fitxer sembla ser una imatge en mida reduïda (<em>miniatura</em>). [[$1|thumb]]\nComproveu si us plau el fitxer <strong>[[:$1]]</strong>.\nSi el fitxer és la mateixa imatge a mida original, no cal carregar cap miniatura més.",
        "license-nopreview": "(Previsualització no disponible)",
        "upload_source_url": " (un URL vàlid i accessible públicament)",
        "upload_source_file": " (un fitxer en el vostre ordinador)",
+       "listfiles-delete": "elimina",
        "listfiles-summary": "Aquesta pàgina especial mostra tots els fitxers carregats.\nSi filtreu per usuari només es mostraran els fitxers la versió més recent dels quals hagi estat carregada per aquell.",
        "listfiles_search_for": "Cerca el nom d'un fitxer de medis:",
        "imgfile": "fitxer",
        "wantedpages-badtitle": "Títol invàlid al conjunt de resultats: $1",
        "wantedfiles": "Fitxers demanats",
        "wantedfiletext-cat": "Els fitxers següents s'utilitzen per no existeixen. Els fitxers de repositoris aliens poden ser llistats encara que existeixin. Aquells que siguin fals positius es <del>tatxaran</del>. A més, les pàgines que tinguin fitxers incrustats que no existeixin es llistaran a [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Els fitxers següents s'utilitzen, però no existeixen. Addicionalment, s'enumeren a [[:$1]] les pàgines que tenen fitxers inserits que no existeixen.",
        "wantedfiletext-nocat": "Els fitxers següents es fan servir però no existeixen. Els fitxers d'un repositori aliè poden ser llistats encara que existeixin. Tots aquells fals positius es <del>tatxaran</del>.",
+       "wantedfiletext-nocat-noforeign": "Els fitxers següents s'utilitzen però no existeixen.",
        "wantedtemplates": "Plantilles demanades",
        "mostlinked": "Pàgines més enllaçades",
        "mostlinkedcategories": "Categories més utilitzades",
        "move-page-legend": "Reanomena la pàgina",
        "movepagetext": "Amb el formulari següent reanomenareu una pàgina, movent tot el seu historial al nou nom.\nEl títol anterior es convertirà en una pàgina de redirecció al nou títol.\nPodeu actualitzar automàticament les redireccions que apuntin al títol original.\nSi no ho feu, assegureu-vos de verificar les redireccions [[Special:DoubleRedirects|dobles]] o [[Special:BrokenRedirects|trencades]].\nSerà de la vostra responsabilitat verificar que els enllaços segueixin apuntant cap a on se suposa que ho han de fer.\n\nTingueu en compte que la pàgina '''no''' serà traslladada si ja existeix una pàgina amb el títol nou, tret que sigui una redirecció sense més historial.\nAixò significa que podeu reanomenar de nou una pàgina al seu títol original si cometeu un error, i que no podeu sobreescriure una pàgina existent.\n\n'''Atenció!'''\nAçò pot ser un canvi dràstic i inesperat en una pàgina que sigui popular; \nassegureu-vos d'entendre les conseqüències que comporta abans de seguir endavant.",
        "movepagetext-noredirectfixer": "Amb el formulari següent podeu reanomenar una pàgina movent tot el seu historial al nom nou.\nEl títol anterior es convertirà en una pàgina de redirecció al nou títol. \nAssegureu-vos de verificar les redireccions [[Special:DoubleRedirects|dobles]] o [[Special:BrokenRedirects|trencades]].\nÉs responsabilitat vostra assegurar que els enllaços continuen apuntant cap a on se suposa que han d'anar. \n\nTingueu en compte que la pàgina '''no''' serà traslladada si ja existeix una pàgina amb el títol nou, tret que sigui una redirecció i no tingui més historial. \nAixò significa que podeu reanomenar de nou una pàgina al seu títol original si cometeu un error, i que no podeu sobreescriure una pàgina existent.\n \n'''Atenció!''' \nAixò pot ser un canvi dràstic i inesperat per una pàgina popular; \nassegureu-vos que sabeu el que feu abans de continuar.",
-       "movepagetalktext": "La pàgina de discussió associada també serà traslladada automàticament '''tret que''':\n* Ja existeix una pàgina de discussió no buida amb el nou nom, o\n* Desactiveu la opció de més avall.\n\nEn aquests casos, haureu de traslladar o fusionar la pàgina manualment si ho desitgeu.",
+       "movepagetalktext": "La pàgina de discussió associada també serà traslladada automàticament '''tret que''':\n* Ja existeixi una pàgina de discussió no buida amb el nou nom, o\n* Desactiveu l'opció de més avall.\n\nEn aquests casos, haureu de traslladar o fusionar la pàgina manualment si ho desitgeu.",
        "movearticle": "Reanomena la pàgina",
        "moveuserpage-warning": "'''Atenció:''' Esteu a punt de moure una pàgina d'usuari. Tingueu en compte que només la pàgina es desplaçarà i que el compte d'usuari ''no'' canviarà de nom.",
        "movecategorypage-warning": "<strong>Avís:</strong> Esteu a punt de moure una pàgina de categoria. Tingueu en compte que només es moure la pàgina i qualsevol de les pàgines a l'antiga categoria <em>no</em> es recategoritzarà automàticament en la nova.",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discussió]])",
        "unknown_extension_tag": "Etiqueta d'extensió desconeguda «$1»",
        "duplicate-defaultsort": "Atenció: La clau d'ordenació per defecte \"$2\" invalida l'anterior clau \"$1\".",
+       "duplicate-displaytitle": "<strong>Avís:</strong> El títol a mostrar «$2» sobreescriu l'anterior títol a mostrar «$1».",
        "version": "Versió",
        "version-extensions": "Extensions instaŀlades",
-       "version-skins": "Aparences",
+       "version-skins": "Temes instal·lats",
        "version-specialpages": "Pàgines especials",
        "version-parserhooks": "Extensions de l'analitzador",
        "version-variables": "Variables",
        "version-license": "Llicència del MediaWiki",
        "version-ext-license": "Llicència",
        "version-ext-colheader-name": "Extensió",
+       "version-skin-colheader-name": "Aparença",
        "version-ext-colheader-version": "Versió",
        "version-ext-colheader-license": "Llicència",
        "version-ext-colheader-description": "Descripció",
        "expand_templates_remove_nowiki": "Suprimeix l'etiqueta <nowiki> en el resultat",
        "expand_templates_generate_xml": "Mostra l'arbre XML",
        "expand_templates_generate_rawhtml": "Mostra l'HTML sense filtrar",
-       "expand_templates_preview": "Previsualitza"
+       "expand_templates_preview": "Previsualitza",
+       "pagelanguage": "Selector de l'idioma de les pàgines",
+       "pagelang-name": "Pàgina",
+       "pagelang-language": "Idioma",
+       "pagelang-use-default": "Utilitza l'idioma per defecte",
+       "pagelang-select-lang": "Selecciona un idioma",
+       "right-pagelang": "Canvia l'idioma de la pàgina",
+       "action-pagelang": "canvia l'idioma de la pàgina",
+       "log-name-pagelang": "Canvia el registre de llengua",
+       "log-description-pagelang": "Aquest és un registre dels canvis en les llengües de les pàgines.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|ha canviat}} la llengua de la pàgina per a $3 de $4 a $5."
 }
index 91752be..1f6960d 100644 (file)
@@ -7,7 +7,8 @@
                        "Mega programmer",
                        "Sasan700",
                        "Умар",
-                       "아라"
+                       "아라",
+                       "Kaganer"
                ]
        },
        "tog-underline": "КӀел сиз хьакха хьажорган:",
        "talkpagelinktext": "Дийцаре",
        "specialpage": "Белха агӀо",
        "personaltools": "Долахь болу гӀирсаш",
-       "postcomment": "Керла дакъа",
        "articlepage": "Хьажа яззаме",
        "talk": "Дийцаре",
        "views": "Хьажарш",
        "externaldberror": "Арахьара хаамийн базан гӀоьнца аутентификаци ечу хенахь гӀалат даьлла я хьа дӀаяздаран хийцам бан бакъонаш яц.",
        "login": "Системин чугӀо",
        "nav-login-createaccount": "Системин чугӀо / дӀаяздар кхолла",
-       "loginprompt": "Ахьа бакъо яла еза оцу «cookies» хьайна системин чохь болхбан лаахь.",
        "userlogin": "Довзийтар я декъашхочун дӀаяздар кхоллар",
        "userloginnocreate": "Довзийта",
        "logout": "Болх дӀаберзор",
        "login-abort-generic": "Сестемин довзийта тарцаделира",
        "loginlanguagelabel": "Мотт: $1",
        "suspicious-userlogout": "Хьан сеанс чекхъяккха дина дехаш кхочуш цадина, иза нийса йоцу браузерца дар бахьнехь я прокси кэш еш хилар бахьнехь.",
+       "createacct-another-realname-tip": "Декъашхочун бакъ цӀе (яз ца йича мега).\nАхьа и язяхь, агӀона хийцам бича хьан цӀе гуш хира ю.",
        "pt-login": "ЧугӀо",
        "pt-login-button": "ЧугӀо",
        "pt-createaccount": "Кхолла декъашхочун дӀаяздар",
        "passwordreset-emailelement": "Декъашхочун цӀе: $1\nХанна йолу пароль: $2",
        "passwordreset-emailsent": "Электронан хаам баийтина кхоьссинчу паролах лаьцна хаам чохь болуш.",
        "passwordreset-emailsent-capture": "Электронан хаам баийтина кхоьссинчу паролах лаьцна хаам чохь болуш. \nцуна йозане хьажа йиш ю лахахь.",
+       "passwordreset-emailerror-capture": "Пароль кхоссаран хаам чохь болуш электронан кехат кхоьллина, цуна йоза хьажа йиш ю лахахь, амма иза {{GENDER:$2|декъашхочунга}} дӀадахьийта тар цаделира бахьнехь: $1",
        "changeemail": "Хийца электронан почта",
        "changeemail-header": "Электронан почтан адрес хийцар",
        "changeemail-text": "Юза хӀара форма хьайн электронан почтан адрес хуьйцуш. Ахьа хийцар бакъдан язъян еза пароль.",
        "accmailtitle": "Пароль дlаяхьийтина.",
        "accmailtext": "Пароль декъашхочуьнан [[User talk:$1|$1]], йина ша шех хитта делла чу элпашах, дӀаяхийтина хьокху $2 адрес тӀе.\n\nЧуваьлла/яла чул тӀехьа , кху гӀирса чохь шуьга хийцалур ю ''[[Special:ChangePassword|шай пароль]]''.",
        "newarticle": "(Kерла)",
-       "newarticletext": "Хьо веана хьажоригци хӀокху агӀон тӀе, хӀара агӀо хӀинца йоцаш ю.\nНагахь иза кхолла лаахь, хӀотта де лахо гуш долу корехь йоза (мадарра хьажа. [$1 гӀон агӀон чу]).\nНагахь гӀалат даьлла цахууш кхечехь кхузе, атта тӀе тӀаӀа йе '''юха йоккхуриг''' хьай гӀирса тӀехь.",
+       "newarticletext": "ХӀара агӀо хӀинца йоцаш ю.\nНагахь иза кхолла лаахь, хӀотта де лахо гуш долу корехь йоза (мадарра хьажа. [$1 гӀон агӀон чу]).\nНагахь гӀалат даьлла цахууш кхечехь кхузе, атта тӀе тӀаӀа йе '''юха йоккхуриг''' хьай браузеран тӀехь.",
        "anontalkpagetext": "----''ХӀара дийцаре агӀо къайлаха декъашхочуьна ю, хӀинца дӀаяздар доцу, я лелош воцуш/йоцуш.\nЦундела иза вовзийта/йовзийта лелош ду терахьца IP-адрес.\nИза терахь долу меттиг хила мега кхечу декъашхойчух терра.\nНагахь хьо къайлах волу декъашхо валахь хьайна хаам кхаьчна аьлла хеташн, хьуна хьажийна доцуш, дехар до, кхолла хьай меттиг кху чохь[[Special:UserLogin/signup|дӀаяздар кхоллар]] я [[Special:UserLogin|системин чугӀо]],",
        "noarticletext": "Хlокх хан чохь кху агlонца йоза дац.\nШуьга далундерг [[Special:Search/{{PAGENAME}}|лахар ишта хьехош йолу цlе]] кхечу яззамашкахь,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} лахар кхечу тептаршкахь],\nйа '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} кхолла ишта цlе йолу агlо]'''</span>.",
        "noarticletext-nopermission": "ХӀокх хан чохь кху агӀонца йоза дац.\nШуьга далундерг [[Special:Search/{{PAGENAME}}|лахар ишта хьехош йолу цӀе]] кхечу яззамашкахь,\nйа <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} лаха оцуьнах терадерг кхечу тептаршкахь].</span>",
        "copyrightwarning": "Тергаме хьажа, массо яззаман чутухуш долу йозан хийцам хьажарехь бу, арахоьцушсанна оцу бакъойалар хьоляхь $2 (хьаж. $1).\nНагахь хьо лууш вацахь хьай йозанаш маьрша даржа а кхечаьрга хийцам байта, мадаха уьш кху чу.<br />\nИшта чlагlо йой ахьа, айхьа далош долучуьн хьо куьг да ву аьлла, йа хьаэцна цхьан\nхьостера, хийцам ба а дlаса даржада а чулацам болуш.<br />\n'''МАТОХИЙШ БАКЪО ЙОЦУ ГlИРСАШ КХУ ЧУ, КУЬГ ДЕ БАКЪО ЛАР ЙЕШ ЙОЛУ!'''",
        "readonlywarning": "'''ДӀАХЬЕДО. ГӀирса бух блоктоьхна оьшуш долучу хьаштан, цундера хӀинц хьоьга дӀа ца йазло хийцам.\nХила мега, ахьа Ӏалаш дан дезаш хьайн йоза, юха тӀаьхьо леладан иза йоза.'''\n\nКуьйгалхочо блоктоьхна гӀирса бух, цо битина кхетош хӀара хаам: $1",
        "protectedpagewarning": "'''Дlахьедар. Хlара агlо гlаролла дина ю хийцам цабайта, иза хийца йа нисйа а бакъо йолуш адаманкуьйгалла лелош болу декъашхой бе бац.'''\nЛахахьа гойту хаамаш тlаьхьара бина болу хийцамна тептар чура:",
+       "semiprotectedpagewarning": "'''ДӀахьедо.''' ХӀара агӀо гӀаролла йина ю; дӀабазбиначу декъашхошка бе цӀе хийцалуш яц.\nЛахахьа тептаро балийна тӀаьхьаралера дӀаязбина хаам:",
        "cascadeprotectedwarning": "<div id=\"cascadeprotectedwarning\" style=\"border:1px solid #ee0; padding:10px; background:#ffa; margin-bottom:1em\">[[file:Padlock.svg|left|25px|ДовгӀа|link=]]\nХӀара агӀо тада бакъо йолуш [[Project:Куьйгалхой|куьйгалхой]] бу, хӀунда аьлча и агӀо латийна кхечу агӀонашца хӀоттделлачу гӀаролле:</div>",
        "templatesused": "{{PLURAL:$1|1=Кеп, лелийна|Кепаш, лелош ю}} хӀокху агон башхонца:",
        "templatesusedpreview": "{{PLURAL:$1|1=Кеп, лелошдолу|Кепаш, лелойлу}} оцу хьалх хьожучу агӀонца:",
        "revdelete-reason-dropdown": "Даржина долу дӀаяккхаран баьхьанаш \n** Авторан бакъонаш талхор\n** Бита йиш йоцу шех лаьцна хаам\n** Бакъдоцург зуламан хаам",
        "revdelete-otherreason": "Кхин бахьна/тӀетохар:",
        "revdelete-reasonotherlist": "Кхин бахьна",
-       "revdelete-edit-reasonlist": "Бахьанин список нисяр",
+       "revdelete-edit-reasonlist": "Бахьанин могӀам нисбар",
        "revdelete-offender": "АгӀона версен автор:",
        "suppressionlog": "Хьулдаран тептар",
        "mergehistory": "Нисдарин истори цхьаьнатохар",
        "showingresultsheader": "{{PLURAL:$5|1=Хилам '''$1''' кху '''$3'''|Хиламаш '''$1 — $2''' кху '''$3'''}} оцун '''$4'''",
        "search-nonefound": "Дехаре терра цхьа хӀума ца карийна.",
        "powersearch-legend": "Шуьро лахар",
-       "powersearch-ns": "Цlераши анахь лахар:",
+       "powersearch-ns": "ЦӀерийн меттигашкахь лахар:",
        "powersearch-togglelabel": "Билгалдан:",
        "powersearch-toggleall": "Массо",
        "powersearch-togglenone": "ХӀумма цаоьшу",
+       "powersearch-remember": "Дагахь дита хаьржинарг кхечу хенахь лаха",
        "search-external": "Арахула лахар",
        "search-error": "Лохуш гӀалат даьлла: $1",
        "preferences": "ГӀирс нисбан",
        "http-read-error": "Ешаран гӀалат HTTP.",
        "http-timed-out": "Хьежаран хан чекхели HTTP-жоп дехаран.",
        "http-curl-error": "URLан гӀалат: $1",
+       "upload-curl-error6": "Билгал дина адресе хьажа цало.",
        "upload-curl-error28": "Чуйоккху хан чеккхелла",
        "license": "Бакъойалар:",
        "license-header": "Бакъойалар",
        "nolicense": "Яц",
        "license-nopreview": "(Хьалха муха ю хьажа цало)",
        "upload_source_file": " (файл хьан компьютер чохь ю)",
+       "listfiles-delete": "дӀаяккха",
        "listfiles-summary": "Лахахь гойтуш ю ерриг файлаш.\nДекъашхо къастичи, цун керла файлаш гойту.",
        "listfiles_search_for": "Лаха хIуман цIарца:",
        "imgfile": "файл",
        "filedelete-otherreason": "Кхин бахьна:",
        "filedelete-reason-otherlist": "Кхин бахьна",
        "filedelete-reason-dropdown": "* Даржина долу дӀаяккхаран баьхьанаш \n** Авторан бакъонаш талхор\n** ЦхӀатера файлаш хилар",
-       "filedelete-edit-reasonlist": "Бахьанин список нисяр",
+       "filedelete-edit-reasonlist": "Бахьанин могӀам нисбар",
        "filedelete-maintenance-title": "Файл дӀаяккха цало",
        "mimesearch": "MIME хула лаха",
        "mimesearch-summary": "ХӀокху агӀоно йиш хуьлуьйту MIME-тайпан файлаш харжа. Яздеш долу формат: чулацаман тайп/бухара тайп, масала  <code>image/jpeg</code>.",
        "mimetype": "MIME-тайп:",
        "download": "чуяккха",
-       "unwatchedpages": "Цхьамо тергам ца беш йолу агIонаш",
+       "unwatchedpages": "Цхьамо тергам ца беш йолу агӀонаш",
        "listredirects": "ДIасахьажоран могIам",
        "listduplicatedfiles": "Файлийн могӀам дубликатшца",
        "listduplicatedfiles-entry": "Файлан [[:File:$1|$1]] — [[$3|{{PLURAL:$2|дубликат ю}}]].",
        "unusedtemplateswlh": "кхин хьажоргаш",
        "randompage": "Цахууш нисъелла агӀо",
        "randomincategory": "Категори чу цахууш нисъелла  агӀо",
+       "randomincategory-nopages": "[[:Category:$1]] категори чохь агӀонаш яц.",
        "randomincategory-selectcategory": "Категори чу цахууш нийса елла агӀона чу гӀо: $1 $2.",
        "randomincategory-selectcategory-submit": "Дехьа гӀо",
        "randomredirect": "Цахууш нисделла дIасахьажор",
+       "randomredirect-nopages": "«$1» цӀерийн меттиган чохь дӀасахьажораш яц.",
        "statistics": "Статистика",
        "statistics-header-pages": "АгӀонийн жамӀ",
        "statistics-header-edits": "Нисдаран жамӀ",
        "pageswithprop-text": "Кхузахь гойтуш ю агӀонаш цхьадолу къастамаш куьйга юху билгал даьхнарш.",
        "pageswithprop-prop": "Къастаман цӀе:",
        "pageswithprop-submit": "Лаха",
+       "pageswithprop-prophidden-long": "деха йозан хӀуман маьӀна хьулйина ($1)",
+       "pageswithprop-prophidden-binary": "шалха маьӀна долу хӀума хьулйина ($1)",
        "doubleredirects": "Шалха дIасахьажийнарш",
        "doubleredirectstext": "ХӀокху агӀонехь ю дӀасахьажорашан тӀе хьажийна йолу дӀасахьажораш.\n<del>ТӀехула сиз хаькхна </del>нисйина чарна.",
        "double-redirect-fixed-move": "АгӀон [[$1]] цӀе хийцина, хӀинца иза дӀахьажийна оцу [[$2]]",
        "withoutinterwiki": "Юкъарвики-хьажоргаш йоцу агӀонаш",
        "withoutinterwiki-summary": "Лахара агӀонийн юкъарвики-хьажоргаш яц:",
        "withoutinterwiki-submit": "Гайта",
-       "fewestrevisions": "ЧIогIа кIезиг башхонаш йолу агIонаш",
+       "fewestrevisions": "ЧӀогӀа кӀезиг версеш йолу агӀонаш",
        "nbytes": "$1 {{PLURAL:$1|байт}}",
        "ncategories": "$1 {{PLURAL:$1|категори|категореш}}",
        "ninterwikis": "$1 {{PLURAL:$1|1=юкъарвики-хьажораг|юкъарвики-хьажоргаш}}",
        "nimagelinks": "Лелош ю $1 {{PLURAL:$1|агӀонгахь|агӀонашкахь}}",
        "ntransclusions": "лелош ю $1 {{PLURAL:$1|агӀонгахь|агӀонашкахь}}",
        "specialpage-empty": "Дехаро хӀумма ца елла.",
-       "lonelypages": "Байлахь йисина агIонаш",
+       "lonelypages": "Байлахь йисина агӀонаш",
        "lonelypagestext": "Кхузахь ю {{grammar:genitive|{{SITENAME}}}} кхечу агӀонашкахь тӀе хьажийна хьажоргаш йоцу агӀонаш.",
-       "uncategorizedpages": "Категореш йоцу агIонаш",
+       "uncategorizedpages": "Категореш йоцу агӀонаш",
        "uncategorizedcategories": "Категореш йоцу категореш",
        "uncategorizedimages": "Категореш йоцу файлаш",
        "uncategorizedtemplates": "Категореш йоцу кепаш",
        "unusedimages": "Лелош йоцу файлаш",
        "popularpages": "ГӀараяьлла агӀонаш",
        "wantedcategories": "Оьшуш йолу категореш",
-       "wantedpages": "Оьшуш йолу агIонаш",
+       "wantedpages": "Оьшуш йолу агӀонаш",
        "wantedfiles": "Оьшуш йолу файлаш",
        "wantedfiletext-cat": "Лахара йоцу файлаш лело гӀерта. Оцу могӀам юкъа ца хууш файлаш кхета там бу, кхечу проекташ чохь йолу. Ишта ца хууш юкъа нийса елачарна тӀехула <del>сиз</del> хира ду.\nКхин йоцу файлаш гойту [[:$1]] чохь",
        "wantedfiletext-nocat": "Лахара йоцу файлаш лело гӀерта. Оцу могӀам юкъа ца хууш файлаш кхета там бу, кхечу проекташ чохь йолу. Ишта ца хууш юкъа нийса елачарна тӀехула <del>сиз</del> хира ду.",
        "mostcategories": "Дуккха категореш тӀе тоьхна йолу агӀонаш",
        "mostimages": "Массарел дуккха лелайо файлаш",
        "mostinterwikis": "Дуккха юкъарвики хьажоргаш тӀе тоьхна йолу агӀонаш",
-       "mostrevisions": "Сих сиха нисйина йолу агIонаш",
+       "mostrevisions": "Сих сиха нисйина йолу агӀонаш",
        "prefixindex": "Хьалха агӀонашан цӀераш хӀотто йеза",
        "prefixindex-namespace": "Хьалха агӀонашан цӀераш хӀотто еза («{{ns:$1}}»)",
        "prefixindex-strip": "Хиламийн могӀам чура префикс къайлаяккха",
        "shortpages": "Боца яззамаш",
        "longpages": "Беха яззамаш",
-       "deadendpages": "Дика йоцу агIонаш",
-       "protectedpages": "ГIаролла дина агIонаш",
+       "deadendpages": "Дика йоцу агӀонаш",
+       "protectedpages": "ГIаролла дина агӀонаш",
        "protectedpages-indef": "Хан йоцуш гӀоралла динарш бен",
        "protectedpages-cascade": "Чахчарин гӀоралла бен",
        "protectedpages-noredirect": "Къайлаяха дӀасахьажийнарш",
        "email-legend": "{{grammar:genitive|{{SITENAME}}}} кхечу декъашхочунга кехат дахьийтар",
        "emailfrom": "Хьаьнгара",
        "emailto": "Хьаьнга:",
+       "emailsubject": "Къамел:",
        "emailmessage": "Хаам:",
        "emailsend": "ДӀадахьийта",
        "emailccme": "Соьга а кхосса хааман копи.",
        "deleteotherreason": "Кхин бахьна/тӀетохар:",
        "deletereasonotherlist": "Кхин бахьна",
        "deletereason-dropdown": "* Даржина долу дӀаяккхаран баьхьанаш \n** зулма  \n** авторан лаамца\n** авторан бакъонаш талхор",
-       "delete-edit-reasonlist": "Бахьанин список нисяр",
+       "delete-edit-reasonlist": "Бахьанин могӀам нисбар",
        "deleting-backlinks-warning": "'''ДӀахьедар:''' Ахьа дӀайоккхуш йолчун тӀе товжийна [[Special:WhatLinksHere/{{FULLPAGENAME}}|кхин агӀонаш]] ю.",
        "rollback": "Юхабаккха хийцам",
        "rollback_short": "Юхаяккхар",
        "modifiedarticleprotection": "агlонан гlаролли локхалла хийцина «[[$1]]»",
        "unprotectedarticle": "ГӀоролла дӀадаьстина «[[$1]]»",
        "movedarticleprotection": "«[[$2]]» агӀона тӀера гӀаролла «[[$1]]» агӀона тӀе даьккхина",
-       "protect-title": "Оцунна «$1» гӀоралла дар",
+       "protect-title": "ГӀоралла хӀоттор: «$1»",
+       "protect-title-notallowed": "ГӀораллин бараме хьажар «$1»",
        "prot_1movedto2": "«[[$1]]» цӀе хийцина → «[[$2]]»",
+       "protect-badnamespace-title": "ГӀораладан цалуш йолу цӀерийн меттиг",
+       "protect-badnamespace-text": "ХӀокху цӀерийн меттигехь йолу агӀонашна гӀараладан цало.",
+       "protect-norestrictiontypes-title": "ГӀараладан цалуш йолу агӀо",
        "protect-legend": "Бакъде гӀоралла дар",
        "protectcomment": "Бахьна:",
        "protectexpiry": "Чекхйолу:",
        "protect-otherreason": "Кхин бахьна/тӀетохар:",
        "protect-otherreason-op": "Кхин бахьна",
        "protect-dropdown": "* ГӀоралла дарна баьхьаш \n** сих-сиха зулам дар \n** дуккха спам хилар\n** нисдаршан тӀом \n** гӀараялл агӀо",
-       "protect-edit-reasonlist": "Бахьанин список нисяр",
+       "protect-edit-reasonlist": "Бахьанин могӀам нисбар",
        "protect-expiry-options": "1 сахьт:1 hour,1 де:1 day,1 кӀиран:1 week,2 кӀиран:2 weeks,1 бутт:1 month,3 бутт:3 months,6 бутт:6 months,1 шо:1 year,цlкъа:infinite",
        "restriction-type": "Бакъонаш:",
        "restriction-level": "ТӀекхочаран локхалла:",
        "contribsub2": "Къинхьегам $1 ($2)",
        "contributions-userdoesnotexist": "«$1» декъашхочун дӀаяздар дӀаяздина яц.",
        "nocontribs": "Дехарца хийцамаш цакарий.",
-       "uctop": " (тlаьхьара)",
+       "uctop": "(карара)",
        "month": "Баттаца (я хьалхе):",
        "year": "Шерачохь (я хьалхе):",
        "sp-contributions-newbies": "Гайта бекъ къинхьегам, керла дlабазбиначара бина болу",
        "istemplate": "юкъаялийнарш",
        "isimage": "Файлан хьажораг",
        "whatlinkshere-prev": "{{PLURAL:$1|1=хьалхайодарг|хьалхайодарш}} $1",
-       "whatlinkshere-next": "{{PLURAL:$1|тlаьхьайогlург|тlаьхьайогlурш|тlаьхьайогlурш}} $1",
+       "whatlinkshere-next": "{{PLURAL:$1|тӀаьхьайогӀург|тӀаьхьайогӀурш}} $1",
        "whatlinkshere-links": "← хьажоргаш",
        "whatlinkshere-hideredirs": "$1 дӀасахьажорш",
        "whatlinkshere-hidetrans": "$1 латораш",
        "ipaddressorusername": "IP-адрес я декъашхочун цӀе:",
        "ipbexpiry": "Хан чекхйолу:",
        "ipbreason": "Бахьна:",
-       "ipbreason-dropdown": "* Белхан некъ дӀакъовлар бахьанаш:\n** Харца хаам бар\n** АгӀонан чураниг дӀаяккхар\n** Спам-хьажоргаш арахьара сайташна\n** МаьӀна доцу текст тӀетохар\n** Декъашхой хьийзабар, кхерамаш тийсар\n** Масийтта лараман яздар зуламан лелаяр\n** Магийтина йоцу декъашхочун цӀе",
+       "ipbreason-dropdown": "* Белхан некъ дӀакъовлар бахьанаш:\n** Харца хаам бар\n** АгӀонан чураниг дӀаяккхар\n** Спам-хьажоргаш арахьара сайташна\n** МаьӀна доцу йоза тӀетохар\n** Декъашхой хьийзабар, кхерамаш тийсар\n** Масийтта лараман яздар зуламан лелаяр\n** Магийтина йоцу декъашхочун цӀе",
        "ipb-hardblock": "Шаш довзийтина болу декъашхошна бехкам бе хӀокху IP-адресца тадарш дан",
        "ipbcreateaccount": "Цамаго керла декъашхочун дӀаяздарш кхолла",
        "ipbemailban": "Цамагдо декъашхошка хааман кехаташ кхехьийта",
        "ipbsubmit": "Блоктоха хӀокху декъашхочун/адресна",
        "ipbother": "Кхин хан:",
        "ipboptions": "2 сахьат:2 hours,1 де:1 day,3 де:3 days,1 кlиран:1 week,2 кlиран:2 weeks,1 бутт:1 month,3 бутт:3 months,6 бутт:6 months,1 шо:1 year,цӀкъа:infinite",
+       "ipbhidename": "Нисдарийн а могӀаман а чура декъашхочун цӀе хьул йе",
        "ipbwatchuser": "ТӀетоха тергаме могӀам юкъа цуьнан долахь йолу агӀо а цуьнан дийцаре агӀо а",
        "ipb-disableusertalk": "Цамагдо шин дийцаре агӀо та я блоктоьхна хан чекхъяллалц",
        "ipb-change-block": "Юхаблоктоха декъашхочун оьцу хийцамашца",
        "blockipsuccesssub": "Блоктохар чакхдели",
        "blockipsuccesstext": "[[Special:Contributions/$1|«$1»]] {{GENDER:$1|блоктоьхна}}.<br />\nХьажа. [[Special:BlockList|блоктоьхна IP-адресийнн могӀам]].",
        "ipb-blockingself": "Хьо хьайна блоктоха гӀерта! Лаьий хьона и кхочушдан?",
-       "ipb-edit-dropdown": "Бахьанин список нисяр",
+       "ipb-edit-dropdown": "Бахьанин могӀам нисбар",
        "ipb-unblock-addr": "ДӀаякхаблок $1",
        "ipb-unblock": "дӀаякхаблок декъашхонтӀера я IP-адрес тӀера",
        "ipb-blocklist": "Блоктоьхнарш",
        "blocklogentry": "блоктоьхна [[$1]] цхьана ханна $2 $3",
        "reblock-logentry": "Хийцина  блоктоьхна хан [[$1]] $2 $3",
        "blocklogtext": "Блоктохаршна а блокдӀаякхаршна а тептар. Ша блоккхеташ долу IP-адресаш кхузахь гойтуш дац. Кхин. [[Special:BlockList|хӀийнца блоктоьха берш]].",
-       "unblocklogentry": "дӀаякхинаблок $1",
+       "unblocklogentry": "дӀаяькхинаблок $1",
        "block-log-flags-anononly": "Къайлаха берш",
        "block-log-flags-nocreate": "цамагдо керла дӏаяздарш кхоллар",
        "block-log-flags-noautoblock": "ша блоктухарг дӏаяйина",
        "block-log-flags-noemail": "цамаго кехаташ кхехӀита",
        "block-log-flags-nousertalk": "шин дийцаре агӀо тая лууш дац",
+       "block-log-flags-angry-autoblock": "латина шуьйра автоблоктохар",
        "block-log-flags-hiddenname": "декъашхочун цӀе къайлаяьккхина",
+       "range_block_disabled": "Куьйгалхошна диапазонашна блоктоха цамага до.",
        "ipb_expiry_invalid": "Дешдерг дан нийса йоцу хан.",
        "ipb_already_blocked": "«$1» хӀинцале блоктоьхна ю.",
        "ipb-needreblock": "ХӀокху $1 декъашхочун {{GENDER:$1|блоктоьхна ю}}. Лаьий хьуна блоктохаран параметраш хийца?",
        "ipb_cant_unblock": "ГӀалат: блоктохар цакарий $1. Иза хӀинцале дӀаяьккхина хила мега.",
        "ip_range_invalid": "IP-адресийн магийна йоцу диапазон.",
        "proxyblocker": "Проксин блоктохар",
+       "lockdb": "Хаамийн база еша бен цалуш йе",
+       "unlockdb": "Хаамийн базан чу дӀаяздарш дан аьтту меттахӀотта бе",
+       "lockbtn": "Хаамийн база еша бен цалуш йе",
+       "unlockbtn": "Хаамийн базан чу дӀаяздарш дан аьтту меттахӀотта бе",
+       "locknoconfirm": "Ахьа бакъдеш йолу меттиге билгало йилина яц.",
+       "lockdbsuccesssub": "Хаамийн базан блоктоьхна",
+       "unlockdbsuccesssub": "Хаамийн базан тӀера блокдӀаяьккхина",
        "move-page": "$1 — цӀе хийцар",
        "move-page-legend": "ЦӀe хийца яр",
        "movepagetext": "Бухахь йолу форманца агӀон цӀе хийцало. Цул совнах цуьна хийцаман тептар кхоьчу метте доккха. Хьалхалера цӀарахь хиръю керла кхоьллина агӀонан хьажораг.\n\nХьовсалаш [[Special:DoubleRedirects|шалха]] а [[Special:BrokenRedirects|йохна хьажоргаш]] юй техь аьлла.\n\nШу жоьпехь ду хьажоргаш нийса некъ гойтуш хиларан.\n\nТидам бе хьалхалера агӀон цӀе ‘’’хийцалур яц’’’ иштта цӀе йолу агӀо йолуш елахь. Юкъардаккхар: йолуш йолу агӀо кхоьчухьа хьажораг елахь, я еса елахь а, цуьна хийцаме истори яцахь а.\n\nИ бохург ду шун агӀонан цӀе юха а хьалха хилларгчунтӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
        "semiprotectedpagemovewarning": "'''ДӀахьедо.''' ХӀара агӀо гӀаролла йина ю; дӀабазбиначу декъашхошка бе цӀе хийцалуш яц.\nЛахахьа тептаро балийна тӀаьхьаралера дӀаязбина хаам:",
        "export": "АгӀонаш араяхар",
        "exporttext": "Шуьга далур ду кхечу меттера чудахарш, йоза а хийцаме тептарш билгалла йолу агӀонаш йа гулдина йолу агӀонаш хӀокх XML барамца, юха тӀяхьа чура [[Special:Import|хьаэцалурдолш]] кхечу вики-хьалхен, болх беш йолу хlокху MediaWiki гlирсаца.\n\nКхечу меттера яззамаш чуйаха, чуязйе цӀе тадечу метте, цӀхьа могӀан цӀе могӀаршкахь, юха харжа лаьи шуна Кхечу меттер чуйаха массо яззамашна истори хийцамбарш йа тӀяхьаралера яззамна башхо.\n\nШуьга кхи даландерг, лелаеш йолу меттиг къастаман машан хьажораг кхечу меттер чудаха тӀаьхьарлерачу башхон яззамаш. Масала оцу яззамна [[{{MediaWiki:Mainpage}}]] хӀара хира ю хьажораг [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]].",
+       "exportall": "Массо агӀонаш экспорт ян",
        "exportcuronly": "Карара верси бен юкъа ма тоха, юзийна хьалхалерра истори йоцуш",
        "export-submit": "Экспорт ян",
        "export-addcattext": "ТӀетоха агӀонаш категори чура:",
        "filemissing": "Файл цакарий",
        "thumbnail_error": "Миниатюра кхолларна гӀалат: $1",
        "thumbnail_error_remote": "ГӀалатах хаам $1:\n$2",
+       "thumbnail_image-missing": "$1 файл йоцчух тера ду",
        "import": "АгӀонаш чуяхар",
+       "importinterwiki": "Викиюкъахь-импорт",
        "import-interwiki-source": "Вики-хьост/агlо:",
+       "import-interwiki-history": "ХӀокху агӀона ерриг хийцаман истори копи ян",
        "import-interwiki-templates": "Юкъайихка массо кепаш",
        "import-interwiki-submit": "Импорт ян",
+       "import-interwiki-namespace": "Коьрта цӀерийн меттиг:",
+       "import-interwiki-rootpage": "Коьрта агӀо (тӀехь дац):",
        "import-upload-filename": "Файлан цӀе:",
        "import-comment": "Билгалдаккхар:",
        "importstart": "АгӀонаш импорт яр…",
        "importnopages": "Импорт ян агӀонаш яц.",
        "imported-log-entries": "{{PLURAL:$1|Тептар чура импорт дина $1 дӀаяздар|Тептар чура импорт дина $1 дӀаяздарш}}.",
        "importfailed": "Импорт ян цаелира: $1",
+       "importcantopen": "Цатарло импорт еш йолу файл елла.",
+       "importbadinterwiki": "Нийса йоцу юкъаравики-хьажорг",
+       "importsuccess": "Импорт яр кхочушдина!",
        "importnosources": "Юкъаравики-импортан хьост хаьржина яцара, дуьхьала хийцамашан истори чуяккхар дӀадайина ду.",
+       "importnofile": "Импорт еш йолу файл чуяьккхина яц.",
        "import-noarticle": "Импорт ян агӀонаш яц!",
        "xml-error-string": "$1 $2 могӀан чохь, позицеш $3 (байт $4): $5",
        "import-upload": "Чуяха XML-хаамаш",
        "tooltip-ca-nstab-template": "Куцкепа агlо",
        "tooltip-ca-nstab-help": "ГӀоьна агӀо",
        "tooltip-ca-nstab-category": "Категорешан агӀо",
-       "tooltip-minoredit": "Къастам бé хlокху хийцамна кlеззиг боуш санна",
+       "tooltip-minoredit": "Къастам бé хӀокху хийцамна кӀеззиг болуш санна",
        "tooltip-save": "Хьан хийцамаш lалашбой",
        "tooltip-preview": "Дехар до, агlо lалаш йарал хьалха хьажа муха йу яз!",
        "tooltip-diff": "Гайта долуш долу йозанах бина болу хийцам.",
        "ilsubmit": "Лаха",
        "bydate": "терахьашца",
        "sp-newimages-showfrom": "Гайта керла файлаш $2, $1 тӀера дуьйна",
-       "seconds-abbrev": "$1оцу",
+       "seconds-abbrev": "$1 оцу",
        "minutes-abbrev": "$1 мин",
        "hours-abbrev": "$1 сахь.",
-       "seconds": "{{PLURAL:$1|$1 секунд}}",
-       "minutes": "{{PLURAL:$1|$1 минут}}",
-       "hours": "{{PLURAL:$1|сахьат}}",
-       "days": "{{PLURAL:$1|$1 де}}",
+       "seconds": "{{PLURAL:$1|$1 секунд|$1 секунд}}",
+       "minutes": "{{PLURAL:$1|$1 минут|$1 минут}}",
+       "hours": "{{PLURAL:$1|$1 сахьт|$1 сахьт}}",
+       "days": "{{PLURAL:$1|$1 де|$1 де}}",
        "weeks": "{{PLURAL:$1|$1 кӀира}}",
-       "months": "$1 {{PLURAL:$1|бутт}}",
-       "years": "$1 {{PLURAL:$1|шо}}",
+       "months": "{{PLURAL:$1|$1 бутт|$1 бутт}}",
+       "years": "{{PLURAL:$1|$1 шо|$1 шо}}",
        "ago": "$1 хьалха",
        "just-now": "хӀинца",
-       "hours-ago": "$1 {{PLURAL:$1|сахьт}} хьалха",
+       "hours-ago": "$1 {{PLURAL:$1|сахьт}}",
        "minutes-ago": "$1 {{PLURAL:$1|минут}} хьалха",
        "seconds-ago": "$1 {{PLURAL:$1|секунд}} хьалха",
        "monday-at": "оршотан дийнахь $1",
        "exif-whitebalance": "Къайн баланс",
        "exif-digitalzoomratio": "Терхьаш дукха хиларан коэффициент",
        "exif-scenecapturetype": "Сурт доккхуш йолу меттиган тайп",
+       "exif-contrast": "Къастам",
+       "exif-saturation": "Ӏаьбна",
+       "exif-sharpness": "Къаьсташ хилар",
+       "exif-devicesettingdescription": "Камеран хьолахь лаьцна",
+       "exif-subjectdistancerange": "Сурт тӀехь йолучун хӀуман юкъ",
        "exif-imageuniqueid": "Суьртан номер (ID)",
+       "exif-gpslatituderef": "Шораллин индекс",
        "exif-gpslatitude": "Шоралла",
+       "exif-gpslongituderef": "Дохаллин индекс",
        "exif-gpslongitude": "Дохалла",
+       "exif-gpsaltituderef": "Локхаллин индекс",
        "exif-gpsaltitude": "Локхалла",
+       "exif-gpstimestamp": "UTC-ца нийса хан",
        "exif-gpsdestlatitude": "Объектан дохалла",
        "exif-gpsdatestamp": "Терахь",
        "exif-jpegfilecomment": "JPEG-файлан билгалдаккхар",
        "exif-headline": "Корта",
        "exif-credit": "Кхоьхьург, хьа делла сурт",
        "exif-source": "Хьост",
+       "exif-urgency": "Керлачу хенахь",
+       "exif-fixtureidentifier": "МогӀан цӀе",
+       "exif-locationdest": "Сурт тӀера меттиг",
+       "exif-locationdestcode": "Сурт тӀера меттиган код",
+       "exif-contact": "Контактан хаам",
+       "exif-writer": "Йозан автор",
        "exif-languagecode": "Мотт",
        "exif-iimversion": "Верси IIM",
+       "exif-iimcategory": "Категори",
+       "exif-iimsupplementalcategory": "Кхин тӀе категореш",
+       "exif-datetimeexpires": "Ма лелае тӀехьа",
+       "exif-datetimereleased": "Араяларан терахь",
        "exif-originaltransmissionref": "ДӀадолалун меттиган код",
+       "exif-identifier": "ID",
+       "exif-lens": "ID",
+       "exif-serialnumber": "Камеран серин номер",
+       "exif-cameraownername": "Камера ерг",
        "exif-label": "Билгало",
        "exif-datetimemetadata": "ТӀехьара метахаамаш хийцина терахь",
+       "exif-nickname": "ЧӀагӀъелла йоцу суьртан цӀе",
+       "exif-rating": "Мах хадор (5 нах)",
+       "exif-rightscertificate": "Бакъонийн урхалладаран сертификат",
+       "exif-copyrighted": "Авторийн-бакъонийн статус:",
        "exif-copyrightowner": "Авторийн бакъонаш ерг",
        "exif-usageterms": "Лелоран хьал",
+       "exif-webstatement": "Интернет чохь долу авторийн бакъонийн хьал",
+       "exif-originaldocumentid": "ДӀадолалун документан ша тайпа ID",
+       "exif-licenseurl": "Авторийн лицензин URL",
+       "exif-morepermissionsurl": "Альтернативан лицензин хаам",
        "exif-pngfilecomment": "PNG-файлан билгалдаккхар",
+       "exif-disclaimer": "Бехк тӀе ца эцар",
+       "exif-contentwarning": "Чулацамах лаьцна дӀахьедар",
        "exif-giffilecomment": "GIF-файлан билгалдаккхар",
+       "exif-intellectualgenre": "ХӀуман тайп",
+       "exif-subjectnewscode": "Теман код",
+       "exif-scenecode": "IPTC сценан код",
+       "exif-event": "Сурт тӀе даьккхина хиларг",
+       "exif-organisationinimage": "Сурт тӀера организаци",
+       "exif-personinimage": "Сурт тӀера адам",
        "exif-compression-1": "ТIеIовдан яц",
        "exif-copyrighted-false": "Юкъараллин хьал",
        "exif-unknowndate": "Хууш доцу терахь",
        "exif-whitebalance-0": "Къайн автоматически баланс",
        "exif-whitebalance-1": "Куьйга хӀоттийна къайн баланс",
        "exif-scenecapturetype-0": "Стандартан",
+       "exif-scenecapturetype-3": "Буса даьккхина сурт",
        "exif-gaincontrol-0": "Яц",
+       "exif-gaincontrol-1": "Жим докха дар",
+       "exif-gaincontrol-2": "Дукху доккха дар",
+       "exif-gaincontrol-3": "Дуккху жим дар",
+       "exif-gaincontrol-4": "Дукху жим дар",
        "exif-contrast-0": "Лартӏахь",
+       "exif-contrast-1": "КӀеда айина",
+       "exif-contrast-2": "ЧӀогӀа айина",
        "exif-saturation-0": "Лартӏахь",
+       "exif-saturation-1": "КӀезиг Ӏаьбна",
+       "exif-saturation-2": "Докха Ӏаьбна",
        "exif-sharpness-0": "Лартӏахь",
+       "exif-sharpness-1": "КӀеда айина",
+       "exif-sharpness-2": "ЧӀогӀа айина",
+       "exif-subjectdistancerange-0": "Хууш дац",
+       "exif-subjectdistancerange-1": "Макро сурт даккхар",
+       "exif-subjectdistancerange-2": "Уллера сурт даккхар",
+       "exif-subjectdistancerange-3": "Генара сурт даккхар",
+       "exif-gpslatitude-n": "къилбседера шоралла",
+       "exif-gpslatitude-s": "къилбера шоралла",
+       "exif-gpslongitude-e": "малхбалера дохалла",
+       "exif-gpslongitude-w": "малхбузера шоралла",
        "exif-gpsaltitude-above-sealevel": "Хи хIоттарал локхалла $1 {{PLURAL:$1|метр}}",
        "exif-gpsaltitude-below-sealevel": "Хи хIоттарал локхаллин $1 {{PLURAL:$1|метр}} лахахь",
+       "exif-gpsstatus-a": "Дустар чекх даьлла дац",
+       "exif-gpsstatus-v": "Хаам дӀабала кичча ю",
+       "exif-gpsmeasuremode-2": "Дустар 2-х координаташ",
+       "exif-gpsmeasuremode-3": "Дустар 3-х координаташ",
        "exif-gpsspeed-k": "км/сахьтехь",
        "exif-gpsspeed-m": "миль/сахьтехь",
        "exif-gpsspeed-n": "шеддаш",
        "exif-dc-type": "Медиан тайп",
        "exif-rating-rejected": "ДӀайайина",
        "exif-isospeedratings-overflow": "65535 дукха",
+       "exif-iimcategory-ace": "Исбаьхьалла, культура а синкъерам а",
+       "exif-iimcategory-clj": "Зулам дар а Ӏедал а",
+       "exif-iimcategory-dis": "Ирча бохам а авари а",
+       "exif-iimcategory-fin": "Экономика а бизнес а",
+       "exif-iimcategory-edu": "Дешна хилар",
+       "exif-iimcategory-lab": "Къинхьегам",
+       "exif-iimcategory-rel": "Дин а тешар а",
+       "exif-iimcategory-sci": "Ӏилма а техника а",
+       "exif-iimcategory-soi": "Социалан хаттарш",
+       "exif-iimcategory-wea": "Хенан хӀоттам",
+       "exif-urgency-normal": "Диканиг ($1)",
+       "exif-urgency-low": "Лахара ($1)",
+       "exif-urgency-high": "Лакхара ($1)",
+       "exif-urgency-other": "Декъашхочо билгалйина приоритет ($1)",
        "watchlistall2": "массо",
        "namespacesall": "массо",
        "monthsall": "массо",
+       "confirmemail": "Электронан почтан адрес бакъдар",
+       "confirmemail_noemail": "Ахьа нийса электронан почтан адрес яздина дац [[Special:Preferences|гӀирсан чохь]].",
        "confirmrecreate": "Декъашхочо [[User:$1|$1]] ([[User talk:$1|дийцаре]]) хӀара агӀо дӀаяьккхина, ахьа иза тая йолийча, дӀаяккхарна бахьна:\n: ''$2''\nДехар до, тешал де, хьо иза агӀо меттахӀотто лууш ву/ю але.",
        "confirmrecreate-noreason": "Декъашхочо [[User:$1|$1]] ([[User talk:$1|дийцаре]]) хӀара агӀо дӀаяьккхина, ахьа иза тая йолийча. Дехар до, тешал де, хьо иза агӀо меттахӀотто лууш ву/ю але.",
        "recreate": "Юха кхолла",
        "watchlistedit-clear-submit": "Тергаман могӀам дӀацӀанбан (иза сацадан лурдац)",
        "watchlistedit-clear-done": "Хьан тергаман могӀам дӀацӀанбина",
        "watchlistedit-clear-removed": "{{PLURAL:$1|ДӀаяьккхина|ДӀаяьхна}} $1 {{PLURAL:$1|дӀаяздар|дӀаяздарш}}:",
-       "watchlistedit-too-many": "Ð\9aÑ\85Ñ\83ззаÑ\85Ñ\8c Ð³Ð°Ð¹Ñ\82а Ñ\82Ó\80еÑ\85Ñ\8c Ð´Ñ\83кÑ\85а Ð°Ð³Ó\80онаÑ\88 Ñ\8e.",
+       "watchlistedit-too-many": "Кхузахь гайта тӀехь дукха агӀонаш ю.",
        "watchlisttools-clear": "Тергаман могӀам дӀацӀанбан",
        "watchlisttools-view": "МогӀам чура агӀонашан хийцамаш",
        "watchlisttools-edit": "Хьажа/нисбé могӀам",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|дийцаре]])",
        "version": "Верси MediaWiki",
        "version-extensions": "ДӀахӀоттийна шордарш",
-       "version-skins": "Ð\9aечяран темаш",
+       "version-skins": "Ð\94Ó\80аÑ\85Ó\80оÑ\82Ñ\82ийна Ðºечяран темаш",
        "version-specialpages": "Белхан агӀонаш",
        "version-parserhooks": "Cинтаксисан къастор схьалоцурш",
        "version-variables": "Хийцаме",
        "version-other": "Кхин",
        "version-mediahandlers": "Медиа кеч ерраш",
+       "version-hooks": "Схьалуьцарш",
        "version-parser-extensiontags": "Cинтаксисан къасторан шораллин тегаш",
        "version-parser-function-hooks": "Cинтаксисан къасторан функци схьалоцурш",
+       "version-hook-name": "Схьалуьцачун цӀе",
+       "version-hook-subscribedby": "ДӀабазбелла тӀе",
        "version-version": "(Верси $1)",
-       "version-license": "Бакъо",
+       "version-no-ext-name": "[цӀе йоцуш]",
+       "version-license": "MediaWiki Лицензи",
        "version-ext-license": "Лицензи",
        "version-ext-colheader-name": "Шордарш",
+       "version-skin-colheader-name": "Кечяран тема",
        "version-ext-colheader-version": "Верси",
        "version-ext-colheader-license": "Лицензи",
        "version-ext-colheader-description": "Цуьнах лаьцна",
        "version-ext-colheader-credits": "Автораш",
+       "version-license-title": "Лицензи цу $1",
+       "version-credits-title": "Авторийн могӀам цу $1",
        "version-poweredby-credits": "ХӀара вики болх беш ю '''[https://www.mediawiki.org/ MediaWiki]''' движок тӀехь, copyright © 2001-$1 $2.",
        "version-poweredby-others": "кхин",
        "version-poweredby-translators": "гочдархой translatewiki.net",
        "version-license-info": "MediaWiki ю маьрша программин латораг, шу йиш ю фондас арахецна йолу GNU General Public License лицензица и яржо я хийца а.\n\nMediaWiki яржош ю и шуна пайдане хир яц те аьлла, амма  ЦХЬА ЮКЪАРАХИЛАР ДОЦУШ. Хь. кхин. лицензи мадарра GNU General Public License .\n\nШоьга кхача езаш яра [{{SERVER}}{{SCRIPTPATH}}/COPYING копи GNU General Public License] хӀокху программица, кхаьчна яцахь язъе Free Software Foundation, Inc., адрес тӀе: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA я [//www.gnu.org/licenses/old-licenses/gpl-2.0.html еша и онлайнехь].",
        "version-software": "ДӀахӀоттийна программин латтор",
+       "version-software-product": "Сурсат",
        "version-software-version": "Верси",
        "version-entrypoints": "ЧугӀо адресин тӀадамаш",
        "version-entrypoints-header-entrypoint": "Яздаран тӀадам",
        "redirect-lookup": "Лаха:",
        "redirect-value": "МаьӀна:",
        "redirect-user": "Декъашхочун ID",
+       "redirect-page": "АгӀона ID",
        "redirect-revision": "АгӀона верси",
        "redirect-file": "Файлан цӀе",
+       "redirect-not-exists": "МаьӀна цакарий",
        "fileduplicatesearch": "Лаха цхьатера йолу файлаш",
        "fileduplicatesearch-summary": "Лаха цхьатера йолу файлаш хэш-кодаца.",
        "fileduplicatesearch-legend": "Цхьатера ерш лахар",
        "fileduplicatesearch-filename": "Файлан цӀе:",
        "fileduplicatesearch-submit": "Лаха",
        "fileduplicatesearch-info": "$1 × $2 пиксель<br />Файлан барам: $3<br />MIME-тайп: $4",
+       "fileduplicatesearch-result-1": "«$1» файлах тера хӀума яц.",
        "fileduplicatesearch-noresults": "ЦӀе «$1» йолуш файл цакарий.",
        "specialpages": "Леррина агlонаш",
        "specialpages-note": "* Гуттарлера белха агlонаш.\n* <strong class=\"mw-specialpagerestricted\">Кlеззиг таронаш йолу леррина агlонаш.</strong>",
        "htmlform-no": "ХӀахӀа",
        "htmlform-yes": "ХӀаъ",
        "htmlform-chosen-placeholder": "Харжа кеп",
+       "htmlform-cloner-create": "ТӀетоха кхин",
+       "htmlform-cloner-delete": "ДӀаяккха",
        "logentry-delete-delete": "$1 {{GENDER:$2|дӀаяьккхина}} агӀо $3",
        "logentry-delete-restore": "$1 {{GENDER:$2|меттахӀоттайина|меттахӀоттайина}} агӀо $3",
        "logentry-delete-event": "$1 {{GENDER:$2|хийцина}} гуш хилар {{PLURAL:$5|1=$5 дӀаяздаран|$5 дӀаяздаршан}} тептаран → $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|хийцина}} {{PLURAL:$5|1=$5 верси|$5 версеш}} гуш хилар $3: $4 агӀорахь",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|хийцина}} $3 агӀона тептаран дӀаяздарш гуш хилар",
        "logentry-delete-revision-legacy": "$1 {{GENDER:$2|хийцина}} $3 агӀона верси гуш хилар",
+       "logentry-suppress-delete": "$1 {{GENDER:$2|дӀаяьккхина}} агӀо $3",
        "logentry-suppress-event": "$1 къайлаха {{GENDER:$2|хийцина}} тептаран {{PLURAL:$5|1=$5 дӀаяздар|$5 дӀаяздарш}} гуш хилар $3: $4 чохь",
        "logentry-suppress-revision": "$1 къайлаха {{GENDER:$2|хийцина}} {{PLURAL:$5|1=$5 верси|$5 версеш}} $3: $4 чохь гуш хилар",
        "logentry-suppress-event-legacy": "$1 къайлаха {{GENDER:$2|хийцина}} $3 тептар чура дӀаяздарш гуш хилар",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|цӀе хийцина}} $3 → $4 дӀасахьажийнарг цаюьтуш",
        "logentry-move-move_redir": "$1 {{GENDER:$2|цӀе хийцина}} $3 → $4 дӀасахьажоран тӀохул",
        "logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|цӀе хийцина}} $3 → $4 дӀасахьажоран тӀохул а дӀасахьажийнарг цаюьтуш а",
+       "logentry-patrol-patrol": "$1 {{GENDER:$2|хьаьжина}}  агӀона $3 $4 версега",
        "logentry-patrol-patrol-auto": "$1 автоматически {{GENDER:$2|хьаьжина}} $3 агӀона версега $4",
        "logentry-newusers-newusers": "{{GENDER:$2|ДӀавазвелла|ДӀаязелла}} керла декъашхо $1",
        "logentry-newusers-create": "{{GENDER:$2|ДӀавазвелла|ДӀаязелла}} керла декъашхо $1",
+       "logentry-newusers-create2": "$1 {{GENDER:$2|кхоьллина}} декъашхочун дӀаяздапр $3",
+       "logentry-newusers-byemail": "$1 {{GENDER:$2|кхоьллина}} декъашхочун дӀаяздар $3 пароль электронан почте яхьийтина",
        "logentry-newusers-autocreate": "Автоматически кхоьллина {{GENDER:$2|декъашхочун}} $1 дӀаяздар",
        "logentry-rights-rights": "$1 {{GENDER:$2|хийцина}} $3 бакъо $4 → $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|хийцина}} хӏокхуна $3 бакъо",
+       "logentry-rights-autopromote": "$1 {{GENDER:$2|вара|яра}} автоматически {{GENDER:$2|сихьа ваьлла|сихьа яьлла}} $4 $5 чу",
        "rightsnone": "(яц)",
+       "feedback-bugornote": "Хьайн техникин халонах лаьцна яздан хӀума делахь, дехар до, [$1 хаам бе тхоьга].\nДацахь хьан йиш ю хӀокху атта кепаца «[$3 $2]» агӀонг къамел тӀетоха хьан декъашхочун цӀарца, кхин лелош йолу браузер билгал еш.",
+       "feedback-subject": "Къамел:",
+       "feedback-message": "Хаам:",
        "feedback-cancel": "Цаоьшу",
+       "feedback-submit": "Дахьийта хетарг",
+       "feedback-adding": "АгӀона хетарг тӀетохар...",
        "feedback-close": "Кийчча ю",
        "searchsuggest-search": "Лаха",
        "searchsuggest-containing": "чуьраниг…",
        "api-error-duplicate": "Иштта чулацам болу {{PLURAL:$1|1=[$2 кхин файл]|[$2 кхин файлаш]}} йолуш ю",
        "api-error-duplicate-popup-title": "{{PLURAL:$1|1=Файлан|Файлийн}} дубликат.",
        "api-error-empty-file": "Ахьа яхьийтина файл еса ю.",
+       "api-error-mustbeposted": "Чоьхьара гӀалат: дехаро хьехам схьабоьху HTTP POST.",
        "api-error-noimageinfo": "Кхиамца чуяьккхина, амма серверо файлахь лаьцна цхьаа хаам битина бац.",
        "api-error-nomodule": "Чоьхьара гӀалат: чуйокху модуль нисйина яц.",
        "api-error-ok-but-empty": "Чоьхьара гӀалат: серверара жоп дац.",
        "limitreport-cputime": "Процессоран хан лелор",
        "limitreport-cputime-value": "$1 {{PLURAL:$1|секунд}}",
        "limitreport-walltime": "Йодуш йолу хенахь лелор",
-       "limitreport-walltime-value": "$1 {{PLURAL:$1|секунд}}",
+       "limitreport-walltime-value": "$1 секунд",
        "limitreport-ppvisitednodes": "Препроцессор хьаьжна шадин дукхалла",
        "limitreport-ppgeneratednodes": "Препроцессорс сгенерировать бина шадин дукхалла",
        "limitreport-postexpandincludesize": "Схьаяьстина юккъерчаран барам",
        "expand_templates_remove_nowiki": "ДӀайоху тегаш <nowiki> хилча",
        "expand_templates_generate_xml": "Гойту дитта цу XML",
        "expand_templates_generate_rawhtml": "Гайта HTML",
-       "expand_templates_preview": "Хьалха муха ю хьажа"
+       "expand_templates_preview": "Хьалха муха ю хьажа",
+       "pagelanguage": "АгӀона мотт харжар",
+       "pagelang-name": "АгӀо",
+       "pagelang-language": "Мотт",
+       "pagelang-use-default": "Ӏад битарца мотт",
+       "pagelang-select-lang": "Харжа мотт",
+       "right-pagelang": "АгӀона мотт хийца",
+       "action-pagelang": "агӀона мотт хийца",
+       "log-name-pagelang": "Мотт хийцаран тептар",
+       "log-description-pagelang": "ХӀара агӀонашкахь мотт хийцаран тептар ду.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|хийцина}} агӀона мотт $3 $4 → $5."
 }
index 42f53e3..db28279 100644 (file)
@@ -13,7 +13,8 @@
                        "Muhammed taha",
                        "رزگار",
                        "아라",
-                       "Serwan"
+                       "Serwan",
+                       "Ebraminio"
                ]
        },
        "tog-underline": "ھێڵ ھێنان بەژێر بەستەرەکان:",
        "talkpagelinktext": "لێدوان",
        "specialpage": "په‌ڕه‌ی تایبه‌ت",
        "personaltools": "ئامڕازە تاکەکەسییەکان",
-       "postcomment": "بەشی نوێ",
        "articlepage": "پەڕەی ناوەرۆک ببینە",
        "talk": "وتووێژ",
        "views": "بینینەکان",
        "externaldberror": "یان هەڵەی ڕێگەپێدانی بنکەدراو هەیە یان ڕێگات پێ نادرێت بۆ نوێ کردنی هەژماری دەرەکیت.",
        "login": "بچۆ ژوورەوە",
        "nav-login-createaccount": "بچۆ ژوورەوە / ھەژمار دروست بکە",
-       "loginprompt": "بۆ چوونەژوورەوە بۆ {{SITENAME}} دەبێ کوکییەکان چالاک بکەیت.",
        "userlogin": "بچۆ ژوورەوە / ھەژمار دروست بکە",
        "userloginnocreate": "بچۆ ژوورەوە",
        "logout": "بچۆ دەرەوە",
        "undeleteviewlink": "دیتن",
        "undeleteinvert": "ھەڵبژاردەکان پێچەوانە بکە",
        "undeletecomment": "هۆکار:",
-       "undeletedrevisions": "{{PLURAL:$1|1 پێداچوونەوە|$1 پێداچوونەوە}} هێنرایەوە",
+       "undeletedrevisions": "{{PLURAL:$1|$1 پێداچوونەوە}} هێنرایەوە",
        "undeletedrevisions-files": "{{PLURAL:$1|1 پێداچوونەوە|$1 پێداچوونەوە}} و {{PLURAL:$2|1 پەڕگە|$2 پەڕگە}} هێنرایەوە",
        "undeletedfiles": "{{PLURAL:$1|1 پەڕگە|$1 پەڕگە}} هێنرایەوه",
        "cannotundelete": "ھێنانەوە سەرکەوتوو نەبوو:\n$1",
index f87c2e2..250b228 100644 (file)
        "talkpagelinktext": "diskuse",
        "specialpage": "Speciální stránka",
        "personaltools": "Osobní nástroje",
-       "postcomment": "Nová sekce",
        "articlepage": "Prohlédnout si stránku",
        "talk": "Diskuse",
        "views": "Zobrazení",
        "externaldberror": "Buď nastala chyba externí autentizační databáze, nebo nemáte dovoleno měnit svůj externí účet.",
        "login": "Přihlaste se",
        "nav-login-createaccount": "Přihlášení / vytvoření účtu",
-       "loginprompt": "K přihlášení do {{grammar:2sg|{{SITENAME}}}} musíte mít povoleny cookies.",
        "userlogin": "Přihlášení / vytvoření účtu",
        "userloginnocreate": "Přihlášení",
        "logout": "Odhlásit se",
        "loginerror": "Chyba při přihlašování",
        "createacct-error": "Chyba při zakládání účtu",
        "createaccounterror": "Nepodařilo se vytvořit uživatelský účet: $1",
-       "nocookiesnew": "Uživatelský účet byl vytvořen, ale nejste přihlášeni. {{SITENAME}} používá cookies k přihlášení uživatelů. Vy máte cookies vypnuty. Prosím zapněte je a přihlaste se znovu s vaším novým uživatelským jménem a heslem.",
+       "nocookiesnew": "Uživatelský účet byl vytvořen, ale nejste přihlášeni. {{SITENAME}} používá cookies k přihlášení uživatelů. Vy máte cookies vypnuty. Prosím, zapněte je a poté se přihlaste svým novým uživatelským jménem a heslem.",
        "nocookieslogin": "{{SITENAME}} používá cookies k přihlášení uživatelů. Vy máte cookies vypnuty. Prosím zapněte je a zkuste znovu.",
        "nocookiesfornew": "Uživatelský účet nebyl založen, neboť jsme nebyli schopni potvrdit jeho původ.\nUjistěte se, že máte povoleny cookies, obnovte tuto stránku a zkuste to znovu.",
        "noname": "Musíte uvést jméno svého účtu.",
        "revdelete-text-text": "Smazané editace se budou i nadále zobrazovat v historii stránky, ale části jejich obsahu nebudou veřejně přístupné.",
        "revdelete-text-file": "Smazané verze souborů se budou i nadále zobrazovat v historii stránky, ale části jejich obsahu nebudou veřejně přístupné.",
        "logdelete-text": "Smazané protokolovací záznamy se budou i nadále zobrazovat v historii stránky, ale části jejich obsahu nebudou veřejně přístupné.",
-       "revdelete-text-others": "Ostatní správci {{grammar:2sg|{{SITENAME}}}} budou i nadále moci ke skrytému obsahu přistupovat a mohou ho pomocí stejného rozhraní obnovit, pokud nejsou nastavena dodatečná omezení.",
+       "revdelete-text-others": "Ostatní správci budou i nadále moci ke skrytému obsahu přistupovat a mohou ho obnovit, pokud nejsou nastavena dodatečná omezení.",
        "revdelete-confirm": "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]].",
        "revdelete-suppress-text": "Utajování by se mělo používat '''pouze''' v následujících případech:\n* Potenciálně pomlouvačné informace\n* Nevhodné osobní údaje\n*: ''adresy bydliště a telefonní čísla, rodná čísla apod.''",
        "revdelete-legend": "Nastavit omezení viditelnosti",
        "right-deletedtext": "Prohlížení smazaného textu a rozdílů mezi smazanými verzemi",
        "right-browsearchive": "Vyhledávání ve smazaných stránkách",
        "right-undelete": "Obnovování smazaných stránek",
-       "right-suppressrevision": "Prohlížení a obnovování revizí skrytých před správci",
+       "right-suppressrevision": "Prohlížení, skrývání a odkrývání revizí skrytých před všemi uživateli",
+       "right-viewsuppressed": "Prohlížení revizí skrytých před všemi uživateli",
        "right-suppressionlog": "Prohlížení skrytých protokolovacích záznamů",
        "right-block": "Blokování možnosti editace ostatním uživatelům",
        "right-blockemail": "Blokování možnosti poslat e-mail",
        "license": "Licence:",
        "license-header": "Licence",
        "nolicense": "Bez udání licence",
+       "licenses-edit": "Editovat nabídku licencí",
        "license-nopreview": "(Náhled není dostupný)",
        "upload_source_url": " (platné, veřejně přístupné URL)",
        "upload_source_file": " (soubor ve vašem počítači)",
+       "listfiles-delete": "smazat",
        "listfiles-summary": "Tato speciální stránka zobrazuje všechny načtené soubory.",
        "listfiles_search_for": "Hledat soubor podle názvu:",
        "imgfile": "soubor",
        "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]].",
+       "wantedfiletext-cat-noforeign": "Následující soubory se používají, ale neexistují. Stránky, které používají neexistující soubory, jsou navíc uvedeny v [[:$1]].",
        "wantedfiletext-nocat": "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>.",
+       "wantedfiletext-nocat-noforeign": "Následující soubory se používají, ale neexistují.",
        "wantedtemplates": "Chybějící šablony",
        "mostlinked": "Nejodkazovanější stránky",
        "mostlinkedcategories": "Nejpoužívanější kategorie",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskuse]])",
        "unknown_extension_tag": "Neznámá značka rozšíření: „$1“",
        "duplicate-defaultsort": "Upozornění: Implicitní klíč řazení (DEFAULTSORTKEY) „$2“ přepisuje dříve nastavenou hodnotu „$1“.",
+       "duplicate-displaytitle": "<strong>Upozornění:</strong> Předchozí zobrazovaný název „$1“ je nahrazen zobrazovaným názvem „$2“.",
        "version": "Verze",
        "version-extensions": "Nainstalovaná rozšíření",
        "version-skins": "Nainstalované vzhledy",
        "expand_templates_remove_nowiki": "Potlačit ve výsledku značky <nowiki>",
        "expand_templates_generate_xml": "Zobrazit syntaktický strom v XML",
        "expand_templates_generate_rawhtml": "Zobrazit surové HTML",
-       "expand_templates_preview": "Náhled"
+       "expand_templates_preview": "Náhled",
+       "pagelanguage": "Volba jazyka stránky",
+       "pagelang-name": "Stránka",
+       "pagelang-language": "Jazyk",
+       "pagelang-use-default": "Použít implicitní jazyk",
+       "pagelang-select-lang": "Vybrat jazyk",
+       "right-pagelang": "Změnit jazyk stránky",
+       "action-pagelang": "měnit jazyk stránky",
+       "log-name-pagelang": "Kniha změn jazyků",
+       "log-description-pagelang": "Toto je protokol změn jazyků stránek.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|změnil|změnila}} jazyk stránky $3 z $4 na $5."
 }
index 4a891b2..fe284ae 100644 (file)
        "talkpagelinktext": "Sgwrs",
        "specialpage": "Tudalen Arbennig",
        "personaltools": "Offer personol",
-       "postcomment": "Adran newydd",
        "articlepage": "Dangos tudalen bwnc",
        "talk": "Sgwrs",
        "views": "Golygon",
        "createacct-another-realname-tip": "Gallwch ddewis roi eich enw go iawn.\nOs y gwnewch, fe gaiff yr enw go iawn ei defnyddio wrth dadogi'ch gwaith.",
        "pt-login": "Mewngofnodi",
        "pt-login-button": "Mewngofnoder",
-       "pt-createaccount": "Creu cyfri",
+       "pt-createaccount": "Crëwch gyfrif",
        "pt-userlogout": "Allgofnodi",
        "php-mail-error-unknown": "Gwall anhysbys yng ngweithrediad post() PHP",
        "user-mail-no-addy": "Wedi ceisio anfon e-bost heb gyfeiriad e-bost",
        "duplicate-defaultsort": "Rhybudd: Mae'r allwedd trefnu diofyn \"$2\" yn gwrthwneud yr allwedd trefnu diofyn blaenorol \"$1\".",
        "version": "Fersiwn",
        "version-extensions": "Estyniadau gosodedig",
+       "version-skins": "Gweddau",
        "version-specialpages": "Tudalennau arbennig",
        "version-parserhooks": "Bachau dosrannydd",
        "version-variables": "Newidynnau",
        "version-antispam": "Atal sbam",
-       "version-skins": "Gweddau",
        "version-other": "Arall",
        "version-mediahandlers": "Trinyddion cyfryngau",
        "version-hooks": "Bachau",
index 028f1c7..b505ce4 100644 (file)
        "talkpagelinktext": "diskussion",
        "specialpage": "Speciel side",
        "personaltools": "Personlige værktøjer",
-       "postcomment": "Nyt afsnit",
        "articlepage": "Se artiklen",
        "talk": "Diskussion",
        "views": "Visninger",
        "externaldberror": "Der er opstået en fejl i en ekstern adgangsdatabase, eller du har ikke rettigheder til at opdatere denne.",
        "login": "Log på",
        "nav-login-createaccount": "Opret en konto eller log på",
-       "loginprompt": "Du skal have cookies slået til for at kunne logge på {{SITENAME}}.",
        "userlogin": "Opret en konto eller log på",
        "userloginnocreate": "Log på",
        "logout": "Log af",
        "right-move": "Flytte sider",
        "right-move-subpages": "Flytte sider og undersider",
        "right-move-rootuserpages": "Flytte hovedbrugersider",
+       "right-move-categorypages": "Flytte kategorisider",
        "right-movefile": "Flytte filer",
        "right-suppressredirect": "Flytte sider uden at oprette en omdirigering fra det gamle navn",
        "right-upload": "Lægge filer op",
        "action-move": "flytte denne side",
        "action-move-subpages": "flytte denne side og dens undersider",
        "action-move-rootuserpages": "flytte hovedbrugersider",
+       "action-move-categorypages": "flytte kategorisider",
        "action-movefile": "flytte denne fil",
        "action-upload": "lægge denne fil op",
        "action-reupload": "overskrive den nuværende fil",
        "watchlistedit-raw-done": "Din overvågningsliste blev opdateret.",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 side|$1 sider}} er tilføjet:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 side|$1 sider}} er fjernet:",
+       "watchlisttools-clear": "Ryd overvågningsliste",
        "watchlisttools-view": "Se ændrede sider i overvågningslisten",
        "watchlisttools-edit": "Rediger overvågningsliste",
        "watchlisttools-raw": "Rediger rå overvågningsliste",
        "duplicate-defaultsort": "Advarsel: Standardsorteringsnøglen \"$2\" tilsidesætter den tidligere sorteringsnøgle \"$1\".",
        "version": "Information om MediaWiki",
        "version-extensions": "Installerede udvidelser",
+       "version-skins": "Udseender",
        "version-specialpages": "Specialsider",
        "version-parserhooks": "Parserfunktioner",
        "version-variables": "Variabler",
        "version-antispam": "Spamforebyggelse",
-       "version-skins": "Udseender",
        "version-other": "Andet",
        "version-mediahandlers": "Specialhåndtering af mediefiler",
        "version-hooks": "Funktionstilføjelser",
index f1bd8f8..c5b8ca4 100644 (file)
        "talkpagelinktext": "Diskussion",
        "specialpage": "Spezialseite",
        "personaltools": "Meine Werkzeuge",
-       "postcomment": "Neuer Abschnitt",
        "articlepage": "Inhaltsseite anzeigen",
        "talk": "Diskussion",
        "views": "Ansichten",
        "externaldberror": "Entweder liegt ein Fehler bei der externen Authentifizierung vor oder du darfst dein externes Benutzerkonto nicht aktualisieren.",
        "login": "Anmelden",
        "nav-login-createaccount": "Anmelden / Benutzerkonto erstellen",
-       "loginprompt": "Zur Anmeldung müssen Cookies aktiviert sein.",
        "userlogin": "Anmelden / Benutzerkonto anlegen",
        "userloginnocreate": "Anmelden",
        "logout": "Abmelden",
        "revdelete-text-text": "Gelöschte Versionen verbleiben noch in der Versionsgeschichte, jedoch sind Teile ihres Inhalts für die Öffentlichkeit nicht zugänglich.",
        "revdelete-text-file": "Gelöschte Dateiversionen verbleiben noch in der Datei-Versionsgeschichte, jedoch sind Teile ihres Inhalts für die Öffentlichkeit nicht zugänglich.",
        "logdelete-text": "Gelöschte Logbucheinträge verbleiben noch in den Logbüchern, jedoch sind Teile ihres Inhalts für die Öffentlichkeit nicht zugänglich.",
-       "revdelete-text-others": "Andere Administratoren auf {{SITENAME}} haben noch Zugriff auf den versteckten Inhalt und können ihn auch mithilfe dieser Spezialseite wiederherstellen, solange keine zusätzlichen Beschränkungen festgelegt werden.",
+       "revdelete-text-others": "Andere Administratoren haben noch Zugriff auf den versteckten Inhalt und können ihn auch wiederherstellen, solange keine zusätzlichen Beschränkungen festgelegt werden.",
        "revdelete-confirm": "Bitte bestätige, dass du beabsichtigst, dies zu tun, die Konsequenzen verstehst und es in Übereinstimmung mit den [[{{MediaWiki:Policy-url}}|Richtlinien]] tust.",
        "revdelete-suppress-text": "Unterdrückungen sollten '''nur''' in den folgenden Fällen vorgenommen werden:\n* Potentiell beleidigende Informationen\n* Unangebrachte persönliche Informationen\n*: ''Adressen, Telefonnummern, Sozialversicherungsnummern etc.''",
        "revdelete-legend": "Setzen der Sichtbarkeitseinschränkungen",
        "right-deletedtext": "Gelöschte Texte und Versionsunterschiede zwischen gelöschten Versionen ansehen",
        "right-browsearchive": "Nach gelöschten Seiten suchen",
        "right-undelete": "Seiten wiederherstellen",
-       "right-suppressrevision": "Versionen ansehen und wiederherstellen, die auch vor Administratoren verborgen sind",
+       "right-suppressrevision": "Spezielle Seitenversionen von jedem Benutzer ansehen, verstecken und wiederherstellen",
+       "right-viewsuppressed": "Versteckte Versionen von jedem Benutzer ansehen",
        "right-suppressionlog": "Private Logbücher ansehen",
        "right-block": "Benutzer sperren (Schreibrecht)",
        "right-blockemail": "Benutzer am Versenden von E-Mails hindern",
        "license": "Lizenz:",
        "license-header": "Lizenz",
        "nolicense": "Keine Vorauswahl",
+       "licenses-edit": "Lizenzoptionen bearbeiten",
        "license-nopreview": "(es ist keine Vorschau verfügbar)",
        "upload_source_url": " (gültige, öffentlich zugängliche URL)",
        "upload_source_file": " (eine Datei auf deinem Computer)",
+       "listfiles-delete": "löschen",
        "listfiles-summary": "Diese Spezialseite listet alle hochgeladenen Dateien auf.",
        "listfiles_search_for": "Suche nach Datei:",
        "imgfile": "Datei",
        "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.",
+       "wantedfiletext-cat-noforeign": "Die folgenden Dateien werden verwendet, sind jedoch nicht vorhanden. Zusätzlich werden Seiten auf [[:$1]] gelistet, die nicht vorhandene Dateien einbetten.",
        "wantedfiletext-nocat": "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.",
+       "wantedfiletext-nocat-noforeign": "Die folgenden Dateien werden verwendet, sind jedoch nicht vorhanden.",
        "wantedtemplates": "Gewünschte Vorlagen",
        "mostlinked": "Seiten mit den meisten Links",
        "mostlinkedcategories": "Meistbenutzte Kategorien",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|Diskussion]])",
        "unknown_extension_tag": "Unbekanntes Parsertag „$1“",
        "duplicate-defaultsort": "Achtung: Der Sortierungsschlüssel „$2“ überschreibt den vorher verwendeten Schlüssel „$1“.",
+       "duplicate-displaytitle": "<strong>Warnung:</strong> Der Anzeigetitel „$2“ überschreibt den früheren Anzeigetitel „$1“.",
        "version": "Version",
        "version-extensions": "Installierte Erweiterungen",
        "version-skins": "Installierte Benutzeroberflächen",
index 2313c1f..0ed4a54 100644 (file)
        "talkpagelinktext": "Vatenayış",
        "specialpage": "Pela xısusiye",
        "personaltools": "Hacetê şexsiy",
-       "postcomment": "Qısımo newe",
        "articlepage": "Pela zerreki bıvêne",
-       "talk": "Vatenkerdış",
+       "talk": "Werênayış",
        "views": "Asayışi",
        "toolbox": "Haceti",
        "userpage": "Pela karberi bıvêne",
        "versionrequired": "No $1 MediaWiki lazımo",
        "versionrequiredtext": "Seba gurenayışê na pele versiyonê MediaWiki $1 lazımo. \n[[Special:Version|Versiyonê pele]] bıvêne.",
        "ok": "Temam",
-       "pagetitle": "\"$1\" adres ra gerya.",
+       "pagetitle": "$1 – {{SITENAME}}",
        "pagetitle-view-mainpage": "{{SITENAME}}",
        "backlinksubtitle": "← $1",
        "retrievedfrom": "\"$1\" ra ard",
        "externaldberror": "Ya database de xeta esta ya zi heqê şıma çino şıma no hesab bıvurni.",
        "login": "Cı kewe",
        "nav-login-createaccount": "Dekew de / hesab vıraze",
-       "loginprompt": "{{SITENAME}} dı ronıştış akerdışi rê ''çerezan'' aktiv kerdış icab keno.",
        "userlogin": "Cı kewe / hesab vıraze",
        "userloginnocreate": "Cı kewe",
        "logout": "Bıveciye",
        "pagemerge-logentry": "[[$1]] u [[$2]] yew kerd (revizyonî heta $3)",
        "revertmerge": "Abırnê",
        "mergelogpagetext": "Cêr de yew liste esta ke mocnena ra, raya tewr peyêne kamci pela tarixi be a bine ra şanawa pê.",
-       "history-title": "Rewizyonê $1:",
+       "history-title": "Tarixê çımraviyarnayışê \"$1\"",
        "difference-title": "Pela \"$1\" ferqê çım ra viyarnayışan",
        "difference-title-multipage": "Ferkê pelan dê \"$1\" u \"$2\"",
        "difference-multipage": "(Ferqê pelan)",
        "created": "viraziya",
        "changed": "vurneya",
        "deletepage": "Pele bestere",
-       "confirm": "Testiq ke",
+       "confirm": "Tesdiq ke",
        "excontent": "Zerreko verén: '$1'",
        "excontentauthor": "Zerrey cı: '$1' no/na ('[[Special:Contributions/$2|$2]]'  teyna iştıraq kerdo)",
        "exbeforeblank": "behsê verê esteriyayişi: '$1'",
        "duplicate-defaultsort": "'''Tembe:''' Hesıbyaye sırmey ratnayış de \"$2\" sırmey ratnayış de \"$1\"i nêhesıbneno.",
        "version": "Versiyon",
        "version-extensions": "Ekstensiyonî ke ronaye",
+       "version-skins": "Cıldi",
        "version-specialpages": "Pelanê xasiyan",
        "version-parserhooks": "Çengelê Parserî",
        "version-variables": "Vurnayeyî",
        "version-antispam": "Spam vındarnayış",
-       "version-skins": "Cıldi",
        "version-api": "API",
        "version-other": "Bin",
        "version-mediahandlers": "Kulbê medyayî",
index 0c7869c..5aec3ec 100644 (file)
@@ -37,7 +37,8 @@
                        "לערי ריינהארט",
                        "Kolega2357",
                        "아라",
-                       "Calak"
+                       "Calak",
+                       "Auslaender"
                ]
        },
        "tog-underline": "Υπογράμμιση συνδέσμων:",
        "talkpagelinktext": "Συζήτηση",
        "specialpage": "Ειδική σελίδα",
        "personaltools": "Προσωπικά εργαλεία",
-       "postcomment": "Νέα ενότητα",
        "articlepage": "Εμφάνιση σελίδας περιεχομένου",
        "talk": "Συζήτηση",
        "views": "Προβολές",
        "externaldberror": "Είτε συνέβη κάποιο σφάλμα εξωτερικής πιστοποίησης της βάσης δεδομένων είτε δεν σας έχει επιτραπεί να ενημερώσετε τον εξωτερικό σας λογαριασμό.",
        "login": "Είσοδος",
        "nav-login-createaccount": "Είσοδος / δημιουργία λογαριασμού",
-       "loginprompt": "Πρέπει να έχετε ενεργοποιήσει τα cookies για να συνδεθείτε στον ιστοχώρο {{SITENAME}}.",
        "userlogin": "Είσοδος / δημιουργία λογαριασμού",
        "userloginnocreate": "Είσοδος",
        "logout": "Έξοδος",
        "recentchanges-label-unpatrolled": "Αυτή η επεξεργασία δεν έχει ελεγχθεί ακόμα",
        "recentchanges-label-plusminus": "Μεταβολή του μεγέθους της σελίδας σε bytes",
        "recentchanges-legend-heading": "'''Υπόμνημα:'''",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (δείÏ\84ε [[Special:NewPages|Î\9dέεÏ\82 Ï\83ελίδεÏ\82]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (δείÏ\84ε [[Special:NewPages|καÏ\84άλογοÏ\82 Î½Î­Ï\89ν Ï\83ελίδÏ\89ν]])",
        "rcnotefrom": "Παρακάτω είναι οι αλλαγές από τις <strong>$2</strong>  (εμφανίζονται μέχρι <strong>$1</strong> ).",
        "rclistfrom": "Εμφάνιση νέων αλλαγών αρχίζοντας από $3 $2",
        "rcshowhideminor": "$1 μικροεπεξεργασιών",
        "largefileserver": "Το μέγεθος αυτού του αρχείο είναι μεγαλύτερο από το μέγιστο μέγεθος που ο εξυπηρετητής είναι ρυθμισμένος να επιτρέπει.",
        "emptyfile": "Το αρχείο που φορτώσατε φαίνεται να είναι κενό. Αυτό μπορεί να οφείλεται σε λάθος πληκτρολόγησης του ονόματος του αρχείου. Παρακαλούμε ελέγξτε εαν αυτό είναι πραγματικά το αρχείο που θέλετε να φορτώσετε.",
        "windows-nonascii-filename": "Αυτό το wiki δεν υποστηρίζει ονόματα αρχείων με ειδικούς χαρακτήρες.",
-       "fileexists": "Υπάρχει ήδη αρχείο με αυτό το όνομα, παρακαλούμε ελέγξτε το <strong>[[:$1]]</strong> εάν δεν είστε σίγουρος/η αν θέλετε να το αλλάξετε.\n[[$1|thumb]]",
+       "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-thumbnail-yes": "Το αρχείο φαίνεται ότι είναι μια εικόνα μειωμένου μεγέθους ''(μικρογραφία)''. [[$1|thumb]]\nΠαρακαλώ ελέγξτε το αρχείο <strong>[[:$1]]</strong>.\nΑν το ελεγμένο αρχείο είναι η ίδια εικόνα στο αρχικό μέγεθος δεν είναι απαραίτητο να επιφορτώσετε μια επιπλέον μικρογραφία.",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 σελίδα|$1 σελίδες}} προστέθηκαν:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 σελίδα|$1 σελίδες}} αφαιρέθηκαν:",
        "watchlistedit-clear-titles": "Τίτλοι:",
-       "watchlistedit-clear-submit": "Καταργήστε τη λίστα παρακολούθησης (αυτό είναι μόνιμο!)",
-       "watchlistedit-too-many": "Î¥Ï\80άÏ\81Ï\87οÏ\85ν Ï\80άÏ\81α Ï\80ολλέÏ\82 Ï\83ελίδεÏ\82 Î³Î¹Î± Î½Î± ÎµÎ¼Ï\86ανίÏ\83εÏ\84ε εδώ.",
+       "watchlistedit-clear-submit": "Καθαρίστε τη λίστα παρακολούθησης (αυτό είναι μόνιμο!)",
+       "watchlistedit-too-many": "Î¥Ï\80άÏ\81Ï\87οÏ\85ν Ï\85Ï\80εÏ\81βολικά Ï\80ολλέÏ\82 Ï\83ελίδεÏ\82 ÎºÎ±Î¹ Î´ÎµÎ½ Î¼Ï\80οÏ\81οÏ\8dν Î½Î± ÎµÎ¼Ï\86ανιÏ\83Ï\84οÏ\8dν εδώ.",
        "watchlisttools-view": "Προβολή σχετικών αλλαγών",
        "watchlisttools-edit": "Προβολή και επεξεργασία λίστας παρακολούθησης",
        "watchlisttools-raw": "Επεξεργασία πρωτογενούς λίστας παρακολούθησης",
index 1be50b4..e42d716 100644 (file)
        "talkpagelinktext": "Talk",
        "specialpage": "Special page",
        "personaltools": "Personal tools",
-       "postcomment": "New section",
        "addsection": "+",
        "articlepage": "View content page",
        "talk": "Discussion",
        "externaldberror": "There was either an authentication database error or you are not allowed to update your external account.",
        "login": "Log in",
        "nav-login-createaccount": "Log in / create account",
-       "loginprompt": "You must have cookies enabled to log in to {{SITENAME}}.",
+       "loginprompt": "",
        "userlogin": "Log in / create account",
        "userloginnocreate": "Log in",
        "logout": "Log out",
        "revdelete-text-text": "Deleted revisions will still appear in the page history, but parts of their content will be inaccessible to the public.",
        "revdelete-text-file": "Deleted file versions will still appear in the file history, but parts of their content will be inaccessible to the public.",
        "logdelete-text": "Deleted log events will still appear in the logs, but parts of their content will be inaccessible to the public.",
-       "revdelete-text-others": "Other administrators on {{SITENAME}} will still be able to access the hidden content and can undelete it again through this same interface, unless additional restrictions are set.",
+       "revdelete-text-others": "Other administrators will still be able to access the hidden content and to undelete it, unless additional restrictions are set.",
        "revdelete-confirm": "Please 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]].",
        "revdelete-suppress-text": "Suppression should <strong>only</strong> be used for the following cases:\n* potentially libelous information\n* inappropriate personal information\n*: <em>home addresses and telephone numbers, national identification numbers, etc.</em>",
        "revdelete-legend": "Set visibility restrictions",
        "right-deletedtext": "View deleted text and changes between deleted revisions",
        "right-browsearchive": "Search deleted pages",
        "right-undelete": "Undelete a page",
-       "right-suppressrevision": "Review and restore revisions hidden from administrators",
+       "right-suppressrevision": "View, hide and unhide specific revisions of pages from any user",
+       "right-viewsuppressed": "View revisions hidden from any user",
        "right-suppressionlog": "View private logs",
        "right-block": "Block other users from editing",
        "right-blockemail": "Block a user from sending email",
        "license-header": "Licensing",
        "nolicense": "None selected",
        "licenses": "-",
+       "licenses-edit": "Edit license options",
        "license-nopreview": "(Preview not available)",
        "upload_source_url": "(a valid, publicly accessible URL)",
        "upload_source_file": "(a file on your computer)",
+       "listfiles-delete": "delete",
        "listfiles-summary": "This special page shows all uploaded files.",
        "listfiles_search_for": "Search for media name:",
        "imgfile": "file",
        "wantedfiles": "Wanted files",
        "wantedfiles-summary": "",
        "wantedfiletext-cat": "The following files are used but do not exist. Files from foreign repositories may be listed despite existing. Any such false positives will be <del>struck out</del>. Additionally, pages that embed files that do not exist are listed in [[:$1]].",
+       "wantedfiletext-cat-noforeign": "The following files are used but do not exist. Additionally, pages that embed files that do not exist are listed in [[:$1]].",
        "wantedfiletext-nocat": "The following files are used but do not exist. Files from foreign repositories may be listed despite existing. Any such false positives will be <del>struck out</del>.",
+       "wantedfiletext-nocat-noforeign": "The following files are used but do not exist.",
        "wantedtemplates": "Wanted templates",
        "wantedtemplates-summary": "",
        "mostlinked": "Most linked-to pages",
        "timezone-utc": "UTC",
        "unknown_extension_tag": "Unknown extension tag \"$1\"",
        "duplicate-defaultsort": "<strong>Warning:</strong> Default sort key \"$2\" overrides earlier default sort key \"$1\".",
+       "duplicate-displaytitle": "<strong>Warning:</strong> Display title \"$2\" overrides earlier display title \"$1\".",
        "version": "Version",
        "version-summary": "",
        "version-extensions": "Installed extensions",
index c9d9b54..340ff8a 100644 (file)
        "talkpagelinktext": "Diskuto",
        "specialpage": "Speciala Paĝo",
        "personaltools": "Personaj iloj",
-       "postcomment": "Nova sekcio",
        "articlepage": "Rigardi artikolon",
        "talk": "Diskuto",
        "views": "Vidoj",
        "externaldberror": "Aŭ estis datenbaza eraro rilate al ekstera aŭtentikigado, aŭ vi ne rajtas ĝisdatigi vian eksteran konton.",
        "login": "Ensaluti",
        "nav-login-createaccount": "Ensaluti / Krei novan konton",
-       "loginprompt": "Via foliumilo nepre permesu kuketojn por ensaluti en la {{SITENAME}}.",
        "userlogin": "Ensaluti / Krei novan konton",
        "userloginnocreate": "Ensaluti",
        "logout": "Elsaluti",
        "edit-gone-missing": "Ne eblis ĝisdatigi la paĝon.\nVerŝajne ĝi estis forigita.",
        "edit-conflict": "Redakto-konflikto.",
        "edit-no-change": "Via redakto estis ignorita, ĉar neniu ŝanĝo estis farita al la teksto.",
+       "postedit-confirmation-created": "La paĝo estis kreita.",
+       "postedit-confirmation-restored": "La paĝo estis restarigita.",
        "postedit-confirmation-saved": "Via redakto estis konservita.",
        "edit-already-exists": "Ne eblis krei novan paĝon.\nĜi jam ekzistas.",
        "defaultmessagetext": "Defaŭlta teksto",
        "currentrev": "Aktuala versio",
        "currentrev-asof": "Nuna versio ekde $1",
        "revisionasof": "Kiel registrite je $1",
-       "revision-info": "Redakto de $1 de $2",
+       "revision-info": "Revizio de $1 fare de {{GENDER:$6|$2}}$7",
        "previousrevision": "← Antaŭa versio",
        "nextrevision": "Sekva versio →",
        "currentrevisionlink": "Rigardi nunan version",
        "editundo": "malfari",
        "diff-empty": "(Neniu diferenco)",
        "diff-multi-sameuser": "({{PLURAL:$1|Unu meza versio|$1 mezaj versioj}} de la sama uzanto ne montriĝas)",
-       "diff-multi-otherusers": "({{PLURAL:$1|Unu meza versio|$1 mezaj versioj}} de {{PLURAL:$2|alia uzanto|$2 uzoj}} ne montriĝas)",
+       "diff-multi-otherusers": "({{PLURAL:$1|Unu meza versio|$1 mezaj versioj}} de {{PLURAL:$2|alia uzanto|$2 uzantoj}} ne montriĝas)",
        "diff-multi-manyusers": "({{PLURAL:$1|Unu intermeza versio|$1 intermezaj versioj}} de pli ol {{PLURAL:$2|unu uzanto|$2 uzantoj}} ne estas {{PLURAL:$1|montrata|montrataj}}.)",
        "difference-missing-revision": "{{PLURAL:$2|Unu revizio|$2 revizioj}} de ĉi tiu malsameco ($1) ne {{PLURAL:$2|estis|estis}} trovebla.\n\nLa kutima kaŭzo estas sekvi malaktualan malsamo-ligilon al paĝo forviŝita.\nDetaloj troveblos en la [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de forviŝoj].",
        "searchresults": "Serĉrezultoj",
        "powersearch-togglelabel": "Elekti:",
        "powersearch-toggleall": "Ĉion",
        "powersearch-togglenone": "Nenion",
+       "powersearch-remember": "Memori elekton por estontaj serĉoj",
        "search-external": "Ekstera serĉo",
        "searchdisabled": "<p>Oni provizore malŝaltis serĉadon per la plenteksta\nindekso pro troŝarĝita servilo. Intertempe, vi povas serĉi per <i>guglo</i> aŭ per <i>jahu!</i>:</p>",
        "search-error": "Okazis eraro dum serĉado: $1",
        "right-upload": "Alŝuti dosierojn",
        "right-reupload": "Anstataŭigi ekzistantan dosieron",
        "right-reupload-own": "Anstataŭigi ekzistantan dosieron alŝutitan de la sama uzanto",
-       "right-reupload-shared": "Anstataŭigi dosierojn en la komuna bildprovizejo loke",
+       "right-reupload-shared": "Anstataŭigi dosierojn en la komuna bildprovizejo ĉi-loke",
        "right-upload_by_url": "Alŝuti dosieron de URL-adreso",
        "right-purge": "Refreŝigi la retejan kaŝmemoron por paĝo sen konfirma paĝo",
        "right-autoconfirmed": "Redakti duone protektitajn paĝojn",
        "right-deletedtext": "Rigardi forigitan tekston kaj ŝanĝojn inter forigitaj revizioj.",
        "right-browsearchive": "Serĉi forigitajn paĝojn",
        "right-undelete": "Restarigi paĝon",
-       "right-suppressrevision": "Kontroli kaj restarigi versiojn kaŝitajn de administrantoj",
+       "right-suppressrevision": "Montri, kaŝi kaj malkaŝi specifajn paĝajn versiojn de ajna uzanto",
        "right-suppressionlog": "Vidi privatajn protokolojn",
        "right-block": "Forbari aliajn uzantoj de redaktado",
        "right-blockemail": "Forbari uzanton de retpoŝta sendado",
        "largefileserver": "Ĉi tiu dosiero estas pli granda ol permesas la servilaj preferoj.",
        "emptyfile": "La dosiero kiun vi alŝutis ŝajnas malplena. Tio povas esti kaŭzita sde tajperaro en la titolo. Bonvolu kontroli ĉu vi vere volas alŝuti tiun dosieron.",
        "windows-nonascii-filename": "Ĉi tiu vikio ne subtenas dosiernomoj kun specialaj signoj.",
-       "fileexists": "Dosiero kun tia ĉi nomo jam ekzistas.\nBonvolu kontroli <strong>[[:$1]]</strong> krom se vi certas ke vi konscie volas ŝanĝi ĝuste tiun.\n[[$1|thumb]]",
+       "fileexists": "Dosiero kun tiu ĉi nomo jam ekzistas.\nBonvolu kontroli <strong>[[:$1]]</strong> krom se vi certas ke {{GENDER:|vi}} konscie volas ŝanĝi ĝuste tiun.\n[[$1|thumb]]",
        "filepageexists": "La priskriba paĝo por ĉi tiu dosiero jam estis kreita ĉe <strong>[[:$1]]</strong>, sed neniu dosiero kun ĉi tiu nomo nune ekzistas.\nLa resumo kiun vi entajpos ne aperos en la priskribo-paĝo.\nPor aperigi vian resumon, vi devos permane redakti ĝin.\n[[$1|thumb]]",
-       "fileexists-extension": "Dosiero kun simila nomo ekzistas: [[$2|thumb]]\n* Nomo de la alŝuta dosiero: <strong>[[:$1]]</strong>\n* Nomo de la ekzistanta dosiero: <strong>[[:$2]]</strong>\nBonvolu elekti malsaman nomon.",
+       "fileexists-extension": "Dosiero kun simila nomo ekzistas: [[$2|thumb]]\n* Nomo de la alŝutanta dosiero: <strong>[[:$1]]</strong>\n* Nomo de la ekzistanta dosiero: <strong>[[:$2]]</strong>\nBonvolu elekti malsaman nomon.",
        "fileexists-thumbnail-yes": "Ĉi tiu dosiero ŝajnas kiel bildo de malkreskigita grandeco ''(bildeto)''. [[$1|thumb]]\nBonvolu kontroli la dosieron <strong>[[:$1]]</strong>.\nSe la kontrolita dosiero estas la sama bildo kiel la originala grandeco, ĝi ne nepras alŝuti plian bideton.",
        "file-thumbnail-no": "La dosiernomo komencas kun <strong>$1</strong>.\nĜi ŝajnas kiel bildo de malgrandigita grandeco ''(thumbnail)''.\nSe vi havas ĉi tiun bildon en plena distingivo, alŝutu ĉi tiun, alikaze bonvolu ŝanĝi la dosieran nomon.",
        "fileexists-forbidden": "Dosiero kun ĉi tiu nomo jam ekzistas kaj ne povas anstataŭigi ĝin.\nSe vi ankoraŭ volas alŝuti vian dosieron, bonvolu reprovi kun nova nomo.\n[[File:$1|thumb|center|$1]]",
        "license-nopreview": "(Antaŭvido ne montrebla)",
        "upload_source_url": " (valida, publike atingebla URL-o)",
        "upload_source_file": " (dosiero en via komputilo)",
+       "listfiles-delete": "forigi",
        "listfiles-summary": "Ĉi tiu speciala paĝo montras ĉiujn alŝutitajn dosierojn.\nKiam oni filtras ĝin laŭ uzanto, nur la aktuala versio de la dosiero estos montrita.",
        "listfiles_search_for": "Serĉi dosieran nomon:",
        "imgfile": "dosiero",
        "filedelete-maintenance": "Forigado kaj restarigado de dosieroj provizore malŝaltis dum funkciteno.",
        "filedelete-maintenance-title": "Ne povas forigi dosieron",
        "mimesearch": "MIME-serĉilo",
-       "mimesearch-summary": "Ĉi tiu paĝo ebligas la filtradon de dosieroj por ties MIME-tipo. Enigu: enhavo-tipo/subtipo, ekz. <code>image/jpeg</code>.",
+       "mimesearch-summary": "Ĉi tiu paĝo ebligas la filtradon de dosieroj por ties MIME-tipo. \nEnigu: enhavo-tipo/subtipo, aŭ enhavo-tipo/* - ekz. <code>image/jpeg</code>.",
        "mimetype": "MIME-tipo:",
        "download": "elŝuti",
        "unwatchedpages": "Neatentataj paĝoj",
        "doubleredirects": "Duoblaj alidirektadoj",
        "doubleredirectstext": "Ĉi tiu paĝo montras paĝojn kiuj alidirektas al aliaj alidirektiloj.\nĈiu vico enhavas ligilojn ĉe la unua kaj dua alidirektadoj, kaj la unua linio de la dua alidirektado, kiu ĝenerale montras la \"veran\" celpaĝon, kiu celu la unuan alidirektadon.\n<del>Forstrekitaj</del> listeroj estis riparitaj.",
        "double-redirect-fixed-move": "[[$1]] estis alinomigita. Ĝi estis ĝisdatigita kaj nun ĝi alidirektas al [[$2]].",
-       "double-redirect-fixed-maintenance": "Riparas duoblan alidirektilon de [[$1]] al [[$2]].",
+       "double-redirect-fixed-maintenance": "Aŭtomate riparas duoblan alidirektilon de [[$1]] al [[$2]] dum prizorga tasko.",
        "double-redirect-fixer": "Alidirektila riparilo",
        "brokenredirects": "Rompitaj alidirektadoj",
        "brokenredirectstext": "La jenaj alidirektadoj ligas al neekzistantaj paĝoj:",
        "listgrouprights-namespaceprotection-header": "Nomspacaj restriktoj",
        "listgrouprights-namespaceprotection-namespace": "Nomspaco",
        "listgrouprights-namespaceprotection-restrictedto": "Rajtoj, kiuj permesas al uzanto redakti",
+       "trackingcategories": "Kategorioj por kontrolado",
+       "trackingcategories-summary": "Ĉi tiu paĝo listigas kategoriojn por kontrolado, aŭtomate farita de la Mediavikia programaro. Ties nomoj estas ŝanĝebla, ŝanĝante la paran sistemmesaĝon en la nomspaco {{ns:8}}.",
+       "trackingcategories-msg": "Kategorio pri kontrolado",
+       "trackingcategories-name": "Nomo de mesaĝo",
+       "trackingcategories-desc": "Kriterio por inkluzivi kategorion",
        "trackingcategories-nodesc": "Neniu priskribo estas disponebla.",
        "trackingcategories-disabled": "Kategorio estas malaktivigita",
        "mailnologin": "Neniu alsendota adreso",
        "addedwatchtext": "La paĝo \"[[:$1]]\" aldoniĝis al via [[Special:Watchlist|atentaro]]. Estontaj ŝanĝoj de tiu paĝo kaj de ĝia rilata diskutpaĝo aperos tie.",
        "removewatch": "Forigi el atentaro",
        "removedwatchtext": "La paĝo \"[[:$1]]\" estas forigita el via [[Special:Watchlist|atentaro]].",
+       "removedwatchtext-short": "La paĝo \"$1\" estis forigita el via atento-listo.",
        "watch": "Atenti",
        "watchthispage": "Priatenti paĝon",
        "unwatch": "Malatenti",
        "newimages-summary": "Ĉi tiu speciala paĝo montras la lastajn alŝutitajn dosierojn.",
        "newimages-legend": "Dosiernomo",
        "newimages-label": "Dosiernomo (aŭ parto de ĝi):",
+       "newimages-showbots": "Montri alŝutojn per robotoj",
        "noimages": "Nenio videbla.",
        "ilsubmit": "Serĉi",
        "bydate": "laŭ dato",
        "duplicate-defaultsort": "'''Averto:''' Defaŭlta ordiga ŝlosilo \"$2\" anstataŭigas pli fruan defaŭltan ordigan ŝlosilon \"$1\".",
        "version": "Versio",
        "version-extensions": "Instalitaj kromprogramoj",
-       "version-skins": "Etosoj",
+       "version-skins": "Instalitaj etosoj",
        "version-specialpages": "Specialaj paĝoj",
        "version-parserhooks": "Sintaksaj hokoj",
        "version-variables": "Variabloj",
        "version-hook-name": "Nomo de hoko",
        "version-hook-subscribedby": "Abonita de",
        "version-version": "($1)",
+       "version-no-ext-name": "[sen nomo]",
        "version-license": "Permesilo de MediaWiki",
        "version-ext-license": "Permesilo",
        "version-ext-colheader-name": "Etendilo",
+       "version-skin-colheader-name": "Etoso",
        "version-ext-colheader-version": "Versio",
        "version-ext-colheader-license": "Permesilo",
        "version-ext-colheader-description": "Priskribo",
        "expand_templates_remove_nowiki": "Nuligi <nowiki> etikedojn en rezulto",
        "expand_templates_generate_xml": "Montri XML-sintaksarbon",
        "expand_templates_generate_rawhtml": "Montri krudan HTML-n",
-       "expand_templates_preview": "Antaŭrigardo"
+       "expand_templates_preview": "Antaŭrigardo",
+       "pagelang-name": "Paĝo",
+       "pagelang-language": "Lingvo",
+       "pagelang-use-default": "Uzi defaŭltan lingvon",
+       "pagelang-select-lang": "Elekti la lingvon",
+       "right-pagelang": "Ŝanĝi paĝan lingvon",
+       "action-pagelang": "ŝanĝi la lingvon de la paĝo",
+       "log-name-pagelang": "Ŝanĝi la lingvan protokolon",
+       "log-description-pagelang": "Jen protokolo pri ŝanĝoj de paĝaj lingvoj.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|ŝanĝis}} la paĝan lingvon por $3 de $4 al $5."
 }
index 295a54f..deec915 100644 (file)
                        "Mcervera",
                        "Wifidel",
                        "Macofe",
-                       "Koavf"
+                       "Koavf",
+                       "Themasterriot"
                ]
        },
        "tog-underline": "Subrayar los enlaces:",
        "tog-prefershttps": "Utilizar una conexión segura siempre que haya iniciado una sesión",
        "underline-always": "Siempre",
        "underline-never": "Nunca",
-       "underline-default": "Aspecto (skin) o valor predeterminado del navegador",
+       "underline-default": "Tema o valor predeterminado del navegador",
        "editfont-style": "Estilo de tipografía del área de edición:",
        "editfont-default": "Predeterminado del navegador",
        "editfont-monospace": "Tipo de letra monoespaciado",
        "talkpagelinktext": "Discusión",
        "specialpage": "Página especial",
        "personaltools": "Herramientas personales",
-       "postcomment": "Sección nueva",
        "articlepage": "Ver artículo",
        "talk": "Discusión",
        "views": "Vistas",
        "externaldberror": "Hubo un error de autenticación de la base de datos o bien no tienes autorización para actualizar tu cuenta externa.",
        "login": "Iniciar sesión",
        "nav-login-createaccount": "Acceder/crear cuenta",
-       "loginprompt": "Hay que activar las ''cookies'' en el navegador para iniciar sesión en {{SITENAME}}.",
        "userlogin": "Acceder/crear cuenta",
        "userloginnocreate": "Acceder",
        "logout": "Salir",
        "revdelete-text-text": "Las revisiones eliminadas aún aparecerán en el historial de la página, pero parte de su contenido será inaccesible para el público.",
        "revdelete-text-file": "Las versiones de los archivos eliminados aún aparecerán en el historial del archivo, pero partes de su contenido serán inaccesibles para el público.",
        "logdelete-text": "Las revisiones eliminadas aún aparecerán en el historial de la página, pero parte de su contenido será inaccesible para el público.",
-       "revdelete-text-others": "Otros administradores en {{SITENAME}} aun serán capaces de acceder a los contenidos ocultos y pueden restaurarlos a través de esta interfaz, a menos que se establezcan restricciones adicionales.",
+       "revdelete-text-others": "Otros administradores aun serán capaces de acceder a los contenidos ocultos y restaurarlos, a menos que se establezcan restricciones adicionales.",
        "revdelete-confirm": "Por favor confirma que deseas realizar la operación, que entiendes las consecuencias y que estás ejecutando dicha acción acorde con [[{{MediaWiki:Policy-url}}|las políticas]].",
        "revdelete-suppress-text": "La herramienta de supresión '''solo''' debería usarse en los siguientes casos:\n* información potencialmente injuriosa o calumniante.\n* información personal inapropiada, tal como:\n*: ''nombres, domicilios, números de teléfono, números de la seguridad social e información análoga.''",
        "revdelete-legend": "Establecer restricciones de revisión:",
        "gender-unknown": "Prefiero no especificarlo",
        "gender-male": "Masculino",
        "gender-female": "Femenino",
-       "prefs-help-gender": "Opcional: empleado para que sea usado correctamente el género por parte del software. Esta información será pública.",
+       "prefs-help-gender": "Opcional: el software utiliza esta preferencia para dirigirse a ti con el género gramatical apropiado. Esta información es pública.",
        "email": "Correo electrónico",
        "prefs-help-realname": "El nombre real es opcional. Si decides proporcionarlo, se usará para dar atribución a tu trabajo.",
        "prefs-help-email": "La dirección de correo electrónico es opcional, pero es necesaria para el restablecimiento de tu contraseña, en caso de que la olvides.",
        "right-deletedtext": "Ver texto borrado y cambios entre revisiones borradas",
        "right-browsearchive": "Buscar páginas borradas",
        "right-undelete": "Restaurar una página",
-       "right-suppressrevision": "Revisar y restaurar revisiones escondidas por administradores",
+       "right-suppressrevision": "Ver, ocultar y mostrar revisiones específicas de páginas de cualquier usuario",
        "right-suppressionlog": "Ver registros privados",
        "right-block": "Bloquear a otros usuarios para que no editen",
        "right-blockemail": "Bloquear a un usuario para que no pueda mandar correos electrónicos",
        "right-editprotected": "Editar páginas protegidas como «{{int:protect-level-sysop}}»",
        "right-editsemiprotected": "Editar páginas protegidas como «{{int:protect-level-autoconfirmed}}»",
        "right-editinterface": "Editar la interfaz de usuario",
-       "right-editusercssjs": "Editar las páginas de CSS y JS de otros usuarios",
+       "right-editusercssjs": "Editar las páginas de CSS y JavaScript de otros usuarios",
        "right-editusercss": "Editar las páginas de CSS de otros usuarios",
-       "right-edituserjs": "Editar las páginas de JS de otros usuarios",
+       "right-edituserjs": "Editar las páginas de JavaScript de otros usuarios",
        "right-editmyusercss": "Editar tus archivos de usuario CSS",
        "right-editmyuserjs": "Editar tus propios archivos JavaScript de usuario",
        "right-viewmywatchlist": "Ver tu lista de seguimiento",
        "recentchanges-summary": "Sigue los cambios más recientes de la wiki en esta página.",
        "recentchanges-noresult": "No hubo cambios durante el período seleccionado que respondan a esos criterios.",
        "recentchanges-feed-description": "Realiza un seguimiento de los cambios más recientes en el wiki en este canal.",
-       "recentchanges-label-newpage": "Esta edición inició una página",
+       "recentchanges-label-newpage": "Esta edición creó una página",
        "recentchanges-label-minor": "Esta es una edición menor",
        "recentchanges-label-bot": "Esta edición fue realizada por un robot",
        "recentchanges-label-unpatrolled": "Esta edición todavía no se ha patrullado",
        "license": "Licencia:",
        "license-header": "Licencia",
        "nolicense": "Ninguna seleccionada",
+       "licenses-edit": "Editar las opciones de licencia",
        "license-nopreview": "(Previsualización no disponible)",
        "upload_source_url": " (una URL válida y accesible públicamente)",
-       "upload_source_file": " (un archivo en tu disco)",
+       "upload_source_file": "(un archivo en tu computadora)",
+       "listfiles-delete": "borrar",
        "listfiles-summary": "Esta página especial muestra todos los archivos subidos.\nCuando el usuario la filtra, solo se muestran los archivos cargados por el usuario en su versión más reciente.",
        "listfiles_search_for": "Buscar por nombre de imagen:",
        "imgfile": "archivo",
        "wantedpages-badtitle": "Título inválido en conjunto de resultados: $1",
        "wantedfiles": "Ficheros requeridos",
        "wantedfiletext-cat": "Los siguientes archivos están en uso, pero no existen. Es posible que algunos de ellos estén almacenados en repositorios externos y se hayan incluido aquí por error; dichas entradas aparecen <del>tachadas</del>. De igual manera, las páginas que incluyen archivos inexistentes se enumeran en [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Los siguientes archivos están en uso, pero no existen. Además, las páginas con archivos que no existen están listadas en [[:$1]].",
        "wantedfiletext-nocat": "Los siguientes archivos están en uso, pero no existen. Es posible que algunos de ellos estén almacenados en repositorios externos y se hayan incluido aquí por error; dichas entradas aparecen <del>tachadas</del>.",
+       "wantedfiletext-nocat-noforeign": "Los siguientes archivos están en uso, pero no existen.",
        "wantedtemplates": "Plantillas requeridas",
        "mostlinked": "Artículos más enlazados",
        "mostlinkedcategories": "Categorías más enlazadas",
        "patrol-log-header": "Este es un registro de revisiones patrulladas.",
        "log-show-hide-patrol": "$1 registro de patrullaje",
        "deletedrevision": "Borrada revisión antigua $1",
-       "filedeleteerror-short": "Se produjo un error al borrar el archivo: $1",
+       "filedeleteerror-short": "Error al borrar el archivo: $1",
        "filedeleteerror-long": "Se han producido errores mientras se borraba el archivo:\n\n$1",
        "filedelete-missing": "No se pudo borrar el archivo \"$1\" porque no existe.",
        "filedelete-old-unregistered": "La revisión de archivo \"$1\" no está en la base de datos.",
        "watchlistedit-clear-removed": "{{PLURAL:$1|un título fue removido|Los títulos $1 fueron removidos}}:",
        "watchlistedit-too-many": "Hay demasiadas páginas para mostrar aquí.",
        "watchlisttools-clear": "Limpiar la lista de seguimiento",
-       "watchlisttools-view": "Ver cambios",
+       "watchlisttools-view": "Ver cambios relevantes",
        "watchlisttools-edit": "Ver y editar tu lista de seguimiento",
        "watchlisttools-raw": "Editar lista de seguimiento en crudo",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discusión]])",
        "unknown_extension_tag": "Etiqueta desconocida «$1»",
        "duplicate-defaultsort": "'''Atención:''' La clave de ordenamiento predeterminada «$2» anula la clave de ordenamiento anterior «$1».",
+       "duplicate-displaytitle": "<strong>Advertencia:</strong> El título visualizado \"$2\" sobreescribe al anterior \"$1\".",
        "version": "Versión",
        "version-extensions": "Extensiones instaladas",
-       "version-skins": "Apariencias",
+       "version-skins": "Temas instalados",
        "version-specialpages": "Páginas especiales",
        "version-parserhooks": "Extensiones del analizador sintáctico",
        "version-variables": "Variables",
        "version-license": "Licencia de MediaWiki",
        "version-ext-license": "Licencia",
        "version-ext-colheader-name": "Extensión",
+       "version-skin-colheader-name": "Tema",
        "version-ext-colheader-version": "Versión",
        "version-ext-colheader-license": "Licencia",
        "version-ext-colheader-description": "Descripción",
        "api-error-filetype-banned": "Este tipo de archivo está prohibido.",
        "api-error-filetype-banned-type": "$1 {{PLURAL:$4|no es un tipo de archivo permitido|no son tipos de archivos permitidos}}. {{PLURAL:$3|El tipo de archivo permitido es|Los tipos de archivos permitidos son}} $2.",
        "api-error-filetype-missing": "El archivo no tiene extensión de archivo.",
-       "api-error-hookaborted": "La modificación que intentaste hacer fue cancelada por un gancho de extensión.",
+       "api-error-hookaborted": "La modificación que intentaste hacer fue cancelada por una extensión.",
        "api-error-http": "Error interno: No se puede conectar al servidor.",
        "api-error-illegal-filename": "El nombre de archivo no está permitido.",
        "api-error-internal-error": "Error interno: Algo salió mal al procesar tu subida en el wiki.",
        "expand_templates_remove_nowiki": "Suprimir <nowiki> etiquetas en resultado",
        "expand_templates_generate_xml": "Mostrar el árbol XML.",
        "expand_templates_generate_rawhtml": "Mostrar HTML en crudo",
-       "expand_templates_preview": "Previsualización"
+       "expand_templates_preview": "Previsualización",
+       "pagelanguage": "Selector de idioma de página",
+       "pagelang-name": "Página",
+       "pagelang-language": "Idioma",
+       "pagelang-use-default": "Utilizar el idioma predeterminado",
+       "pagelang-select-lang": "Seleccionar idioma",
+       "right-pagelang": "Cambiar el idioma de la página",
+       "action-pagelang": "cambiar el idioma de la página",
+       "log-name-pagelang": "Registro de cambios en idiomas",
+       "log-description-pagelang": "Este es un registro de los cambios en los idiomas de las páginas.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|cambió}} el idioma de la página «$3» del $4 al $5."
 }
index 05c0e32..794dbe7 100644 (file)
        "category-file-count-limited": "{{PLURAL:$1|Järgmine fail|Järgmised $1 faili}} on selles kategoorias.",
        "listingcontinuesabbrev": "jätk",
        "index-category": "Indeksiga leheküljed",
-       "noindex-category": "Indeksita leheküljed",
+       "noindex-category": "Indekseerimata leheküljed",
        "broken-file-category": "Katkiste pildilinkidega leheküljed",
        "about": "Tiitelandmed",
        "article": "artikkel",
        "talkpagelinktext": "arutelu",
        "specialpage": "Erilehekülg",
        "personaltools": "Personaalsed tööriistad",
-       "postcomment": "Uus alaosa",
        "articlepage": "Artiklilehekülg",
        "talk": "Arutelu",
        "views": "vaatamisi",
        "externaldberror": "Esines autentimistõrge või sul pole õigust konto andmeid muuta.",
        "login": "Logi sisse",
        "nav-login-createaccount": "Logi sisse või registreeru kasutajaks",
-       "loginprompt": "Sisselogimiseks peavad küpsised lubatud olema.",
        "userlogin": "Sisselogimine või kasutajakonto loomine",
        "userloginnocreate": "Sisselogimine",
        "logout": "Logi välja",
        "revdelete-text-text": "Kustutatud redaktsioonid jäävad lehekülje ajalukku alles, aga osa nende sisust pole kõigile juurdepääsetav.",
        "revdelete-text-file": "Kustutatud failiversioonid jäävad faili ajalukku alles, aga osa nende sisust pole kõigile juurdepääsetav.",
        "logdelete-text": "Kustutatud logisündmused jäävad logisse alles, aga osa nende sisust pole kõigile juurdepääsetav.",
-       "revdelete-text-others": "Teised {{GRAMMAR:genitive|{{SITENAME}}}} administraatorid pääsevad ikkagi peidetud sisu juurde ja saavad sama liidese kaudu selle taastada, kui seatud pole lisapiiranguid.",
+       "revdelete-text-others": "Teised administraatorid pääsevad ikkagi peidetud sisu juurde ja saavad selle taastada, kui seatud pole lisapiiranguid.",
        "revdelete-confirm": "Kinnita, et soovid tõesti seda teha ning et saad aru tagajärgedest ja tegevus on kooskõlas [[{{MediaWiki:Policy-url}}|siinsete kokkulepetega]].",
        "revdelete-suppress-text": "Andmed tuleks varjata '''ainult''' järgmistel juhtudel:\n* võimalik laim\n* sobimatu isiklik teave\n*: ''kodune aadress ja telefoninumber, isikukood jne''",
        "revdelete-legend": "Nähtavuse piirangute seadmine",
        "prefs-watchlist-edits-max": "Ülemmäär: 1000",
        "prefs-watchlist-token": "Jälgimisloendi luba:",
        "prefs-misc": "Muu",
-       "prefs-resetpass": "Muuda parooli",
+       "prefs-resetpass": "Muuda parool",
        "prefs-changeemail": "Muuda e-posti aadressi",
        "prefs-setemail": "Määra e-posti aadress",
        "prefs-email": "E-posti sätted",
        "right-deletedtext": "Vaadata kustutatud teksti ja võrrelda kustutatud redaktsioone",
        "right-browsearchive": "Otsida kustutatud lehekülgi",
        "right-undelete": "Taastada lehekülg",
-       "right-suppressrevision": "Üle vaadata ja taastada administraatorite eest peidetud redaktsioone",
+       "right-suppressrevision": "Vaadata, peita ja taastada kõigi kasutajate eest varjatud kindlaid redaktsioone",
+       "right-viewsuppressed": "Vaadata kõigi kasutajate eest varjatud redaktsioone",
        "right-suppressionlog": "Vaadata eralogisid",
        "right-block": "Keelata lehekülgede muutmist mõnel kasutajal",
        "right-blockemail": "Keelata kasutajal e-kirjade saatmine",
        "action-deletedhistory": "selle lehekülje kustutatud ajalugu vaadata",
        "action-browsearchive": "kustutatud lehekülgi otsida",
        "action-undelete": "lehekülgi taastada",
-       "action-suppressrevision": "seda peidetud redaktsiooni vaadata ja taastada",
+       "action-suppressrevision": "seda peidetud redaktsiooni vaadata ega taastada",
        "action-suppressionlog": "seda eralogi vaadata",
        "action-block": "selle kasutaja redigeerimisõigust blokeerida",
        "action-protect": "selle lehekülje kaitsetasemeid muuta",
        "license": "Litsents:",
        "license-header": "Litsents",
        "nolicense": "pole valitud",
+       "licenses-edit": "Redigeeri litsentsivalikut",
        "license-nopreview": "(Eelvaade ei ole saadaval)",
        "upload_source_url": "(avalikult ligipääsetav URL)",
        "upload_source_file": "(fail sinu arvutis)",
+       "listfiles-delete": "kustuta",
        "listfiles-summary": "Sellel erileheküljel näidatakse kõiki üles laaditud faile.",
        "listfiles_search_for": "Nimeotsing:",
        "imgfile": "fail",
        "wantedpages-badtitle": "Tulemuste seas on vigane pealkiri: $1",
        "wantedfiles": "Kõige oodatumad failid",
        "wantedfiletext-cat": "Järgmised failid puuduvad, aga on lehekülgedel kasutuses. Siin võivad olla loetletud ka välistes hoidlates asuvad failid, hoolimata sellest, et nad tegelikult olemas on. Loendi sellised valeliikmed on <del>läbi kriipsutatud</del>. Lisaks on puuduvaid faile sisaldavad leheküljed loetletud asukohas [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Järgmised failid puuduvad, aga on kasutuses. Peale selle, leheküljel [[:$1]] on loetletud leheküljed, kus kasutatakse puuduvaid faile.",
        "wantedfiletext-nocat": "Järgmised failid puuduvad, aga on lehekülgedel kasutuses. Siin võivad olla loetletud ka välistes hoidlates asuvad failid, hoolimata sellest, et nad tegelikult olemas on. Loendi sellised valeliikmed on <del>läbi kriipsutatud</del>.",
+       "wantedfiletext-nocat-noforeign": "Järgmised failid puuduvad, aga on kasutuses.",
        "wantedtemplates": "Kõige oodatumad mallid",
        "mostlinked": "Kõige viidatumad leheküljed",
        "mostlinkedcategories": "Kõige viidatumad kategooriad",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|arutelu]])",
        "unknown_extension_tag": "Tundmatu lisa silt \"$1\".",
        "duplicate-defaultsort": "'''Hoiatus:''' Järjestamisvõti \"$2\" tühistab eespool oleva järjestamisvõtme \"$1\".",
+       "duplicate-displaytitle": "<strong>Hoiatus:</strong> Kuvatava pealkirjaga \"$2\" kirjutatakse üle varasem kuvatav pealkiri \"$1\".",
        "version": "Versioon",
        "version-extensions": "Paigaldatud lisad",
        "version-skins": "Paigaldatud kujundused",
index 4f10d30..ab0bb1f 100644 (file)
        "talkpagelinktext": "Eztabaida",
        "specialpage": "Aparteko orrialdea",
        "personaltools": "Tresna pertsonalak",
-       "postcomment": "Atal berria",
        "articlepage": "Artikulua ikusi",
        "talk": "Eztabaida",
        "views": "Ikustaldiak",
        "externaldberror": "Kanpoko datu-base autentifikazio errorea gertatu da edo ez duzu zure kanpo kontua eguneratzeko baimenik.",
        "login": "Saioa hasi",
        "nav-login-createaccount": "Saioa hasi / kontua sortu",
-       "loginprompt": "Cookieak gaituta izatea beharrezkoa da {{SITENAME}}(e)n saioa hasteko.",
        "userlogin": "Saioa hasi / kontua sortu",
        "userloginnocreate": "Saioa hasi",
        "logout": "Saioa itxi",
        "limitreport-expansiondepth": "Gehienezko espantsio sakonera",
        "limitreport-expensivefunctioncount": "Parser funtzio kontaketa garestia",
        "expandtemplates": "Txantiloi ordezkatzailea",
-       "expand_templates_intro": "Aparteko orrialde honek modu errekurtsiboan txantiloiak ordezkatu egiten ditu.\nFuntzioak ere ordezkatu egiten ditu, hala nola\n<code><nowiki>{{</nowiki>#language:…}}</code>, eta\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code> bezalako aldagaiak ere.\nKortxete bikoitzarekin hobeto egiten da lan.",
+       "expand_templates_intro": "Orri berezi honek testua hartu eta txantiloi guztiak modu errekurtsiboan zabaltzen ditu.\nOnartutako funtzio sintaktikoak ere ordezkatzen ditu, hala nola\n<code><nowiki>{{</nowiki>#language:…}}</code>; eta aldagaiak ere, hala nola\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nIzan ere, kortxete bikoitzen arteko ia edozer zabaltzen du.",
        "expand_templates_title": "Izenburua ({{FULLPAGENAME}} ordezkatzeko, eta abar):",
        "expand_templates_input": "Sarrerako testua:",
        "expand_templates_output": "Emaitza",
index 2ae3059..cc18333 100644 (file)
@@ -34,7 +34,9 @@
                        "درفش کاویانی",
                        "محک",
                        "아라",
-                       "Mostafadaneshvar"
+                       "Mostafadaneshvar",
+                       "Pouyana",
+                       "Oldstoneage"
                ]
        },
        "tog-underline": "خط کشیدن زیر پیوندها:",
        "talkpagelinktext": "بحث",
        "specialpage": "صفحهٔ ویژه",
        "personaltools": "ابزارهای شخصی",
-       "postcomment": "بخش جدید",
        "articlepage": "نمایش مقاله",
        "talk": "بحث",
        "views": "بازدیدها",
        "externaldberror": "خطایی در ارتباط با پایگاه داده رخ داده‌است یا اینکه شما اجازهٔ به‌روزرسانی حساب خارجی خود را ندارید.",
        "login": "ورود به سامانه",
        "nav-login-createaccount": "ورود به سامانه / ایجاد حساب کاربری",
-       "loginprompt": "برای ورود به {{SITENAME}} باید کوکی‌ها را فعال کنید.",
        "userlogin": "ورود به سامانه / ایجاد حساب کاربری",
        "userloginnocreate": "ورود به سامانه",
        "logout": "خروج از سامانه",
        "shown-title": "نمایش $1 {{PLURAL:$1|نتیجه|نتیجه}} در هر صفحه",
        "viewprevnext": "نمایش ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "'''صفحه‌ای با عنوان «[[:$1]]» در این ویکی وجود دارد.'''",
-       "searchmenu-new": "<strong>اÛ\8cجاد ØµÙ\81Ø­Ù\87Ù\94 Â«[[:$1]]» Ø¯Ø± Ø§Û\8cÙ\86 Ù\88Û\8cÚ©Û\8c!</strong> {{PLURAL:$2|0=|Ù\87Ù\85Ú\86Ù\86Û\8cÙ\86 Ù\85شاÙ\87دÙ\87Ù\94 ØµÙ\81Ø­Ù\87Ù\94 Ù¾Û\8cدا Ø´Ø¯Ù\87 Ø¨Ø§ Ø¬Ø³ØªØ¬Ù\88Û\8c Ø´Ù\85ا.|Ù\87Ù\85Ú\86Ù\86Û\8cÙ\86 Ù\85شاÙ\87دÙ\87Ù\94 Ø¬Ø³ØªØ¬Ù\88Û\8c Ù\86تاÛ\8cج Ù¾Û\8cدا Ø´Ø¯Ù\87.}}",
+       "searchmenu-new": "<strong>صÙ\81Ø­Ù\87Ù\94 Â«[[:$1]]» Ø±Ø§ Ø¯Ø± Ø§Û\8cÙ\86 Ù\88Û\8cÚ©Û\8c Ø¨Ø³Ø§Ø²Û\8cد!</strong> {{PLURAL:$2|0=Ù\87Ù\85Ú\86Ù\86Û\8cÙ\86 ØµÙ\81Ø­Ù\87Ù\94 Û\8cاÙ\81تâ\80\8cشدÙ\87 Ø¨Ø§ Ø¬Ø³ØªØ¬Ù\88Û\8cتاÙ\86 Ø±Ø§ Ø¨Ø¨Û\8cÙ\86Û\8cد.|Ù\87Ù\85Ú\86Ù\86Û\8cÙ\86 Ù\86تاÛ\8cج Ø¬Ø³ØªØ¬Ù\88Û\8c Û\8cاÙ\81تâ\80\8cشدÙ\87 Ø±Ø§ Ø¨Ø¨Û\8cÙ\86Û\8cد.}}",
        "searchprofile-articles": "صفحه‌های محتوایی",
        "searchprofile-images": "چندرسانه‌ای",
        "searchprofile-everything": "همه‌چیز",
        "license": "اجازه‌نامه:",
        "license-header": "اجازه‌نامه",
        "nolicense": "هیچ کدام انتخاب نشده‌است",
+       "licenses-edit": "گزینه‌های مجوز ویرایش",
        "license-nopreview": "(پیش‌نمایش وجود ندارد)",
        "upload_source_url": "(یک نشانی اینترنتی معتبر و قابل دسترسی برای عموم)",
        "upload_source_file": "(پرونده‌ای در رایانهٔ شما)",
+       "listfiles-delete": "حذف",
        "listfiles-summary": "این صفحهٔ ویژه تمام پرونده‌های بارگذاری‌شده را نمایش می‌دهد.",
        "listfiles_search_for": "جستجو به دنبال نام پرونده چندرسانه‌ای:",
        "imgfile": "پرونده",
        "wantedpages-badtitle": "عنوان نامجاز در مجموعهٔ نتایج: $1",
        "wantedfiles": "پرونده‌های مورد نیاز",
        "wantedfiletext-cat": "پرونده‌های زیر استفاده می‌شوند اما موجود نیستند. همچنین ممکن است پرونده‌های مخازن خارجی با وجود موجود بودن در اینجا فهرست شوند. هرگونه رتبه مثبت کاذب <del>خط خواهد خورد.</del> علاوه بر این، صفحاتی که پرونده‌هایی ناموجود را در خود جای داده‌اند در [[:$1]] فهرست شده‌اند.",
+       "wantedfiletext-cat-noforeign": "پرونده‌های زیر استفاده می‌شود اما وجود ندارد. علاوه بر این، صفحاتی که پرونده‌ها در آنها وجود دارند فهرست شده‌اند در [[:$1]].",
        "wantedfiletext-nocat": "پرونده‌های زیر استفاده می‌شوند اما موجود نیستند. همچنین ممکن است پرونده‌های مخازن خارجی با وجود موجود بودن در اینجا فهرست شوند. هرگونه رتبهٔ مثبت کاذب <del>خط خواهد خورد.</del>",
+       "wantedfiletext-nocat-noforeign": "پرونده‌های زیر استفاده می‌شوند اما وجود ندارد.",
        "wantedtemplates": "الگوهای مورد نیاز",
        "mostlinked": "صفحه‌هایی که بیشتر از همه به آن‌ها پیوند داده شده‌است",
        "mostlinkedcategories": "رده‌هایی که بیشتر از همه به آن‌ها پیوند داده شده‌است",
        "undeleteviewlink": "نمایش",
        "undeleteinvert": "وارونه کردن انتخاب",
        "undeletecomment": "دلیل:",
-       "undeletedrevisions": "$1 نسخه احیا {{PLURAL:$1|شد|شدند}}",
+       "undeletedrevisions": "$1 نسخه احیا {{PLURAL:$1|شد}}",
        "undeletedrevisions-files": "$1 نسخه و $2 پرونده احیا {{PLURAL:$1|شد|شدند}}.",
        "undeletedfiles": "$1 پرونده احیا {{PLURAL:$1|شد|شدند}}.",
        "cannotundelete": "احیا ناموفق بود:\n$1",
        "sp-contributions-search": "جستجوی مشارکت‌ها",
        "sp-contributions-username": "نشانی آی‌پی یا نام کاربری:",
        "sp-contributions-toponly": "فقط ویرایش‌هایی که آخرین نسخه‌اند نمایش داده شود",
-       "sp-contributions-newonly": "Ù\81Ù\82Ø· Ù\86Ù\85اÛ\8cØ´ Ù\88Û\8cراÛ\8cØ´â\80\8cÙ\87اÛ\8cÛ\8c Ú©Ù\87 ØªÙ\88Ù\84Û\8cدâ\80\8cÙ\87اÛ\8c صفحه هستند",
+       "sp-contributions-newonly": "Ù\81Ù\82Ø· Ù\86Ù\85اÛ\8cØ´ Ù\88Û\8cراÛ\8cØ´â\80\8cÙ\87اÛ\8cÛ\8c Ú©Ù\87 Ø§Û\8cجاد صفحه هستند",
        "sp-contributions-submit": "جستجو",
        "whatlinkshere": "پیوندها به این صفحه",
        "whatlinkshere-title": "صفحه‌هایی که به «$1» پیوند دارند",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|بحث]])",
        "unknown_extension_tag": "برچسب ناشناختهٔ افزونه «$1»",
        "duplicate-defaultsort": "هشدار: ترتیب پیش‌فرض «$2» ترتیب پیش‌فرض قبلی «$1» را باطل می‌کند.",
+       "duplicate-displaytitle": "<strong>هشدار:</strong> نمایش عنوان \" $2 \"باعث ابطال پیش نمایش عنوان\" $1 \" می‌شود.",
        "version": "نسخه",
        "version-extensions": "افزونه‌های نصب‌شده",
-       "version-skins": "پوسته‌ها",
+       "version-skins": "پوسته‌های نصب شده",
        "version-specialpages": "صفحه‌های ویژه",
        "version-parserhooks": "قلاب‌های تجزیه‌گر",
        "version-variables": "متغیرها",
        "version-hook-name": "نام قلاب",
        "version-hook-subscribedby": "وارد شده توسط",
        "version-version": "(نسخه  $1)",
+       "version-no-ext-name": "[بدون نام]",
        "version-svn-revision": "(&رلم;r$2)",
        "version-license": "اجازه‌نامهٔ مدیاویکی",
        "version-ext-license": "مجوزها",
        "version-ext-colheader-name": "گستره‌ها",
+       "version-skin-colheader-name": "پوسته",
        "version-ext-colheader-version": "نسخه",
        "version-ext-colheader-license": "مجوز",
        "version-ext-colheader-description": "توصیفات",
        "expand_templates_remove_nowiki": "خنثی کردن تگ‌های <nowiki> در نتیجه",
        "expand_templates_generate_xml": "نمایش درخت تجزیهٔ XML",
        "expand_templates_generate_rawhtml": "نمایش اچ‌تی‌ام‌ال خام",
-       "expand_templates_preview": "پیش‌نمایش"
+       "expand_templates_preview": "پیش‌نمایش",
+       "pagelanguage": "صفحه انتخاب زبان",
+       "pagelang-name": "صفحه",
+       "pagelang-language": "زبان",
+       "pagelang-use-default": "استفاده از زبان پیش‌فرض",
+       "pagelang-select-lang": "انتخاب زبان",
+       "right-pagelang": "تغییر صفحهٔ زبان",
+       "action-pagelang": "تغییر زبان صفحه",
+       "log-name-pagelang": "تغییر سیاههٔ زبان",
+       "log-description-pagelang": "این سیاههٔ تغییرات صفحهٔ زبان‌ها است.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2| تغییریافت}} زبان صفحه برای  $3  از  $4  به  $5 ."
 }
index 79c467f..15b04aa 100644 (file)
@@ -39,7 +39,8 @@
                        "ZeiP",
                        "לערי ריינהארט",
                        "아라",
-                       "Syreeni"
+                       "Syreeni",
+                       "MrTapsa"
                ]
        },
        "tog-underline": "Linkkien alleviivaus:",
        "talkpagelinktext": "keskustelu",
        "specialpage": "Toimintosivu",
        "personaltools": "Henkilökohtaiset työkalut",
-       "postcomment": "Uusi osio",
        "articlepage": "Näytä varsinainen sivu",
        "talk": "Keskustelu",
        "views": "Näkymät",
        "externaldberror": "Tapahtui virhe ulkoisen autentikointitietokannan käytössä tai sinulla ei ole lupaa päivittää tunnustasi.",
        "login": "Kirjaudu sisään",
        "nav-login-createaccount": "Kirjaudu sisään tai luo tunnus",
-       "loginprompt": "Sinun täytyy sallia evästeet, jotta voit kirjautua sivustolle {{SITENAME}}.",
        "userlogin": "Kirjaudu sisään tai luo tunnus",
        "userloginnocreate": "Kirjaudu sisään",
        "logout": "Kirjaudu ulos",
        "revdelete-text-text": "Poistetut versiot näkyvät edelleen sivun historiassa, mutta osa niiden sisällöstä ei enää ole saatavilla julkisesti.",
        "revdelete-text-file": "Poistetut tiedostoversiot näkyvät yhä sivun historiassa, mutta osa niiden sisällöstä ei ole saatavilla julkisesti.",
        "logdelete-text": "Poistetut lokimerkinnät näkyvät edelleen lokeissa, mutta osa niiden sisällöstä ei enää ole saatavilla julkisesti.",
-       "revdelete-text-others": "Muut ylläpitäjät sivustolla {{SITENAME}} kykenevät silti näkemään piilotetun sisällön ja voivat palauttaa sen takaisin näkyviin tämän saman käyttöliittymän kautta, paitsi silloin kun lisärajoituksia on asetettu.",
+       "revdelete-text-others": "Muut ylläpitäjät kykenevät silti näkemään piilotetun sisällön ja voivat palauttaa sen takaisin näkyviin, paitsi silloin kun lisärajoituksia on asetettu.",
        "revdelete-confirm": "Varmista, että haluat tehdä tämän – ymmärrät seuraukset ja teet tämän [[{{MediaWiki:Policy-url}}|käytäntöjen]] mukaisesti.",
        "revdelete-suppress-text": "Häivytystä pitäisi käyttää '''vain''' seuraavissa tapauksissa:\n* Mahdollisesti henkilön kunniaa loukkaavia tietoja\n* Sopimattomat henkilötiedot\n*: ''kotiosoitteet, puhelinnumerot, henkilötunnukset ja muut.''",
        "revdelete-legend": "Aseta version näkyvyyden rajoitukset",
        "mergehistory-box": "Yhdistä kahden sivun muutoshistoria",
        "mergehistory-from": "Lähdesivu",
        "mergehistory-into": "Kohdesivu",
-       "mergehistory-list": "Liitettävissä olevat muutokset",
+       "mergehistory-list": "Sivuhistoria, joka voidaan yhdistää",
        "mergehistory-merge": "Seuraavat sivun [[:$1]] muutokset voidaan liittää sivun [[:$2]] muutoshistoriaan. Voit valita version, jota myöhempiä muutoksia ei liitetä. Selainlinkkien käyttäminen kadottaa tämän valinnan.",
        "mergehistory-go": "Etsi muutokset",
        "mergehistory-submit": "Yhdistä versiot",
        "mergehistory-autocomment": "Yhdisti sivun [[:$1]] sivuun [[:$2]]",
        "mergehistory-comment": "Yhdisti sivun [[:$1]] sivuun [[:$2]]: $3",
        "mergehistory-same-destination": "Lähde- ja kohdesivut eivät voi olla samat",
-       "mergehistory-reason": "Syy",
+       "mergehistory-reason": "Syy:",
        "mergelog": "Yhdistämisloki",
        "pagemerge-logentry": "liitti sivun [[$1]] sivuun [[$2]] (muokkaukseen $3 asti)",
        "revertmerge": "Kumoa yhdistäminen",
        "right-deletedtext": "Tarkastella poistettujen sivujen tekstiä ja muutoksia poistettujen versioiden välillä",
        "right-browsearchive": "Hakea poistettuja sivuja",
        "right-undelete": "Palauttaa poistettuja sivuja",
-       "right-suppressrevision": "Tarkastella ja palauttaa ylläpitäjiltä piilotettuja versioita",
+       "right-suppressrevision": "Katsoa, piilottaa ja tuoda näkyviin tiettyjä sivujen versioita kaikilta käyttäjiltä",
+       "right-viewsuppressed": "Katsoa kaikilta käyttäjiltä piilotettuja versioita",
        "right-suppressionlog": "Tarkastella yksityisiä lokeja",
        "right-block": "Asettaa toiselle käyttäjälle muokkausesto",
        "right-blockemail": "Estää käyttäjää lähettämästä sähköpostia",
        "license": "Lisenssi",
        "license-header": "Lisenssi",
        "nolicense": "Ei lisenssiä",
+       "licenses-edit": "Muokkaa lisenssivaihtoehtoja",
        "license-nopreview": "(esikatselua ei saatavilla)",
        "upload_source_url": " (julkinen verkko-osoite)",
        "upload_source_file": " (tiedosto tietokoneella)",
+       "listfiles-delete": "poista",
        "listfiles-summary": "Tämä toimintosivu näyttää kaikki tallennetut tiedostot.",
        "listfiles_search_for": "Nimihaku",
        "imgfile": "tiedosto",
        "wantedpages-badtitle": "Virheellinen otsikko tuloksissa: $1",
        "wantedfiles": "Halutut tiedostot",
        "wantedfiletext-cat": "Seuraavia tiedostoja käytetään, mutta niitä ei ole olemassa. Ulkopuolissa mediavarastoissa olevat tiedostot voivat näkyä tällä listalla, vaikka ne ovat olemassa. Tällaiset väärät merkinnät on <del>yliviivattu</del>. Lisäksi sellaiset sivut, joihin on sisällytetty tiedostoja, jotka eivät ole olemassa, on luetteloitu [[:$1|täällä]].",
+       "wantedfiletext-cat-noforeign": "Seuraavat tiedostot ovat käytössä vaikka niitä ei ole olemassa. Luettelo sellaisista sivuista, joihin on upotettu olemattomia tiedostoja, on [[:$1]].",
        "wantedfiletext-nocat": "Seuraavia tiedostoja käytetään, mutta niitä ei ole olemassa. Ulkopuolissa mediavarastoissa olevat tiedostot voivat näkyä tällä listalla, vaikka ne ovat olemassa. Tällaiset väärät merkinnät on <del>yliviivattu</del.>",
+       "wantedfiletext-nocat-noforeign": "Seuraavia tiedostoja käytetään vaikka niitä ei ole olemassa.",
        "wantedtemplates": "Halutut mallineet",
        "mostlinked": "Viitatuimmat sivut",
        "mostlinkedcategories": "Viitatuimmat luokat",
        "deletedcontributions-title": "Poistetut muokkaukset",
        "sp-deletedcontributions-contribs": "muokkaukset",
        "linksearch": "Etsi ulkoisia linkkejä",
-       "linksearch-pat": "Osoite",
-       "linksearch-ns": "Nimiavaruus",
+       "linksearch-pat": "Hakuehto:",
+       "linksearch-ns": "Nimiavaruus:",
        "linksearch-ok": "Etsi",
        "linksearch-text": "Jokerimerkkejä, kuten \"*.wikipedia.org\", voidaan käyttää.\nVaaditaan vähintään ylätason verkkotunnus, esimerkiksi \"*.org\".<br />\n{{PLURAL:$2|Tuettu protokolla|Tuetut protokollat}}: <code>$1</code> (oletuksena on <code>http://</code>, jos protokollaa ei määritetä).",
        "linksearch-line": "$1 on linkitetty sivulta $2",
        "undelete-error-long": "Tiedoston palauttaminen epäonnistui:\n\n$1",
        "undelete-show-file-confirm": "Haluatko varmasti nähdä poistetun version tiedostosta <nowiki>$1</nowiki>, joka on tallennettu $2 kello $3?",
        "undelete-show-file-submit": "Kyllä",
-       "namespace": "Nimiavaruus",
+       "namespace": "Nimiavaruus:",
        "invert": "Käänteinen valinta",
        "tooltip-invert": "Valitse tämä kohta, jos haluat piilottaa muutokset sivuihin valitussa nimiavaruudessa (ja liittyviin nimiavaruuksiin, jos valittu)",
-       "namespace_association": "Liitetty nimiavaruus",
-       "tooltip-namespace_association": "Valitse tämä kohta, jos haluat sisällyttää myös keskustelu- tai aihe-nimiavaruudet, jotka on liitetty valittuun nimiavaruuteen",
+       "namespace_association": "Liittyvä nimiavaruus",
+       "tooltip-namespace_association": "Valitse tämä kohta, jos haluat sisällyttää ne keskustelu- tai aihe-nimiavaruudet, jotka liittyvät valittuun nimiavaruuteen",
        "blanknamespace": "(sivut)",
        "contributions": "{{GENDER:$1|Käyttäjän}} muokkaukset",
        "contributions-title": "Käyttäjän $1 muokkaukset",
        "blockip-legend": "Estä käyttäjä",
        "blockiptext": "Tällä toiminnolla voit estää käyttäjätunnusta tai IP-osoitetta muokkaamasta.<br />\nTällainen muokkausesto pitäisi asettaa vain vandalismin torjumiseksi ja [[{{MediaWiki:Policy-url}}|käytännön]] mukaisesti.\nKirjoita eston syy alla olevaan kenttään.",
        "ipaddressorusername": "IP-osoite tai käyttäjätunnus",
-       "ipbexpiry": "Kesto",
-       "ipbreason": "Syy",
+       "ipbexpiry": "Vanhentuu:",
+       "ipbreason": "Syy:",
        "ipbreason-dropdown": "*Yleiset estosyyt\n** Väärän tiedon lisääminen\n** Sisällön poistaminen\n** Mainoslinkkien lisääminen\n** Sotkeminen tai roskan lisääminen\n** Häiriköinti\n** Useamman käyttäjätunnuksen väärinkäyttö\n** Sopimaton käyttäjätunnus",
        "ipb-hardblock": "Estä sisäänkirjautuneita käyttäjiä muokkaamasta tästä IP-osoitteesta",
        "ipbcreateaccount": "Estä tunnusten luonti",
        "ipbemailban": "Estä käyttäjää lähettämästä sähköpostia",
        "ipbenableautoblock": "Estä automaattisesti viimeisin IP-osoite, josta käyttäjä on muokannut, sekä ne osoitteet, joista hän jatkossa yrittää muokata.",
        "ipbsubmit": "Estä",
-       "ipbother": "Muu kesto",
+       "ipbother": "Muu aikamääre:",
        "ipboptions": "2 tuntia:2 hours,1 päivä:1 day,3 päivää:3 days,1 viikko:1 week,2 viikkoa:2 weeks,1 kuukausi:1 month,3 kuukautta:3 months,6 kuukautta:6 months,1 vuosi:1 year,ikuinen:infinite",
        "ipbhidename": "Piilota tunnus muokkauksista ja listauksista",
        "ipbwatchuser": "Tarkkaile tämän käyttäjän käyttäjä- ja keskustelusivua",
        "allmessages-filter-unmodified": "Muuttamaton",
        "allmessages-filter-all": "Kaikki",
        "allmessages-filter-modified": "Muutettu",
-       "allmessages-prefix": "Suodata etuliitteellä",
+       "allmessages-prefix": "Suodata etuliitteellä:",
        "allmessages-language": "Kieli:",
        "allmessages-filter-submit": "Siirry",
        "allmessages-filter-translate": "Käännä",
        "siteuser": "{{GRAMMAR:genitive|{{SITENAME}}}} käyttäjä $1",
        "anonuser": "{{GRAMMAR:genitive|{{SITENAME}}}} anonyymi käyttäjä $1",
        "lastmodifiedatby": "Tätä sivua muokkasi viimeksi $3 $1 kello $2.",
-       "othercontribs": "Perustuu työlle, jonka teki $1.",
+       "othercontribs": "Perustuu seuraavien tekijöiden työhön: $1.",
        "others": "muut",
        "siteusers": "{{GRAMMAR:genitive|{{SITENAME}}}} {{PLURAL:$2|käyttäjä|käyttäjät}} $1",
        "anonusers": "{{GRAMMAR:genitive|{{SITENAME}}}} {{PLURAL:$2|anonyymi käyttäjä|anonyymit käyttäjät}} $1",
        "pageinfo-display-title": "Sivun otsikko",
        "pageinfo-default-sort": "Oletuslajitteluavain",
        "pageinfo-length": "Sivun pituus (tavuina)",
-       "pageinfo-article-id": "Sivun tunniste",
+       "pageinfo-article-id": "Sivun tunnistenumero",
        "pageinfo-language": "Sivun sisällön kieli",
        "pageinfo-content-model": "Sivun sisällön muoto",
        "pageinfo-robot-policy": "Hakukonemerkinnät",
        "pageinfo-toolboxlink": "Sivun tiedot",
        "pageinfo-redirectsto": "Ohjaus sivulle",
        "pageinfo-redirectsto-info": "tiedot",
-       "pageinfo-contentpage": "Lasketaan sisältösivuksi",
+       "pageinfo-contentpage": "Kohdellaan sisältösivuna",
        "pageinfo-contentpage-yes": "Kyllä",
        "pageinfo-protect-cascading": "Tämä on tarttuvan suojauksen lähdesivu",
        "pageinfo-protect-cascading-yes": "Kyllä",
        "size-kilobytes": "$1 KiB",
        "size-megabytes": "$1 MiB",
        "size-gigabytes": "$1 GiB",
+       "size-terabytes": "$1 TiB",
+       "size-petabytes": "$1 PiB",
+       "size-exabytes": "$1 EiB",
+       "size-zetabytes": "$1 ZiB",
+       "size-yottabytes": "$1 YiB",
+       "bitrate-bits": "$1 bit/s",
+       "bitrate-kilobits": "$1 kbit/s",
+       "bitrate-megabits": "$1 Mbit/s",
+       "bitrate-gigabits": "$1 Gbit/s",
+       "bitrate-terabits": "$1 Tbit/s",
+       "bitrate-petabits": "$1 Pbit/s",
+       "bitrate-exabits": "$1 Ebit/s",
+       "bitrate-zetabits": "$1 Zbit/s",
+       "bitrate-yottabits": "$1 Ybit/s",
        "lag-warn-normal": "Muutokset, jotka ovat uudempia kuin $1 {{PLURAL:$1|sekunti|sekuntia}}, eivät välttämättä näy tällä sivulla.",
        "lag-warn-high": "Tietokannoilla on työjonoa. Muutokset, jotka ovat uudempia kuin $1 {{PLURAL:$1|sekunti|sekuntia}}, eivät välttämättä näy tällä sivulla.",
        "watchlistedit-normal-title": "Tarkkailulistan muokkaus",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|keskustelu]])",
        "unknown_extension_tag": "Tuntematon laajennuskoodi ”$1”.",
        "duplicate-defaultsort": "'''Varoitus:''' Oletuslajitteluavain ”$2” korvaa aiemman oletuslajitteluavaimen ”$1”.",
+       "duplicate-displaytitle": "<strong>Varoitus:</strong> Näytettävä otsikko \"$2\" päällekirjoittaa edellisen otsikon \"$1\".",
        "version": "Versio",
        "version-extensions": "Asennetut laajennukset",
        "version-skins": "Asennetut ulkoasut",
        "intentionallyblankpage": "Tämä sivu on tarkoituksellisesti tyhjä.",
        "external_image_whitelist": " #Älä muuta tätä riviä lainkaan.<pre>\n#Laita säännöllisten lausekkeiden palaset (vain osa, joka menee //-merkkien väliin) alle\n#Niitä verrataan ulkoisten (suoralinkitettyjen) kuvien URLeihin\n#Ne jotka sopivat, näytetään kuvina, muutoin kuviin näytetään vain linkit\n#Rivit, jotka alkavat #-merkillä ovat kommentteja\n#Tämä on riippumaton kirjainkoosta\n\n#Laita kaikki säännöllisten lausekkeiden palaset tämän rivit yläpuolelle. Älä muuta tätä riviä lainkaan</pre>",
        "tags": "Voimassa olevat muutosmerkinnät",
-       "tag-filter": "[[Special:Tags|Merkintäsuodatin]]",
+       "tag-filter": "[[Special:Tags|Merkintä]]suodatin:",
        "tag-filter-submit": "Suodata",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Merkintä|Merkinnät}}]]: $2)",
        "tags-title": "Merkinnät",
        "pagelang-language": "Kieli",
        "pagelang-use-default": "Käytä oletuskieltä",
        "pagelang-select-lang": "Valitse kieli",
-       "right-pagelang": "Vaihda sivun kieli",
+       "right-pagelang": "Vaihtaa sivun kieli",
        "action-pagelang": "muuttaa sivun kieliasetuksia",
        "log-name-pagelang": "Kielenvaihtoloki",
        "log-description-pagelang": "Tämä on loki, johon merkitään muutokset sivujen kieliasetuksissa.",
index 4d0716c..2e56326 100644 (file)
        "gotaccountlink": "Rita inn",
        "userlogin-resetlink": "Hevur tú gloymt tínar logg inn upplýsingar",
        "userlogin-resetpassword-link": "Hevur tú gloymt títt loyniorð?",
+       "userlogin-helplink2": "Hjálp til innritan",
        "userlogin-loggedin": "Tú ert longu innritað/ur sum {{GENDER:$1|$1}}.\nNýt formularin niðanfyri fyri at rita inn sum ein annar brúkari.",
        "userlogin-createanother": "Stovna eina aðra kontu",
        "createacct-emailrequired": "Teldupost adressa",
        "resetpass-submit-loggedin": "Broyt loyniorð",
        "resetpass-submit-cancel": "Ógildað",
        "resetpass-wrong-oldpass": "Ógyldug fyribils ella verandi loyniorð.\nMøguliga hevur tú longu broytt títt loyniorð ella biðið um eitt nýtt fyribils loyniorð.",
+       "resetpass-recycled": "Vinarliga broyt títt loyniorð til okkurt annað enn tað tú hevur í løtuni.",
+       "resetpass-temp-emailed": "Tú hevur ritað inn við einum fyribils loyniorði frá telduposti. \nFyri at gjøgnumføra innritanina, so mást tú velja tær eitt nýtt loyniorð og skriva tað her:",
        "resetpass-temp-password": "Fyribils loyniorð",
        "resetpass-abort-generic": "Broyting av loyniorði bleiv avbrotin av einari víðkan.",
+       "resetpass-expired": "Títt loyniorð er útgingið. Vinarliga vel tær eitt nýtt, so tú kanst rita inn.",
+       "resetpass-expired-soft": "Títt loyniorð er útgingið og má broytast. Vinarliga vel tær eitt nýtt nú ella trýst á \"{{int:resetpass-submit-cancel}}\" fyri at broyta tað seinni.",
        "passwordreset": "Nullstilla loyniorðið",
        "passwordreset-text-one": "Útfyll henda teigin fyri at nullstilla títt loyniorð.",
        "passwordreset-text-many": "{{PLURAL:$1|Útfyll í ein av teigunum fyri at móttaka eitt fyribils loyniorð við telduposti.}}",
        "edit-gone-missing": "Tað var ikki møguligt at dagføra síðuna.\nTað sær út til at hon er blivin strikað.",
        "edit-conflict": "Rættingar trupulleiki (konflikt).",
        "edit-no-change": "Tín rætting var sæð burtur frá, tí ongin broyting varð gjørd í tekstinum.",
+       "postedit-confirmation-created": "Síðan er upprættað.",
+       "postedit-confirmation-restored": "Síðan er endurskapað.",
        "postedit-confirmation-saved": "Tín rætting varð goymd.",
        "edit-already-exists": "Tað var ikki møguligt at upprætta nýggja síðu.\nSíðan er longu til.",
        "defaultmessagetext": "Standard boðtekstur",
        "undo-summary-username-hidden": "Angra versjón $1 sum ein fjaldur brúkari hevur gjørt",
        "cantcreateaccounttitle": "Tað ber ikki til at upprætta konto",
        "cantcreateaccount-text": "Upprættan frá hesi IP adressuni ('''$1''') er blivin sperrað av [[User:$3|$3]]. Orsøkin til sperringina sigst vera ''$2''\n\n$3 sigur orsøkina vera ''$2''",
+       "cantcreateaccount-range-text": "IP adressur í intervallinum '''$1''', sum fevnir um tína IP adressu ('''$4'''), eru sperraðar fyri upprættan av nýggjari konto av [[User:$3|$3]].\n\n$3 segði orsøkina vera ''$2''",
        "viewpagelogs": "Sí logg fyri hesa grein",
        "nohistory": "Eingin broytisøga er til hesa síðuna.",
        "currentrev": "Núverandi endurskoðan",
        "currentrev-asof": "Seinasta endurskoðan sum var $1",
        "revisionasof": "Endurskoðan frá $1",
-       "revision-info": "Versjón frá $1 av $2",
+       "revision-info": "Versjón frá $1 av {{GENDER:$6|$2}}$7",
        "previousrevision": "←Eldri endurskoðan",
        "nextrevision": "Nýggjari endurskoðan→",
        "currentrevisionlink": "Skoða verandi endurskoðan",
        "search-section": "(sektión $1)",
        "search-suggest": "Meinti tú: $1",
        "search-interwiki-caption": "Líknandi verkætlanir",
-       "search-interwiki-default": "$1 úrslit:",
+       "search-interwiki-default": "Úrslit frá $1:",
        "search-interwiki-more": "(meira)",
        "search-relatedarticle": "Líknandi",
        "searchrelated": "líknandi",
        "searchall": "alt",
        "showingresults": "Niðanfyri standa upp til {{PLURAL:$1|'''$1''' úrslit, sum byrjar|'''$1''' úrslit, sum byrja}} við #<b>$2</b>.",
+       "showingresultsinrange": "Niðanfyri verða víst upp til {{PLURAL:$1|<strong>1</strong> úrslit|<strong>$1</strong> úrslit}} í økinum #<strong>$2</strong> til #<strong>$3</strong>.",
        "showingresultsheader": "{{PLURAL:$5|Úrslit '''$1''' av '''$3'''|Úrslit '''$1 - $2''' av '''$3'''}} fyri '''$4'''",
        "search-nonefound": "Leitingin gav onki úrslit.",
        "powersearch-legend": "Víðkað leitan",
        "powersearch-togglelabel": "Kanna eftir:",
        "powersearch-toggleall": "Alt",
        "powersearch-togglenone": "Ongi",
+       "powersearch-remember": "Minst til tað valda til framtíðar leitingar",
        "search-external": "Uttanhýsis leitan",
        "searchdisabled": "{{SITENAME}} leitan er sett úr gildi.\nTú kanst leita via Google ímeðan.\nLegg til merkis, at teirra innihaldsyvirlit av {{SITENAME}} kann vera gamalt og ikki dagført.",
        "search-error": "Ein feilur hendi undir leitanini: $1",
        "preferences": "Innstillingar",
        "mypreferences": "Innstillingar",
        "prefs-edits": "Tal av rættingum:",
+       "prefsnologintext2": "Vinarliga $1 fyri at broyta tínar innstillingat.",
        "prefs-skin": "Hamur",
        "skin-preview": "Forskoðan",
        "datedefault": "Ongi serlig ynskir",
        "right-move": "Flyt síður",
        "right-move-subpages": "Flyt síður saman við undirsíðum teirra",
        "right-move-rootuserpages": "Flyta høvuðs brúkarasíður",
+       "right-move-categorypages": "Flyt bólkasíður",
        "right-movefile": "Flyt fílur",
        "right-suppressredirect": "Flyta síður uttan at upprætta víðaristilling frá tí gomlu síðuni.",
        "right-upload": "Legg upp fílur",
        "action-createpage": "upprætta síður",
        "action-createtalk": "upprætta kjak síður",
        "action-createaccount": "upprætta hesa brúkarakontuna",
+       "action-history": "vís søguna hjá hesi síðu",
        "action-minoredit": "marka hesa rætting sum lítla",
        "action-move": "flyt hesa síðu",
        "action-move-subpages": "flyt hesa síðu og undirsíður hennara",
        "action-move-rootuserpages": "flyt høvuðs brúkarasíður",
+       "action-move-categorypages": "Flyt bólkasíður",
        "action-movefile": "flyt hesa fílu",
        "action-upload": "send hesa fílu upp",
        "action-reupload": "yvirskriva hesa verandi fíluna",
        "recentchanges-label-minor": "Hetta er ein lítil rætting",
        "recentchanges-label-bot": "Henda rætting varð gjørd av einum botti",
        "recentchanges-label-unpatrolled": "Henda rætting er ikki blivin eftirkannað enn",
+       "recentchanges-label-plusminus": "Støddin á síðuni broyttist við hesum talinum av bytes",
        "recentchanges-legend-heading": "'''Teknfrágreiðing:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (sí eisini [[Special:NewPages|yvirlit yvir nýggjar síður]])",
-       "rcnotefrom": "Niðanfyri standa broytingarnar síðani '''$2''', (upp til '''$1''' er sýndar).",
+       "rcnotefrom": "Niðanfyri verða broytingar síðan <strong>$2</strong> (upp til <strong>$1</strong> vístar).",
        "rclistfrom": "Sýn nýggjar broytingar byrjandi við $3 $2",
        "rcshowhideminor": "$1 minni rættingar",
+       "rcshowhideminor-show": "Vís",
+       "rcshowhideminor-hide": "Fjal",
        "rcshowhidebots": "$1 bottar",
+       "rcshowhidebots-show": "Vís",
+       "rcshowhidebots-hide": "Fjal",
        "rcshowhideliu": "$1 skrásettir brúkarar",
+       "rcshowhideliu-show": "Vís",
+       "rcshowhideliu-hide": "Fjal",
        "rcshowhideanons": "$1 navnleysar brúkarar",
+       "rcshowhideanons-show": "Vís",
+       "rcshowhideanons-hide": "Fjal",
        "rcshowhidepatr": "$1 eftirhugdar rættingar",
+       "rcshowhidepatr-show": "Vís",
+       "rcshowhidepatr-hide": "Fjal",
        "rcshowhidemine": "$1 mínar rættingar",
+       "rcshowhidemine-show": "Vís",
+       "rcshowhidemine-hide": "Fjal",
        "rclinks": "Sýn seinastu $1 broytingarnar seinastu $2 dagarnar<br />$3",
        "diff": "munur",
        "hist": "søga",
        "lockmanager-fail-svr-acquire": "Kundi ikki skaffa lás til dátagrunnin $1.",
        "lockmanager-fail-svr-release": "Kundi ikki loysa lásini í ambætaranum $1.",
        "uploadstash": "Legg út stash",
+       "uploadstash-clear": "Rudda burtur stashaðar fílur",
        "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\".",
index 9d3fd76..8f6c670 100644 (file)
                        "아라",
                        "Scoopfinder",
                        "Akeron",
-                       "Linedwell"
+                       "Linedwell",
+                       "Yona b",
+                       "SnowedEarth",
+                       "Orikrin1998"
                ]
        },
        "tog-underline": "Souligner les liens :",
        "tog-minordefault": "Marquer toutes mes modifications comme mineures par défaut",
        "tog-previewontop": "Afficher la prévisualisation au-dessus de la zone de modification",
        "tog-previewonfirst": "Afficher la prévisualisation lors de la première modification",
-       "tog-enotifwatchlistpages": "M'avertir par courriel lorsqu'une page ou un fichier de ma liste de suivi est modifiée",
+       "tog-enotifwatchlistpages": "M'avertir par courriel lorsqu'une page ou un fichier de ma liste de suivi est modifié",
        "tog-enotifusertalkpages": "M'avertir par courriel si ma page de discussion est modifiée",
        "tog-enotifminoredits": "M'avertir par courriel également lors des modifications mineures de pages ou de fichiers",
        "tog-enotifrevealaddr": "Afficher mon adresse de courriel dans les courriels de notification",
        "talkpagelinktext": "discuter",
        "specialpage": "Page spéciale",
        "personaltools": "Outils personnels",
-       "postcomment": "Nouvelle section",
        "articlepage": "Voir la page de contenu",
        "talk": "Discussion",
        "views": "Affichages",
        "externaldberror": "Une erreur s'est produite avec la base de données d'authentification externe, ou bien vous n'êtes pas autorisé{{GENDER:||e|(e)}} à mettre à jour votre compte externe.",
        "login": "Connexion",
        "nav-login-createaccount": "Créer un compte ou se connecter",
-       "loginprompt": "Vous devez activer les cookies pour vous connecter à {{SITENAME}}.",
        "userlogin": "Créer un compte ou se connecter",
        "userloginnocreate": "Connexion",
        "logout": "Se déconnecter",
        "revdelete-text-text": "Les révisions supprimées continueront à apparaître dans l’historique de la page, mais une partie de leur contenu sera inaccessible au public.",
        "revdelete-text-file": "Les versions de fichier supprimées continueront à apparaître dans l’historique des fichiers, mais une partie de leur contenu sera indisponible au public.",
        "logdelete-text": "Les évènements du journal supprimés continueront à apparaître dans les journaux, mais une partie de leur contenu sera indisponible au public.",
-       "revdelete-text-others": "Les autres administrateurs de {{SITENAME}} seront toujours capables d'accéder au contenu caché et peuvent le restaurer à nouveau par cette interface, à moins que des restrictions additionnelles soient définies.",
+       "revdelete-text-others": "Les autres administrateurs seront toujours en mesure d'accéder au contenu caché et le restaurer, à moins que des restrictions supplémentaires soient fixées.",
        "revdelete-confirm": "Confirmez que vous voulez effectuer cette action, que vous en comprenez les conséquences, et que vous le faites en accord avec [[{{MediaWiki:Policy-url}}|les règles]].",
        "revdelete-suppress-text": "La suppression ne doit être utilisée '''que''' dans les cas suivants :\n* Informations potentiellement diffamatoires\n* Informations personnelles inappropriées\n*: ''adresse, numéro de téléphone, numéro de sécurité sociale, …''",
        "revdelete-legend": "Mettre en place des restrictions de visibilité :",
        "right-deletedtext": "Voir le texte supprimé et les différences entre les versions supprimées",
        "right-browsearchive": "Rechercher des pages supprimées",
        "right-undelete": "Restaurer une page supprimée",
-       "right-suppressrevision": "Examiner et restaurer les versions masquées aux administrateurs",
+       "right-suppressrevision": "Afficher, masquer et démasquer des révisions spécifiques de pages pour n’importe quel utilisateur",
+       "right-viewsuppressed": "Afficher les révisions masquées pour n’importe quel utilisateur",
        "right-suppressionlog": "Voir les journaux privés",
        "right-block": "Bloquer en écriture d'autres utilisateurs",
        "right-blockemail": "Empêcher un utilisateur d'envoyer des courriels",
        "license": "Licence",
        "license-header": "Conditions d'utilisation",
        "nolicense": "Aucune licence sélectionnée",
+       "licenses-edit": "Modifier les options de licence",
        "license-nopreview": "(Prévisualisation non disponible)",
        "upload_source_url": " (une URL valide et accessible publiquement)",
        "upload_source_file": " (un fichier sur votre ordinateur)",
+       "listfiles-delete": "supprimer",
        "listfiles-summary": "Cette page spéciale permet de lister tous les fichiers importés.",
        "listfiles_search_for": "Rechercher un nom de média :",
        "imgfile": "fichier",
        "wantedpages-badtitle": "Titre invalide dans les résultats : $1",
        "wantedfiles": "Fichiers les plus demandés",
        "wantedfiletext-cat": "Les fichiers suivants sont utilisés, mais n'existent pas localement. S'ils se trouvent sur un dépôt partagé, ils peuvent être listés ici, bien qu'ils soient, de fait, déjà disponibles. Tous ces faux positifs seront <del>barrés</del>. En outre, les pages qui intègrent des fichiers qui n'existent pas sont répertoriées dans [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Les fichiers suivants sont utilisés mais n'existent pas. De plus, les pages qui intègrent les fichiers qui n'existent pas sont listés dans [[:$1]].",
        "wantedfiletext-nocat": "Les fichiers suivants sont utilisés, mais n'existent pas localement. S'ils se trouvent sur un dépôt partagé, ils peuvent être listés ici, bien qu'ils soient, de fait, déjà disponibles. Tous ces faux positifs seront <del>barrés</del>.",
+       "wantedfiletext-nocat-noforeign": "Les fichiers suivants sont utilisés mais n'existent pas.",
        "wantedtemplates": "Modèles demandés",
        "mostlinked": "Pages les plus liées",
        "mostlinkedcategories": "Catégories les plus utilisées",
        "tooltip-ca-nstab-help": "Voir la page d'aide",
        "tooltip-ca-nstab-category": "Voir la page de la catégorie",
        "tooltip-minoredit": "Marquer mes modifications comme mineures",
-       "tooltip-save": "Enregister vos modifications",
+       "tooltip-save": "Enregistrer vos modifications",
        "tooltip-preview": "Merci de prévisualiser vos modifications avant de les publier",
        "tooltip-diff": "Affiche les modifications que vous avez apportées au texte",
        "tooltip-compareselectedversions": "Afficher les différences entre deux versions de cette page",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discussion]])",
        "unknown_extension_tag": "Balise d’extension « $1 » inconnue",
        "duplicate-defaultsort": "Attention : la clé de tri par défaut « $2 » écrase la précédente clé « $1 ».",
+       "duplicate-displaytitle": "<strong>Attention :</strong> Le titre d'affichage «$2» remplace l'ancien titre d'affichage «$1».",
        "version": "Version",
        "version-extensions": "Extensions installées",
        "version-skins": "Habillages installés",
index ae9dfde..6bb0457 100644 (file)
        "permalink": "Permanent link",
        "print": "Drük",
        "view": "Lees",
+       "view-foreign": "Üüb $1 uunluke",
        "edit": "Bewerke",
+       "edit-local": "Lokaal beskriiwang bewerke",
        "create": "Maage",
+       "create-local": "Lokaal beskriiwang diartudu",
        "editthispage": "Sidj bewerke",
        "create-this-page": "Nei sidj maage",
        "delete": "Strik",
        "jumptonavigation": "Nawigatjuun",
        "jumptosearch": "Schük",
        "view-pool-error": "Det dää üs iarag, a servers san auerläästet.\nTuföl brükern ferschük, det sidj tu beschüken.\nWees so gud an teew en uugenblak, iar dü det noch ans ferschükst.\n\n$1",
+       "generic-pool-error": "Det dää üs iarag, a servers san tu tidj auerläästet.\nTuföl brükern ferschük, det sidj tu beschüken.\nWees so gud an teew en uugenblak, iar dü det noch ans weder ferschükst.",
        "pool-timeout": "Tidj uflepen bi't teewen üüb't sperang",
        "pool-queuefull": "Pool as auerläästet",
        "pool-errorunknown": "Ünbekäänd feeler",
        "edit-gone-missing": "Detdiar sidj küd ei aktualisiaret wurd. Ferlicht as det stregen wurden.",
        "edit-conflict": "Konflikt bi't bewerkin (BK).",
        "edit-no-change": "Din feranrang woort ei seekert, auer dü di tekst ei feranert heest.",
+       "postedit-confirmation-created": "Det sidj as maaget wurden.",
+       "postedit-confirmation-restored": "Det sidj as weder turaghaalet wurden.",
        "postedit-confirmation-saved": "Din feranrang as seekert wurden.",
        "edit-already-exists": "Det nei sidj küd ei iinracht wurd. Son sidj as al diar.",
        "defaultmessagetext": "Standard tekst",
        "parser-template-recursion-depth-warning": "Tuföl föörlaagen uun föörlaagen ($1)",
        "language-converter-depth-warning": "Spriakenkonwerter auerläästet ($1)",
        "node-count-exceeded-category": "Jodiar sidjen haa tuföl ferbinjangen (nodes)",
+       "node-count-exceeded-category-desc": "En kategorii för sidjen mä tuföl knooter (nodes).",
        "node-count-exceeded-warning": "Detdiar sidj hää tuföl ferbinjangen (nodes)",
        "expansion-depth-exceeded-category": "Jodiar sidjen haa tuföl ütjwidjangen (expansion)",
+       "expansion-depth-exceeded-category-desc": "Det as en kategorii för sidjen mä tuföl ütjwidjangen.",
        "expansion-depth-exceeded-warning": "Detdiar sidj hää tuföl ütjwidjangen (expansion)",
        "parser-unstrip-loop-warning": "Diar as en jinsidjag ferwisang",
        "parser-unstrip-recursion-limit": "Tuföl jinsidjag ferwisangen bi $1",
        "currentrev": "Leetst werjuun",
        "currentrev-asof": "Leetst werjuun faan di $2, am a klook $3",
        "revisionasof": "Werjuun faan a $2, klook $3",
-       "revision-info": "Werjuun faan di $4 am a klook $5 faan $2",
+       "revision-info": "Werjuun faan di $4, am a klook $5 faan {{GENDER:$6|$2}}$7",
        "previousrevision": "← Naistääler werjuun:",
        "nextrevision": "Naistjonger werjuun →",
        "currentrevisionlink": "Leetst werjuun",
        "mergehistory-empty": "Nian werjuunen kön tuupfeerd wurd.",
        "mergehistory-success": "$3 {{PLURAL:$3|werjuun|werjuunen}} faan [[:$1]] tuupfeerd tu [[:$2]].",
        "mergehistory-fail": "Werjuunen kön ei tuupfeerd wurd. Luke noch ans efter at sidj an a tidjen.",
+       "mergehistory-fail-toobig": "A werjuunen küd ei tuupfeerd wurd, auer muar üs {{PLURAL:$1|ian werjuun|$1 werjuunen}} fersköwen {{PLURAL:$1|wurd skul|wurd skul}}.",
        "mergehistory-no-source": "Det iarst sidj \"$1\" as ai diar.",
        "mergehistory-no-destination": "Det ööder sidj „$1“ as ei diar.",
        "mergehistory-invalid-source": "Jurtkamstsid mötj en gülti sidnoome heewe.",
        "powersearch-togglelabel": "Schük uun:",
        "powersearch-toggleall": "Aaltumaal",
        "powersearch-togglenone": "Nianen",
+       "powersearch-remember": "Ütjwool mark för leeder schükuunfraagen",
        "search-external": "Schük ekstern",
        "searchdisabled": "Det schüken üüb {{SITENAME}} as ei aktiif. Dü könst uuntesken mä Google schük. Seenk diaram, dat Google sin steegwurden miast ei üüb a leetst stant san.",
        "search-error": "Diar as wat skiaf gingen bi't schüken: $1",
        "right-move": "Sidjen fersküüw",
        "right-move-subpages": "Sidjen mä onersidjen fersküüw",
        "right-move-rootuserpages": "Hood-brükersidj fersküüw",
+       "right-move-categorypages": "Kategoriisidjen fersküüw",
        "right-movefile": "Datein fersküüw",
        "right-suppressredirect": "Bi't fersküüwen nian widjerfeerang iinracht",
        "right-upload": "Datein huuchschüür",
        "action-createpage": "nei sidjen tu maagin",
        "action-createtalk": "diskusjuunssidjen maage",
        "action-createaccount": "jüdeer brükerkonto mååge",
+       "action-history": "di ferluup faan detdiar sidj uuntulukin.",
        "action-minoredit": "detdiar feranrang üs letj kääntiakne",
        "action-move": "an fersküüw det diar sidj",
        "action-move-subpages": "an fersküüw detdiar sidj mä hör onersidjen",
        "action-move-rootuserpages": "hood-brükersidj fersküüw",
+       "action-move-categorypages": "kategoriisidjen uuntulukin",
        "action-movefile": "an fersküüw detdiar datei",
        "action-upload": "Datein huuchschüür",
        "action-reupload": "det datei auerskriiw",
        "windows-nonascii-filename": "Detheer wiki läät nian dateinöömer mä aparte tiakens tu.",
        "fileexists": "En datei mä didiar nööm jaft at al. Luke noch ans efter <strong>[[:$1]]</strong>, wan dü ei gans seeker beest, of dü det anre wel.\n[[$1|thumb]]",
        "filepageexists": "En beskriiwangssidj för <strong>[[:$1]]</strong> as al diar, oober nian datei. Din beskriiwang woort ei apnimen. Det beskriiwangssidj mut do man efter't huuchschüüren noch ans efterluket wurd.\n[[$1|thumb]]",
-       "fileexists-extension": "Diar as al en datei mä di nööm: [[$2|thumb]]\n* Nööm faan det nei datei: <strong>[[:$1]]</strong>\n* Nööm faan det ual datei: <strong>[[:$2]]</strong>\nWees so gud an nem en öödern nööm.",
+       "fileexists-extension": "Diar as al en datei mä di nööm: [[$2|thumb]]\n* Nööm faan det nei datei: <strong>[[:$1]]</strong>\n* Nööm faan det ual datei: <strong>[[:$2]]</strong>\nWel dü ei ferlicht en beedern nööm brük?",
        "fileexists-thumbnail-yes": "Detdiar datei as was en sümnaielbil ''(thumbnail)''. [[$1|thumb]]\nLuke di det datei <strong>[[:$1]]</strong> noch ans uun.\nWan det det originaal bil as, säärst dü nian sümnaielbil huuchschüür.",
        "file-thumbnail-no": "Di dateinööm begant mä <strong>$1</strong>. Det as was en sümnaielbil ''(thumbnail)''.\nLuke noch ans efter, of dü det bil uun fol grate diar heest, an do schüür det huuch.",
        "fileexists-forbidden": "En datei mä didiar nööm jaft at al an koon ei auerskrewen wurd.\nGung noch ans turag an schüür det datei mä en öödern nööm huuch.\n[[File:$1|thumb|center|$1]]",
        "filedelete-maintenance": "Det striken of turaghaalin faan datein gongt uun uugenblak ei.",
        "filedelete-maintenance-title": "Det datei koon ei stregen wurd",
        "mimesearch": "Efter MIME-Typ schük",
-       "mimesearch-summary": "Üüb detheer sidj könst dü datein efter hör MIME-Typ filtre.\nDet formoot as leewen slach/onerslach üs uun det bispal: <code>image/jpeg</code>.",
+       "mimesearch-summary": "Üüb detheer sidj könst dü datein efter hör MIME-Typ filtre.\nDet formoot as leewen slach/onerslach üs uun det bispal: <code>image/jpeg</code> of uk <code>image/*</code>.",
        "mimetype": "MIME-Typ:",
        "download": "Deelloose",
        "unwatchedpages": "Sidjen, diar näämen uun't uug hää",
        "pageswithprop-prophidden-binary": "Binär eegenskapswäärs ferbürgen ($1)",
        "doubleredirects": "Dobelt widjerfeerangen",
        "doubleredirectstext": "Detheer list feert widjerfeerangen ap, diar üüb widjerfeerangen widjer feer.\nUun arke rä stun ferwisangen tu't iarst an ööder widjerfeerang an uk tu det sidj, huar det ööder widjerfeerang üüb ferwiset. <del>Trochstregen</del> iindracher san al bewerket wurden.",
-       "double-redirect-fixed-move": "[[$1]] as fersköwen wurden an feert nü widjer tu [[$2]].",
+       "double-redirect-fixed-move": "[[$1]] as fersköwen wurden. Hat feert nü widjer tu [[$2]].",
        "double-redirect-fixed-maintenance": "Dobelt widjerfeerang faan [[$1]] tu [[$2]] as apredet wurden.",
        "double-redirect-fixer": "Bot för widjerfeerangen",
        "brokenredirects": "Uunstaken widjerfeerangen",
        "wantedtemplates": "Föörlaagen, diar brükt wurd",
        "mostlinked": "Sidjen, huar a miast ööder sidjen üüb ferwise",
        "mostlinkedcategories": "Miast brükt kategoriin",
-       "mostlinkedtemplates": "Miast brükt föörlaagen",
+       "mostlinkedtemplates": "Miast iinbünjen sidjen",
        "mostcategories": "Sidjen mä a miast kategoriin",
        "mostimages": "Datein, huar a miast sidjen üüb ferwise",
        "mostinterwikis": "Sidjen mä a miast ferwisangen tu ööder spriaken",
        "listgrouprights-removegroup-self": "Aanj brükerkonto faan {{PLURAL:$2|detdiar skööl|jodiar sköölen}} wechnem: $1",
        "listgrouprights-addgroup-self-all": "Koon aal a sköölen tu't aanj brükerkonto tuwise",
        "listgrouprights-removegroup-self-all": "Koon aal a sköölen faan't aanj brükerkonto wechnem",
+       "listgrouprights-namespaceprotection-header": "Nöömrüm mögelkhaiden",
+       "listgrouprights-namespaceprotection-namespace": "Nöömrüm",
+       "listgrouprights-namespaceprotection-restrictedto": "Rochten faan di brüker tu bewerkin",
        "trackingcategories": "Kategoriin ferfulge",
        "trackingcategories-summary": "Üüb detdiar sidj stun ferfulagt kategoriin, diar faan't MediaWiki-software iindraanj wurden san. Hör nöömer kön feranert wurd, wan dü a süsteem-noorachten uun a {{ns:8}}-nöömrüm feranerst.",
        "trackingcategories-msg": "Kategorii ferfulge",
        "watchnologin": "Ei uunmeldet",
        "addwatch": "Uk uun't uug behual",
        "addedwatchtext": "Det sidj „[[:$1]]“ wel dü [[Special:Watchlist|uun't uug behual]].\nFeranrangen faan detdiar sidj wurd üüb detdiar list fäästhäälen.",
+       "addedwatchtext-short": "Det sidj „$1“ kaam tu din sidjen, diar dü uun't uug behual wel.",
        "removewatch": "Ei muar uun't uug behual",
        "removedwatchtext": "Det sidj „[[:$1]]“ as faan a sidjen, diar dü [[Special:Watchlist|uun't uug behual]] wel, wechnimen wurden.",
+       "removedwatchtext-short": "Det sidj „$1“ woort ei muar faan di uun't uug behäälen.",
        "watch": "Uun't uug behual",
        "watchthispage": "Detdiar sidj uun't uug behual",
        "unwatch": "Ei muar uun't uug behual",
        "unwatchthispage": "Ei muar uun't uug behual",
        "notanarticle": "Nään artiikel",
        "notvisiblerev": "Det werjuun faan en öödern brüker as stregen wurden.",
-       "watchlist-details": "Dü heest {{PLURAL:$1|1 sidj|$1 sidjen}} uun't uug.",
+       "watchlist-details": "Dü behäälst {{PLURAL:$1|1 sidj|$1 sidjen}} uun't uug, diarbi wurd diskuschuunsidjen ei mätääld.",
        "wlheader-enotif": "Di e-mail siinst as aktiif.",
        "wlheader-showupdated": "Nei feranert sidjen wurd '''fäät''' uunwiset.",
        "wlnote2": "Diar stun a feranrangen faan a leetst {{PLURAL:$1|stünj|<strong>$1</strong> stünjen}}, üüb a stant faan $2, $3.",
        "contributions-title": "Brükerbidracher för \"$1\"",
        "mycontris": "Bidracher",
        "contribsub2": "För {{GENDER:$3|$1}} ($2)",
+       "contributions-userdoesnotexist": "Son brükerkonto \"$1\" jaft at ei.",
        "nocontribs": "Diar wiar nian paasin brükerbidracher",
        "uctop": "(aktuel)",
        "month": "faan muun (of iarer):",
        "movepagetalktext": "Uk det diskusjuunssidj woort fersköwen, wan det diar as, '''oober ei, wan:'''\n*Diar al en diskusjuunssidj mä didiar nööm as, of\n*Dü detdiar mögelkhaid ütjslotst.\n\nUun didiar faal skel dü a diskusjuunssidjen faan hun tuupfeer.\n\nDreeg di '''nei''' tiitel bi '''ööder sidj''' iin, an diaroner '''en grünj''' för't amnäämen.",
        "movearticle": "Sidj fersküüw:",
        "moveuserpage-warning": "'''Paase üüb:''' Dü wel en brükersidj fersküüw. Seenk diaram, dat bluas det brükersidj amnäämd woort, oober '''ei''' di brüker. Hi behäält san ual nööm.",
+       "movecategorypage-warning": "<strong>Paase üüb:</strong> Dü wel jüst en kategoriisidj fersküüw. Seenk diaram, dat bluas det sidj fersköwen woort. A sidjen uun det kategorii wurd <em>ei</em> nei kategorisiaret.",
        "movenologintext": "Dü skel registriaret an [[Special:UserLogin|uunmeldet]] wees, am en sidj tu fersküüwen.",
        "movenotallowed": "Dü mutst nian sidjen fersküüw.",
        "movenotallowedfile": "Dü mutst nian datein fersküüw.",
        "cant-move-user-page": "Dü mutst nian brükersidjen fersküüw (bluas onersidjen).",
        "cant-move-to-user-page": "Dü mutst nian sidjen üüb en brükersidj fersküüw (bluas üüb onersidjen).",
+       "cant-move-category-page": "Dü mutst nian kategoriisidjen fersküüw.",
+       "cant-move-to-category-page": "Dü mutst nian sidj tu en kategoriisidj fersküüw.",
        "newtitle": "Müülj:",
        "move-watch": "Jodiar sidjen uun't uug behual",
        "movepagebtn": "Sidj fersküüw",
        "newimages-summary": "Detdiar spezial-sidj wiset a tuleetst huuchschüürd datein uun.",
        "newimages-legend": "Filter",
        "newimages-label": "Dateinööm (of en dial diarfaan):",
+       "newimages-showbots": "Faan bots huuchschüürd sidjen uunwise.",
        "noimages": "Niks tu sen.",
        "ilsubmit": "Schük",
        "bydate": "efter dootem",
        "watchlistedit-raw-done": "Det list mä sidjen, diar dü uun't uug behual wel, as nü üüb di neist stant.",
        "watchlistedit-raw-added": "{{PLURAL:$1|Ään iindrach as|$1 iindracher san}} diartu skrewen wurden:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|Ään iindrach as|$1 iindracher san}} wechnimen wurden:",
+       "watchlistedit-clear-title": "Nian sidjen muar uun't uug behual",
+       "watchlistedit-clear-legend": "Nian sidjen muar uun't uug behual",
+       "watchlistedit-clear-explain": "Aal a sidjennöömer wel dü ei muar uun't uug behual",
+       "watchlistedit-clear-titles": "Sidjennöömer:",
+       "watchlistedit-clear-submit": "Sidjen, diar dü uun't uug behual wel, strik (permanent)",
+       "watchlistedit-clear-done": "Det list mä sidjen, diar dü uun't uug behual wel, as nü leesag maaget wurden.",
+       "watchlistedit-clear-removed": "{{PLURAL:$1|Ään iindrach as|$1 iindracher san}} wechnimen wurden:",
+       "watchlistedit-too-many": "Diar san tuföl sidjen tu uunwisin heer.",
+       "watchlisttools-clear": "Nian sidjen muar uun't uug behual",
        "watchlisttools-view": "Uun't uug behual: Feranrangen",
        "watchlisttools-edit": "Normool bewerke",
        "watchlisttools-raw": "Uun't listenformoot bewerke",
        "duplicate-defaultsort": "'''Paase üüb:''' Di sortiarkai \"$2\" auerskraft di ual sortiarkai \"$1\"",
        "version": "Werjuun",
        "version-extensions": "Instaliaret ütjwidjangen",
+       "version-skins": "Instaliaret brükerskaker",
        "version-specialpages": "Spezial-sidjen",
        "version-parserhooks": "Ütjwidjet parserfunktjuunen",
        "version-variables": "Wariaabeln",
        "version-antispam": "''Spam''seekerangen",
-       "version-skins": "Brükerskaker",
        "version-other": "Ööders wat",
        "version-mediahandlers": "Ütjwidjet medien-funktjuunen",
        "version-hooks": "Hooks",
        "version-hook-name": "Hook nööm",
        "version-hook-subscribedby": "Aprepen faan",
        "version-version": "($1)",
+       "version-no-ext-name": "[saner nööm]",
        "version-license": "MediaWiki-lisens",
        "version-ext-license": "Lisens",
        "version-ext-colheader-name": "Ütjwidjang",
+       "version-skin-colheader-name": "Skak",
        "version-ext-colheader-version": "Werjuun",
        "version-ext-colheader-license": "Lisens",
        "version-ext-colheader-description": "Beskriiwang",
        "htmlform-no": "Naan",
        "htmlform-yes": "Ja",
        "htmlform-chosen-placeholder": "Schük ütj",
+       "htmlform-cloner-create": "Muar diartudu",
+       "htmlform-cloner-delete": "Wechnem",
+       "htmlform-cloner-required": "Dü skel tumanst ään wäärs uundu.",
        "sqlite-has-fts": "Werjuun $1 mä halep för't schüken uun di hialer tekst.",
        "sqlite-no-fts": "Werjuun $1 saner halep för't schüken uun di hialer tekst.",
        "logentry-delete-delete": "$1 {{Gender:$2}} hää det sidj $3 stregen",
        "expand_templates_remove_nowiki": "<nowiki>-tags uun't resultaat ei uunwise",
        "expand_templates_generate_xml": "XML-parser-buum uunwise",
        "expand_templates_generate_rawhtml": "Rä HTML uunwise",
-       "expand_templates_preview": "Föörskau"
+       "expand_templates_preview": "Föörskau",
+       "pagelanguage": "Ütjwool faan sidjenspriaken",
+       "pagelang-name": "Sidj",
+       "pagelang-language": "Spriak",
+       "pagelang-use-default": "Standard spriak brük",
+       "pagelang-select-lang": "Spriak ütjschük",
+       "right-pagelang": "Sidjenspriak feranre",
+       "action-pagelang": "det sidjenspriak tu feranrin",
+       "log-name-pagelang": "Logbuk för spriak-feranrangen",
+       "log-description-pagelang": "Det as en logbuk för sidjenspriak-feranrangen",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|hää}} det sidjenspriak för $3 faan $4 tu $5 feranert."
 }
index 670f610..b343117 100644 (file)
@@ -12,7 +12,9 @@
                        "Vipuser",
                        "Xiaomingyan",
                        "아라",
-                       "Mywood"
+                       "Mywood",
+                       "Duolaimi",
+                       "Impersonator 1"
                ]
        },
        "tog-underline": "下划链接",
        "talkpagelinktext": "谈詑",
        "specialpage": "特殊页",
        "personaltools": "个人工具",
-       "postcomment": "话滴想法",
        "articlepage": "看吖文章",
        "talk": "谈詑",
        "views": "眵",
        "viewsourcetext": "倷可以眵吖或复制个页𠮶源代码:",
        "protectedinterface": "个页给正嘞软件𠮶界面文本,佢拖锁到怕人乱扤。",
        "editinginterface": "'''Warning:''' You are editing a page which is used to provide interface text for the software.\nChanges to this page will affect the appearance of the user interface for other users.\nFor translations, please consider using [//translatewiki.net/wiki/Main_Page?setlang=en translatewiki.net], the MediaWiki localisation project.",
-       "cascadeprotected": "个页已拖保护,因为佢拖“联锁保护”𠮶{{PLURAL:$1|一只|几只}}拖保护页包到:\n$2",
+       "cascadeprotected": "个页已拖保护,因为佢拖“级联”𠮶{{PLURAL:$1|一只|几只}}拖保护页包到:\n$2",
        "namespaceprotected": "倷冇权编写'''$1'''空间里度𠮶页面。",
        "ns-specialprotected": "编写伓正{{ns:special}}空间𠮶页面。",
        "virus-unknownscanner": "不晓得𠮶防病毒:",
        "readonlywarning": "'''警告: 数据库锁到嘞进行定期修护,眼下倷存伓正倷𠮶改动。倷可以拿佢存到文档再著。'''",
        "protectedpagewarning": "'''警告: 个页拕锁到哩,单就管理员许可权𠮶用户才改得正。'''\n下首系供得汝参考𠮶最晏𠮶日志。",
        "semiprotectedpagewarning": "'''注意:'''个页拕锁到哩,单就注册用户编得正。\n下首系供得汝参考𠮶最晏𠮶日志。",
-       "cascadeprotectedwarning": "警告: 个页已经受保护,单只管理员权限𠮶用户才改得正,因为个页同底下𠮶连锁保护𠮶{{PLURAL:$1|一只|多只}}页面包到嘞:",
+       "cascadeprotectedwarning": "警告: 个页已经受保护,单只管理员权限𠮶用户才改得正,因为个页同底下𠮶级联保护𠮶{{PLURAL:$1|一只|多只}}页面包到嘞:",
        "titleprotectedwarning": "'''警告:个只页锁到哩,需要[[Special:ListGroupRights|指定𠮶权限]]才建立得正。'''\n下首系供得汝参考𠮶最晏𠮶日志。",
        "templatesused": "个只页面使用𠮶有{{PLURAL:$1|模板|模板}}:",
        "templatesusedpreview": "个只预览使用𠮶有{{PLURAL:$1|模板|模板}}",
        "protect-fallback": "非要“$1”𠮶许可",
        "protect-level-autoconfirmed": "禁止冇注册𠮶用户",
        "protect-level-sysop": "只限操作员",
-       "protect-summary-cascade": "联锁",
+       "protect-summary-cascade": "级联",
        "protect-expiring": "$1 (UTC)到期",
-       "protect-cascade": "保护个页含到𠮶页面 (连锁保护)",
+       "protect-cascade": "保护个页含到𠮶页面 (级联保护)",
        "protect-cantedit": "倷改伓正个页𠮶保护程度,因为倷冇搦到编辑授权。",
        "protect-expiry-options": "两个钟头:2 hours,一日:1 day,三日:3 days,一个礼拜:1 week,两个礼拜:2 weeks,一个月:1 month,三个月:3 months,六个月:6 months,一年:1 year,一世:infinite",
        "restriction-type": "权限:",
index 58e4fc0..ee29121 100644 (file)
@@ -20,7 +20,7 @@
        "tog-numberheadings": "Cuir àireamhan ri ceann-sgrìobhaidhean leis fhèin",
        "tog-showtoolbar": "Seall am bàr-inneal deasachaidh",
        "tog-editondblclick": "Tòisich air deasachadh duilleige le briogadh dùbailte",
-       "tog-editsectiononrightclick": "Cuir an comas deasachadh earrainn le briogadh deas air tiotal de dh'earrainn",
+       "tog-editsectiononrightclick": "Cuir an comas deasachadh earrainn le briogadh deas air tiotal na h-earrainn",
        "tog-watchcreations": "Cuir duilleagan a chruthaicheas mi air a' chlàr-fhaire agam",
        "tog-watchdefault": "Cuir duilleagan a dheasaicheas mi air a' chlàr-fhaire agam",
        "tog-watchmoves": "Cuir duilleagan a ghluaiseas mi air a' chlàr-fhaire agam",
@@ -48,7 +48,7 @@
        "tog-showhiddencats": "Seall na roinnean-seòrsa falaichte",
        "tog-norollbackdiff": "Na seall na diofaran às dèidh roladh air ais",
        "tog-useeditwarning": "Thoir rabhadh dhomh ma bhios mi an impis duilleag deasachaidh fhàgail mus do shàbhail mi na mùthaidhean agam",
-       "tog-prefershttps": "Cleachd ceangal tèarainte an-còmhnaidh nuair a bhios mi clàraichte a-staigh",
+       "tog-prefershttps": "Cleachd ceangal tèarainte an-còmhnaidh nuair a bhios mi air logadh a-steach",
        "underline-always": "An-còmhnaidh",
        "underline-never": "Na dèan seo idir",
        "underline-default": "Bun-roghainn a' bhrabhsair no a' chraicinn",
        "help": "Cobhair",
        "search": "Lorg",
        "searchbutton": "Lorg",
-       "go": "Rach",
-       "searcharticle": "Rach",
+       "go": "Siuthad",
+       "searcharticle": "Siuthad",
        "history": "Eachdraidh na duilleige",
        "history_short": "Eachdraidh",
        "updatedmarker": "air ùrachadh on turas mu dheireadh a thadhail mi air",
        "talkpagelinktext": "Deasbaireachd",
        "specialpage": "Duilleag shònraichte",
        "personaltools": "Innealan pearsanta",
-       "postcomment": "Earrann ùr",
        "articlepage": "Seall duilleag na susbainte",
        "talk": "Deasbaireachd",
        "views": "Tadhalan",
        "filereadonlyerror": "Cha ghabh am faidhle \"$1\" atharrachadh a chionn 's gu bheil ionad-tasgaidh fhaidhlichean \"$2\" ri leughadh a-mhàin.\nThug an rianaire a ghlais e seachad an t-adhbhar a leanas: \"$3\".",
        "invalidtitle-knownnamespace": "Tiotal mì-dhligheach leis an ainm-spàs \"$2\" agus an teacsa \"$3\"",
        "invalidtitle-unknownnamespace": "Tiotal mì-dhligheach leis an àireamh ainm-spàis $1 agus an teacsa \"$2\"",
-       "exception-nologin": "Chan eil thu air clàradh a-steach",
-       "exception-nologin-text": "Feumaidh tu [[Special:Userlogin|clàradh a-steach]] mus fhaic thu an duilleag seo no mus urrainn dhut seo a dhèanamh.",
+       "exception-nologin": "Chan eil thu air logadh a-steach",
+       "exception-nologin-text": "Feumaidh tu [[Special:Userlogin|logadh a-steach]] mus fhaic thu an duilleag seo no mus urrainn dhut seo a dhèanamh.",
        "exception-nologin-text-manual": "Ma tha thu ag iarraidh cothrom air an duilleag no air a' ghnìomh seo, $1.",
        "virus-badscanner": "Droch cho-dhealbhachd: sganair bhìorasan neo-aithnichte: <em>$1</em>",
        "virus-scanfailed": "dh'fhàillig an sganadh (còd $1)",
        "virus-unknownscanner": "sganair bhìorasan neo-aithnichte:",
-       "logouttext": "<strong>Chaidh do chlàradh a-mach.</strong>\n\nThoir an aire gum bi coltas air cuid dhe na duilleagan mar gum biodh tu air clàradh a-steach gus am falamhaich thu tasgadan a' bhrabhsair agad.",
+       "logouttext": "<strong>Chaidh do logadh a-mach.</strong>\n\nThoir an aire gum bi coltas air cuid dhe na duilleagan mar gum biodh tu air logadh a-steach gus am falamhaich thu tasgadan a' bhrabhsair agad.",
        "welcomeuser": "Fàilte ort, $1",
        "welcomecreation-msg": "Chaidh an cunntas agad a chruthachadh.\nNa dìochuimhnich na [[Special:Preferences|roghainnean agad air {{SITENAME}}]] a ghleusadh dhut fhèin.",
        "yourname": "Ainm-cleachdaiche:",
        "userlogin-yourname": "Ainm-cleachdaiche",
        "userlogin-yourname-ph": "Cuir a-steach an t-ainm-cleachdaiche agad",
        "createacct-another-username-ph": "Cuir a-steach an t-ainm-cleachdaiche",
-       "yourpassword": "Am facal-faire agad",
+       "yourpassword": "Facal-faire:",
        "userlogin-yourpassword": "Facal-faire",
        "userlogin-yourpassword-ph": "Cuir a-steach am facal-faire agad",
        "createacct-yourpassword-ph": "Cuir a-steach facal-faire",
        "yourpasswordagain": "Ath-sgrìobh facal-faire",
-       "createacct-yourpasswordagain": "Dearbh am facal-faire",
+       "createacct-yourpasswordagain": "Dearbhaich am facal-faire",
        "createacct-yourpasswordagain-ph": "Cuir a-steach am facal-faire a-rithist",
        "remembermypassword": "Cuimhnich gu bheil mi air logadh a-steach air a' choimpiutair seo (suas gu $1 {{PLURAL:$1|latha|latha|làithean|latha}})",
-       "userlogin-remembermypassword": "Cum clàraichte a-staigh mi",
+       "userlogin-remembermypassword": "Cum air logadh a-steach mi",
        "userlogin-signwithsecure": "Cleachd ceangal tèarainte",
        "yourdomainname": "An àrainn-lìn agad:",
        "password-change-forbidden": "Chan urrainn dhut faclan-faire atharrachadh air an uicipeid seo.",
        "externaldberror": "Thachair mearachd le dearbhadh an stòir-dhàta air neo chan eil cead agad an cunntas agad air an taobh a-muigh ùrachadh.",
        "login": "Log a-steach",
        "nav-login-createaccount": "Log a-steach / cruthaich cunntas",
-       "loginprompt": "Feumaidh briosgaidean a bhith ceadaichte mus dèan thu logadh a-steach do {{SITENAME}}.",
        "userlogin": "Log a-steach / cruthaich cunntas",
        "userloginnocreate": "Log a-steach",
        "logout": "Log a-mach",
        "gotaccountlink": "Log a-steach",
        "userlogin-resetlink": "Na dhìochuimhnich thu d' ainm is facal-faire?",
        "userlogin-resetpassword-link": "Na dhìochuimhnich thu am facal-faire agad?",
-       "userlogin-helplink2": "Taic le clàradh a-steach",
-       "userlogin-loggedin": "Chaidh do chlàradh mar $1 mu thràth.\nCleachd am foirm gu h-ìosal airson clàradh a-steach mar chleachdaiche eile.",
+       "userlogin-helplink2": "Taic le logadh a-steach",
+       "userlogin-loggedin": "Chaidh do logadh a-steach mar $1 mu thràth.\nCleachd am foirm gu h-ìosal airson logadh a-steach mar chleachdaiche eile.",
        "userlogin-createanother": "Cruthaich cunntas eile",
        "createacct-emailrequired": "Seòladh puist-d",
        "createacct-emailoptional": "Seòladh puist-d (roghainneil)",
        "password-login-forbidden": "Tha an t-ainm-cleachdaiche 's am facal-faire seo toirmisgte.",
        "mailmypassword": "Ath-shuidhich am facal-faire",
        "passwordremindertitle": "Facal-faire sealach ùr airson {{SITENAME}}",
-       "passwordremindertext": "Dh'iarr cuideigin ('s mathaid gun do dh'iarr thusa seo on t-seòladh IP $1) facal-faire ùr airson {{SITENAME}} ($4). Chaidh facal-faire sealach a chruthachadh airson \"$2\" a tha 'na \"$3\".\nMa bha sin fa-near dhut, bidh agad ri clàradh a-steach agus facal-faire ùr a thaghadh\nan-dràsta fhèin. Falbhaidh an ùine air an fhacal-fhaire sealach agad ann an {{PLURAL:$5|$5 latha|$5 latha|$5 làithean|$5 latha}}.\n\nMa dh'iarr cuideigin eile seo no ma chuimhnich thu am facal-faire agad 's mur eil thu\nairson atharrachadh tuilleadh, 's urrainn dhut an teachdaireachd seo a leigeil seachad\nagus leantainn ort leis an t-seann fhacal-faire.",
+       "passwordremindertext": "Dh'iarr cuideigin ('s mathaid gun do dh'iarr thusa seo on t-seòladh IP $1) facal-faire ùr airson {{SITENAME}} ($4). Chaidh facal-faire sealach a chruthachadh airson \"$2\" a tha 'na \"$3\".\nMa bha sin fa-near dhut, bidh agad ri logadh a-steach agus facal-faire ùr a thaghadh\nan-dràsta fhèin. Falbhaidh an ùine air an fhacal-fhaire sealach agad ann an {{PLURAL:$5|$5 latha|$5 latha|$5 làithean|$5 latha}}.\n\nMa dh'iarr cuideigin eile seo no ma chuimhnich thu am facal-faire agad 's mur eil thu\nairson atharrachadh tuilleadh, 's urrainn dhut an teachdaireachd seo a leigeil seachad\nagus leantainn ort leis an t-seann fhacal-faire.",
        "noemail": "Cha deach post-d a chlàradh airson a' chleachdaiche \"$1\".",
        "noemailcreate": "Feumaidh tu post-d dligheach a chur ann",
-       "passwordsent": "Chaidh facal-faire ùr a chur dhan phost-d a chaidh a chlàradh airson \"$1\".\nClàraich a-steach a-rithist nuair a gheibh thu e.",
+       "passwordsent": "Chaidh facal-faire ùr a chur dhan phost-d a chaidh a chlàradh airson \"$1\".\nDèan logadh a-steach a-rithist nuair a gheibh thu e.",
        "blocked-mailpassword": "Chaidh bacadh a chur air an t-seòladh IP agad 's chan eil cead deasachaidh agad agus chan urrainn dhut an gleus a chum aiseag an fhacail-fhaire a chleachdadh gus casg a chur air mì-ghnàthachadh.",
        "eauthentsent": "Chaidh post-d dearbhaidh a chur dhan phost-d a chaidh ainmeachadh.\nMus dèid post-d sam bith eile a chur dhan chunntas, feumaidh tu leantainn ris an stiùireadh sa phost-d mar dhearbhadh gur ann agadsa a tha an cunntas.",
        "throttled-mailpassword": "Chaidh post-d a chur airson ath-shuidheachadh facail-fhaire mu thràth $1 {{PLURAL:$1|uair|uair|uairean|uair}} a thìde air ais.\nGus casg a chur air mì-ghnàthachadh, cha chuir sinn ach aon chuimhneachan facail-fhaire gach $1 {{PLURAL:$1|uair|uair|uairean|uair}} a thìde.",
        "emailauthenticated": "Chaidh an seòladh puist-d agad a dhearbhadh $2 aig $3.",
        "emailnotauthenticated": "Cha deach am post-d agad a dhearbhadh fhathast.\nCha dèid post-d a chur airson gin dhe na feartan a leanas.",
        "noemailprefs": "Sònraich post-d sna roghainnean agad gus na feartan seo a chur an comas.",
-       "emailconfirmlink": "Dearbh an seòladh puist-dhealain agad",
+       "emailconfirmlink": "Dearbhaich an seòladh puist-dhealain agad",
        "invalidemailaddress": "Chan urrainn dhuinn gabhail ris an t-seòladh seo a chionn 's gu bheil coltas cearr air.\nCuir a-steach seòladh san fhòrmat cheart no falamhaich an raon sin.",
        "cannotchangeemail": "Cha ghabh na puist-d a tha co-cheangailte ri cunntas atharrachadh air an uicipeid seo.",
        "emaildisabled": "Chan urrainn dhut puist-d a chur air an làrach seo.",
        "accountcreated": "Cunntas cruthaichte",
        "accountcreatedtext": "Chaidh an cunntas cleachdaiche airson [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|na deasbaireachd]]) a chruthachadh.",
        "createaccount-title": "Cruthachadh cunntais airson {{SITENAME}}",
-       "createaccount-text": "Chruthaich cuideigin cunntas airson a' phost-d agad air {{SITENAME}} ($4) air a bheil \"$2\", leis an fhacal-fhaire \"$3\".\nBu chòir dhut clàradh a-steach agus am facal-faire agad atharrachadh gu h-ìosal an-dràsta.\n\n'S urrainn dhut an teachdaireachd seo a leigeil seachad ma chaidh an cunntas a chruthachadh air mhearachd.",
-       "login-throttled": "Dh'fheuch thu ri clàradh a-steach ro thric o chionn ghoirid.\nFuirich ort $1 mus feuch thu ris a-rithist.",
-       "login-abort-generic": "Cha do shoirbhich leat leis a' chlàradh a-steach - Chaidh sgur dheth",
+       "createaccount-text": "Chruthaich cuideigin cunntas airson a' phost-d agad air {{SITENAME}} ($4) air a bheil \"$2\", leis an fhacal-fhaire \"$3\".\nBu chòir dhut logadh a-steach agus am facal-faire agad atharrachadh gu h-ìosal an-dràsta.\n\n'S urrainn dhut an teachdaireachd seo a leigeil seachad ma chaidh an cunntas a chruthachadh air mhearachd.",
+       "login-throttled": "Dh'fheuch thu ri logadh a-steach ro thric o chionn ghoirid.\nFuirich ort $1 mus feuch thu ris a-rithist.",
+       "login-abort-generic": "Cha do shoirbhich leat leis an logadh a-steach - Chaidh sgur dheth",
        "loginlanguagelabel": "Cànan: $1",
-       "suspicious-userlogout": "Chaidh d' iarrtas airson clàradh a-mach a dhiùltadh a chionn 's gu bheil coltas gun deach a chur le brabhsair briste no le progsaidh tasglannaidh.",
+       "suspicious-userlogout": "Chaidh d' iarrtas airson logadh a-mach a dhiùltadh a chionn 's gu bheil coltas gun deach a chur le brabhsair briste no le progsaidh tasglannaidh.",
        "createacct-another-realname-tip": "Cha leig thu leas innse dè am fìor-ainm a tha ort.\nMa bheir thu seachad e, thèid seo a chleachdadh gus urram a thoirt dha na h-ùghdaran airson an cuid obrach.",
        "pt-login": "Log a-steach",
        "pt-login-button": "Log a-steach",
        "user-mail-no-addy": "Cha do ghabh am post-d a chur leis nach robh seòladh puist-d ann.",
        "user-mail-no-body": "Bha bodhaig na teachdaireachd bàn no air leth goirid.",
        "changepassword": "Atharraich facal-faire",
-       "resetpass_announce": "Gus an clàradh a-steach a choileanadh, tha agad ri facal-faire ùr a shuidheachadh.",
+       "resetpass_announce": "Gus an logadh a-steach a choileanadh, tha agad ri facal-faire ùr a shuidheachadh.",
        "resetpass_text": "<!-- Cuir teacsa an-seo -->",
        "resetpass_header": "Atharraich facal-faire a' chunntais",
        "oldpassword": "Seann fhacal-faire",
        "newpassword": "Facal-faire ùr",
        "retypenew": "Ath-sgrìobh am facal-faire ùr",
-       "resetpass_submit": "Suidhich am facal-faire 's clàraich a-steach",
+       "resetpass_submit": "Suidhich am facal-faire 's dèan logadh a-steach",
        "changepassword-success": "Chaidh am facal-faire agad atharrachadh!",
-       "changepassword-throttled": "Dh'fheuch thu ri clàradh a-steach ro thric o chionn ghoirid.\nFuirich ort $1 mus feuch thu ris a-rithist.",
+       "changepassword-throttled": "Dh'fheuch thu ri logadh a-steach ro thric o chionn ghoirid.\nFuirich ort $1 mus feuch thu ris a-rithist.",
        "resetpass_forbidden": "Cha ghabh na faclan-faire atharrachadh",
-       "resetpass-no-info": "Feumaidh tu clàradh a-steach mus dèan thu inntrigeadh dìreach dhan duilleag seo.",
+       "resetpass-no-info": "Feumaidh tu logadh a-steach mus dèan thu inntrigeadh dìreach dhan duilleag seo.",
        "resetpass-submit-loggedin": "Atharraich am facal-faire",
        "resetpass-submit-cancel": "Sguir dheth",
        "resetpass-wrong-oldpass": "Tha am facal-faire sealach no làithreach mì-dhligheach.\nSaoil an do dh'atharraich thu am facal-faire agad mu thràth no an do dh'iarr thu facal-faire sealach ùr?",
        "resetpass-recycled": "Tagh facal-faire ùr nach eil co-ionnann ris an fhacal-fhaire a tha agad an-dràsta.",
-       "resetpass-temp-emailed": "Rinn thu clàradh a-steach le còd sealach a fhuair thu air a' phost-d.\nAirson clàradh a-steach slàn a dhèanamh, feumaidh tu facal-faire ùr a shuidheachadh an-seo:",
+       "resetpass-temp-emailed": "Rinn thu logadh a-steach le còd sealach a fhuair thu air a' phost-d.\nAirson logadh a-steach slàn a dhèanamh, feumaidh tu facal-faire ùr a shuidheachadh an-seo:",
        "resetpass-temp-password": "Facal-faire sealach:",
        "resetpass-abort-generic": "Chuir leudachan crìoch air atharrachadh an fhacail-fhaire.",
-       "resetpass-expired": "Dh'fhalbh an ùine air an fhacal-fhaire agad. Suidhich facal-faire ùr airson clàradh a-steach.",
+       "resetpass-expired": "Dh'fhalbh an ùine air an fhacal-fhaire agad. Suidhich facal-faire ùr airson logadh a-steach.",
        "resetpass-expired-soft": "Dh'fhalbh an ùine air an fhacal-fhaire agad is feumaidh tu ath-shuidheachadh. Tagh fear ùr no briog air \"{{int:resetpass-submit-cancel}}\" gus ath-shuidheachadh às a dhèidh seo.",
        "resetpass-validity-soft": "Chan eil am facal-faire seo dligheach: $1\n\nTagh facal-faire ùr an-dràsta no briog air \"{{int:resetpass-submit-cancel}}\" gus ath-shuidheachadh às a dhèidh seo.",
        "passwordreset": "Ath-shuidhich am facal-faire",
        "passwordreset-capture-help": "Ma chuireas tu cromag sa bhogsa seo, chì thusa am post-d (leis an fhacal-fhaire sealach) agus gheibh an cleachdaiche e cuideachd.",
        "passwordreset-email": "Seòladh puist-d:",
        "passwordreset-emailtitle": "Dàta a' chunntais air {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Dh'iarr cuideigin (thu fhèin, 's mathaid, on t-seòladh IP $1) am facal-faire airson {{SITENAME}} ($4) ath-shuidheachadh. Tha {{PLURAL:$3|an cunntas|na cunntasan}} a leanas co-cheangailte ris a' phost-d seo:\n\n$2\n\nFalbhaidh an ùine air {{PLURAL:$3|an fhacal-fhaire shealach|na faclan-faire sealach}} seo an ceann $5 {{PLURAL:$5|latha|latha|làithean|latha}}.\nBu chòir dhut clàradh a-steach agus facal-faire ùr a thaghadh an-dràsta. Ma dh'iarr cuideigin eile seo no ma chuimhnich thu air an fhacal-fhaire agad 's mur eil thu airson atharrachadh tuilleadh, leig seachad an teachdaireachd seo 's lean ort leis an t-seann fhacal-fhaire.",
-       "passwordreset-emailtext-user": "Dh'iarr an cleachdaiche $1 air {{SITENAME}} ath-shuidheachadh an fhacail-fhaire air {{SITENAME}} ($4). Tha {{PLURAL:$3|an cunntas-cleachdaiche|na cunntasan-cleachdaiche}} a leanas co-cheangailte ris an t-seòladh puist-d seo:\n\n$2\n\nFalbhaidh an ùine air {{PLURAL:$3|an fhacal-fhaire shealach|na faclan-faire sealach}} seo an ceann $5 {{PLURAL:$5|latha|latha|làithean|latha}}.\nBu chòir dhut clàradh a-steach agus facal-faire ùr a thaghadh an-dràsta. Ma dh'iarr cuideigin eile seo no ma chuimhnich thu air an fhacal-fhaire agad 's mur eil thu airson atharrachadh tuilleadh, leig seachad an teachdaireachd seo 's lean ort leis an t-seann fhacal-fhaire.",
+       "passwordreset-emailtext-ip": "Dh'iarr cuideigin (thu fhèin, 's mathaid, on t-seòladh IP $1) am facal-faire airson {{SITENAME}} ($4) ath-shuidheachadh. Tha {{PLURAL:$3|an cunntas|na cunntasan}} a leanas co-cheangailte ris a' phost-d seo:\n\n$2\n\nFalbhaidh an ùine air {{PLURAL:$3|an fhacal-fhaire shealach|na faclan-faire sealach}} seo an ceann $5 {{PLURAL:$5|latha|latha|làithean|latha}}.\nBu chòir dhut logadh a-steach agus facal-faire ùr a thaghadh an-dràsta. Ma dh'iarr cuideigin eile seo no ma chuimhnich thu air an fhacal-fhaire agad 's mur eil thu airson atharrachadh tuilleadh, leig seachad an teachdaireachd seo 's lean ort leis an t-seann fhacal-fhaire.",
+       "passwordreset-emailtext-user": "Dh'iarr an cleachdaiche $1 air {{SITENAME}} ath-shuidheachadh an fhacail-fhaire air {{SITENAME}} ($4). Tha {{PLURAL:$3|an cunntas-cleachdaiche|na cunntasan-cleachdaiche}} a leanas co-cheangailte ris an t-seòladh puist-d seo:\n\n$2\n\nFalbhaidh an ùine air {{PLURAL:$3|an fhacal-fhaire shealach|na faclan-faire sealach}} seo an ceann $5 {{PLURAL:$5|latha|latha|làithean|latha}}.\nBu chòir dhut logadh a-steach agus facal-faire ùr a thaghadh an-dràsta. Ma dh'iarr cuideigin eile seo no ma chuimhnich thu air an fhacal-fhaire agad 's mur eil thu airson atharrachadh tuilleadh, leig seachad an teachdaireachd seo 's lean ort leis an t-seann fhacal-fhaire.",
        "passwordreset-emailelement": "Ainm-cleachdaiche: $1\nFacal-faire sealach: $2",
        "passwordreset-emailsent": "Chaidh post-d airson ath-shuidheachadh an fhacail-fhaire a chur.",
        "passwordreset-emailsent-capture": "Chaidh post-d a chum ath-shuidheachadh an fhacail-fhaire a chur agus chì thu sin gu h-ìosal.",
        "changeemail": "Atharraich am post-d",
        "changeemail-header": "Atharraich cunntas a' phuist-d",
        "changeemail-text": "Lìon am foirm seo gus am post-d agad atharrachadh. Feumaidh tu am facal-faire agad a chur a-steach a-rithist gus a dhearbhadh.",
-       "changeemail-no-info": "Feumaidh tu clàradh a-steach mus dèan thu inntrigeadh dìreach dhan duilleag seo.",
+       "changeemail-no-info": "Feumaidh tu logadh a-steach mus dèan thu inntrigeadh dìreach dhan duilleag seo.",
        "changeemail-oldemail": "An seòladh puist-d làithreach:",
        "changeemail-newemail": "An seòladh puist-d ùr:",
        "changeemail-none": "(chan eil gin)",
        "changeemail-password": "Am facal-faire agad air {{SITENAME}}:",
        "changeemail-submit": "Atharraich am post-d",
        "changeemail-cancel": "Sguir dheth",
-       "changeemail-throttled": "Dh'fheuch thu ri clàradh a-steach ro thric.\nFuirich ort $1 mus feuch thu ris a-rithist.",
+       "changeemail-throttled": "Dh'fheuch thu ri logadh a-steach ro thric.\nFuirich ort $1 mus feuch thu ris a-rithist.",
        "resettokens": "Ath-shuidhich na tòcanan",
        "resettokens-text": "'S urrainn dhut tòcanan ath-shuidheachadh a bheir cothrom dhut air cuid a dhàta prìobhaideach a tha co-cheangailte ris a' chunntas agad.\n\nBu chòir dhut seo a dhèanamh ma thug thu do chuideigin e air mhearachd no ma bhris cuideigin a-steach air a' chunntas agad.",
        "resettokens-no-tokens": "Chan eil tòcan ann a ghabhas ath-shuidheachadh.",
        "preview": "Ro-shealladh",
        "showpreview": "Seall an ro-shealladh",
        "showdiff": "Seall na mùthaidhean",
-       "anoneditwarning": "<strong>Rabhadh:</strong> Chan eil thu air logadh a-steach.\nThèid an seòladh IP agad a chlàrachadh ann an eachdraidh na duilleige seo.",
-       "anonpreviewwarning": "<em>Chan eil thu air clàradh a-steach. Ma nì thu sàbhaladh, thèid an seòladh IP agad a chlàradh ann an eachdraidh deasachadh na duilleige seo.</em>",
+       "anoneditwarning": "<strong>Rabhadh:</strong> Chan eil thu air logadh a-steach.\nThèid an seòladh IP agad a chlàradh ann an eachdraidh na duilleige seo.",
+       "anonpreviewwarning": "<em>Chan eil thu air logadh a-steach. Ma nì thu sàbhaladh, thèid an seòladh IP agad a chlàradh ann an eachdraidh deasachadh na duilleige seo.</em>",
        "missingsummary": "<strong>Cuimhnich:</strong> Cha dug thu seachad gearr-chunntas air na dh'atharraich thu.\nMa bhriogas tu air \"{{int:savearticle}}\" a-rithist, thèid na dheasaich thu a shàbhaladh as aonais gearr-chunntais.",
        "missingcommenttext": "Cuir a-steach beachd gu h-ìosal.",
        "missingcommentheader": "<strong>Cuimhnich:</strong> Cha dug thu seachad cuspair/ceann airson a' bheachd seo.\nMa bhriogas tu air \"{{int:savearticle}}\" a-rithist, thèid na dheasaich thu a shàbhaladh as aonais.",
        "confirmedittext": "Feumaidh tu am post-d agad a dhearbhadh mus urrainn dhut duilleagan a dheasachadh.\nSuidhich is dearbhaich am post-d agad ann an [[Special:Preferences|roghainnean a' chleachdaiche]]",
        "nosuchsectiontitle": "Cha ghabh an earrann a lorg",
        "nosuchsectiontext": "Dh'fheuch thu ri earrann a dheasachadh nach eil ann.\nDh'fhaoidte gun deach a ghluasad no a sguabadh às fhad 's a bha thu a' coimhead air an duilleag.",
-       "loginreqtitle": "Feumaidh tu clàradh a-steach",
+       "loginreqtitle": "Feumaidh tu logadh a-steach",
        "loginreqlink": "log a-steach",
        "loginreqpagetext": "Feumaidh tu $1 mus urrainn dhut coimhead air duilleagan eile.",
        "accmailtitle": "Facal-faire air a chur.",
-       "accmailtext": "Chaidh facal-faire a chruthachadh air thuaiream airson [[User talk:$1|$1]] 's a chur gu $2.\n\nGabhaidh am facal-faire airson a' chunntais ùir seo atharrachadh air an fo <em>[[Special:ChangePassword|atharraich facal-faire]]</em> às dèidh dhan chleachdaiche clàradh a-steach.",
+       "accmailtext": "Chaidh facal-faire a chruthachadh air thuaiream airson [[User talk:$1|$1]] 's a chur gu $2.\n\nGabhaidh am facal-faire airson a' chunntais ùir seo atharrachadh air an fo <em>[[Special:ChangePassword|atharraich facal-faire]]</em> às dèidh dhan chleachdaiche logadh a-steach.",
        "newarticle": "(Ùr)",
        "newarticletext": "Lean thu ri ceangal gu duilleag nach eil ann fhathast.\nCuir teacs sa bhogsa gu h-ìosal gus an duilleag seo a chruthachadh (seall air [$1 duilleag na cobharach] airson barrachd fiosrachaidh).\nMura robh dùil agad ris an duilleag seo a ruigsinn, briog air a' phutan <strong>air ais</strong> 'nad bhrabhsair.",
-       "anontalkpagetext": "----\n<em>Seo an duilleag deasbaireachd aig cleachdaiche gun urra nach do chruthaich cunntas fhathast no nach eil 'ga chleachdadh.</em>\nFeumaidh sinn an àireamh IP aca a chleachdadh air sgàth sin.\nFaodadh grunn chleachdaichean seòladh IP mar a chleachdadh còmhla.\nMas e cleachdaiche gun urra a tha annad 's ma tha thu dhen bheachd nach eil na beachdan seo a' buntainn riut, nach [[Special:UserLogin/signup|clàraich thu]] no [[Special:UserLogin|clàraich a-steach]] gus bùrach mar seo a sheachnadh san àm ri teachd?",
+       "anontalkpagetext": "----\n<em>Seo an duilleag deasbaireachd aig cleachdaiche gun urra nach do chruthaich cunntas fhathast no nach eil 'ga chleachdadh.</em>\nFeumaidh sinn an àireamh IP aca a chleachdadh air sgàth sin.\nFaodadh grunn chleachdaichean seòladh IP mar a chleachdadh còmhla.\nMas e cleachdaiche gun urra a tha annad 's ma tha thu dhen bheachd nach eil na beachdan seo a' buntainn riut, nach [[Special:UserLogin/signup|clàraich thu]] no nach dèan thu [[Special:UserLogin|logadh a-steach]] gus bùrach mar seo a sheachnadh san àm ri teachd?",
        "noarticletext": "Chan eil teacsa sam bith anns an duilleag seo an-dràsta.\n'S urrainn dhut [[Special:Search/{{PAGENAME}}|an tiotal seo a lorg]] ann an duilleagan eile,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} na logaichean co-cheangailte a rannsachadh],\nno [{{fullurl:{{FULLPAGENAME}}|action=edit}} an duilleag seo a dheasachadh]</span>.",
        "noarticletext-nopermission": "Chan eil teacsa sam bith san duilleag seo an-dràsta.\n'S urrainn dhut [[Special:Search/{{PAGENAME}}|tiotal na duilleige seo a lorg]] ann an duilleagan eile, no <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} na logaichean co-cheangailte a rannsachadh]</span> ach chan eil cead agad an duilleag seo a chruthachadh.",
        "missing-revision": "Chan eil mùthadh #$1 na duilleige \"{{FULLPAGENAME}}\" ann.\n\nMar is trice, tachraidh seo ma leanas tu ceangal san eachdraidh a tha fìor aosta 's a tha a' dol gu duilleag a chaidh a sguabadh às.\nGheibh thu mion-fhiosrachadh ann an [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} loga nan duilleagan a chaidh a sguabadh às].",
        "previewnote": "<strong>Cuimhnich nach eil ann ach ro-shealladh.</strong>\nCha deach na mùthaidhean agad a shàbhaladh fhathast!",
        "continue-editing": "Rach gun raon deasachaidh",
        "previewconflict": "Tha an ro-shealladh seo a' sealltainn dhut an teacsa san raon teacsa gu h-àrd mar a nochdas e ma shàbhaileas tu an-dràsta.",
-       "session_fail_preview": "<strong>Duilich! Cha b' urrainn dhuinn na dheasaich thu a làimhseachadh air sgàth call dàta an t-seisein.</strong>\nNach fheuch thu ris a-rithist?\nMur obraich e fhathast, feuch is [[Special:UserLogout|clàraich a-mach]] is a-steach a-rithist an uairsin.",
-       "session_fail_preview_html": "<strong>Duilich! Cha b' urrainn dhuinn na dheasaich thu a làimhseachadh air sgàth call dàta an t-seisein.</strong>\n\n<em>A chionn 's gun do chuir {{SITENAME}} còd HTML an comas, tha an ro-shealladh falaichte mar dhìon an aghaidh ionnsaighean JavaScript.</em>\n\n<strong>Mas e deasachadh dligheach a tha seo, feuch ris a-rithist.</strong>\nMur obraich e fhathast, feuch is [[Special:UserLogout|clàraich a-mach]] is a-steach a-rithist an uairsin.",
+       "session_fail_preview": "<strong>Duilich! Cha b' urrainn dhuinn na dheasaich thu a làimhseachadh air sgàth call dàta an t-seisein.</strong>\nNach fheuch thu ris a-rithist?\nMur obraich e fhathast, feuch is [[Special:UserLogout|log a-mach]] is a-steach a-rithist an uairsin.",
+       "session_fail_preview_html": "<strong>Duilich! Cha b' urrainn dhuinn na dheasaich thu a làimhseachadh air sgàth call dàta an t-seisein.</strong>\n\n<em>A chionn 's gun do chuir {{SITENAME}} còd HTML an comas, tha an ro-shealladh falaichte mar dhìon an aghaidh ionnsaighean JavaScript.</em>\n\n<strong>Mas e deasachadh dligheach a tha seo, feuch ris a-rithist.</strong>\nMur obraich e fhathast, feuch is dèan [[Special:UserLogout|logadh a-mach]] is a-steach a-rithist an uairsin.",
        "token_suffix_mismatch": "<strong>Dhiùlt sinn na dheasaich thu a chionn 's gun do chuir an cliant agad na caractaran puingeachaidh tro chèile san tòcan deasachaidh.</strong>\nDhiùlt sinn na dheasaich thu air eagal 's gun coirbeadh e teacsa na duilleige.\nTachraidh seo uaireannan ma chleachdar seirbheis-lìn progsaidh gun urra a tha làn de mhearachdan.",
        "edit_form_incomplete": "<strong>Cha do ràinig cuid dhen fhoirm deasachaidh am frithealaichte; dèan cinnteach gu bheil gach deasachadh agad slàn is feuch ris a-rithist.</strong>",
        "editing": "A' deasachadh $1",
        "hiddencategories": "Tha an duilleag seo 'na ball de {{PLURAL:$1|$1 roinn-seòrsa fhalaichte|$1 roinn-seòrsa fhalaichte|$1 roinnean-seòrsa falaichte|$1 roinn-seòrsa fhalaichte}}:",
        "edittools": "<!-- Nochdaidh an teacsa seo fo fhoirmean deasachaidh 's luchdaidh suas. -->",
        "edittools-upload": "-",
-       "nocreatetext": "Chuir {{SITENAME}} bacadh air cruthachadh de dhuilleagan ùra.\n'S urrainn dhut tilleadh is duilleag a tha ann mu thràth a dheasachadh no [[Special:UserLogin|clàradh a-steach no cunntas a chruthachadh]].",
+       "nocreatetext": "Chuir {{SITENAME}} bacadh air cruthachadh de dhuilleagan ùra.\n'S urrainn dhut tilleadh is duilleag a tha ann mu thràth a dheasachadh no [[Special:UserLogin|logadh a-steach no cunntas a chruthachadh]].",
        "nocreate-loggedin": "Chan eil cead agad duilleagan ùra a chruthachadh.",
        "sectioneditnotsupported-title": "Chan eil taic ri deasachadh earrannan",
        "sectioneditnotsupported-text": "Chan eil taic ri deasachadh earrannan air an duilleag seo.",
        "parser-unstrip-loop-warning": "Mhothaich sinn do lùb unstrip",
        "parser-unstrip-recursion-limit": "Chaidheas thairis air crìoch unstrip recursion ($1)",
        "converter-manual-rule-error": "Mhothaich sinn do mhearachd san riaghailt iompachadh làimhe airson cànan",
-       "undo-success": "Gabhaidh an deasachadh seo a neo-dhèanamh.\nThoir sùil air a' choimeas gu h-ìosal is dearbh gur e sin a tha fa-near dhut agus sàbhail na h-atharraichean gu h-ìosal gus neo-dhèanamh an deasachaidh a choileanadh.",
+       "undo-success": "Gabhaidh an deasachadh seo a neo-dhèanamh.\nThoir sùil air a' choimeas gu h-ìosal is dearbhaich gur e sin a tha fa-near dhut agus sàbhail na h-atharraichean gu h-ìosal gus neo-dhèanamh an deasachaidh a choileanadh.",
        "undo-failure": "Cha b' urrainn dhuinn an deasachadh a neo-dhèanamh air sgàth 's gun robh deasachaidhean eile sa mheadhan.",
        "undo-norev": "Cha b' urrainn dhuinn an deasachadh a neo-dhèanamh a chionn 's nach robh e ann no gun deach a sguabadh às.",
        "undo-nochange": "Tha coltas gun deach am mùthadh seo a neo-dhèanamh mu thràth.",
        "revdelete-text-file": "Nochdaidh tionndaidhean dhen fhaidhle a chaidh a sguabadh às ann an eachdraidh na duilleige fhathast ach chan fhaic buill a' phobaill cuid dhen t-susbaint aca.",
        "logdelete-text": "Nochdaidh tachartasan san loga a chaidh a sguabadh às ann an eachdraidh na duilleige fhathast ach chan fhaic buill a' phobaill cuid dhen t-susbaint aca.",
        "revdelete-text-others": "Gheibh rianairean eile air {{SITENAME}} cothrom air an t-susbaint fhalaichte fhathast agus is urrainn dhaibh an sguabadh às a neo-dhèanamh san dearbh eadar-aghaidh mur an deach cuingeachaidhean a bharrachd a chur orra.",
-       "revdelete-confirm": "Dearbh gu bheil thu airson seo a dhèanamh, gu bheil thu a' tuigsinn na thachras ri linn agus gu bheil thu a' dèanamh seo a-rèir [[{{MediaWiki:Policy-url}}|a' phoileasaidh]].",
+       "revdelete-confirm": "Dearbhaich gu bheil thu airson seo a dhèanamh, gu bheil thu a' tuigsinn na thachras ri linn agus gu bheil thu a' dèanamh seo a-rèir [[{{MediaWiki:Policy-url}}|a' phoileasaidh]].",
        "revdelete-suppress-text": "Cha bu chòir dhut mùchadh a chleachdadh <strong>ach</strong> ann an suidheachaidhean mar seo:\n* Fiosrachadh a dh'fhaodadh a bhith dìteachail\n* Fiosrachadh pearsanta a tha cearr\n*: <em>seòladh taighe, àireamhan fòn, àireamhan NI is msaa.</em>",
        "revdelete-legend": "Suidhich cuingeachaidhean na faicsinneachd",
        "revdelete-hide-text": "Teacsa a' mhùthaidh",
        "datedefault": "Gun roghainnean",
        "prefs-labs": "Feartan nan deuchainn-lannan",
        "prefs-user-pages": "Duilleagan a' chleachdaiche",
-       "prefs-personal": "Pròifil a' chleachdaiche",
+       "prefs-personal": "Pròifil",
        "prefs-rc": "Mùthaidhean ùra",
        "prefs-watchlist": "An clàr-faire",
        "prefs-watchlist-days": "Co mheud latha a sheallar air a' chlàr-fhaire:",
        "prefs-rendering": "Coltas",
        "saveprefs": "Sàbhail",
        "restoreprefs": "Aisig na roghainnean bunaiteach uile (anns gach earrann)",
-       "prefs-editing": "A' deasachadh",
+       "prefs-editing": "Deasachadh",
        "rows": "Sreathan",
        "columns": "Colbhan",
        "searchresultshead": "Lorg",
        "prefs-memberingroups-type": "$1",
        "prefs-registration": "Àm clàraidh:",
        "prefs-registration-date-time": "$1",
-       "yourrealname": "An dearbh ainm a th' ort:",
+       "yourrealname": "D' fhìor-ainm:",
        "yourlanguage": "Cànan:",
        "yourvariant": "Eug-samhail cànan na susbaint:",
        "prefs-help-variant": "Do roghainn eug-samhail sgrìobhaidh a thèid duilleagan na h-uicipeid seo a shealltainn innte.",
        "prefs-help-signature": "Bu chòir dhut d' ainm a chur ri beachdan air duilleagan deasbaireachd le \"<nowiki>~~~~</nowiki>\" agus chithear d' ainm agus stampa ama 'na àite an uairsin.",
        "badsig": "Tha co-chàradh an t-soidhnidh mì-dhligheach.\nThoir sùil air na tagaichean HTML.",
        "badsiglength": "Tha an t-earr-sgrìobhadh agad ro fhada.\nChan fhaod e a bhith nas fhaide na $1 {{PLURAL:$1|charactar|charactar|caractaran|caractar}}.",
-       "yourgender": "Dè a' ghnè a tha annad:",
+       "yourgender": "Do ghnè:",
        "gender-unknown": "B' fhearr leam gun a bhith 'ga leigeil ris",
        "gender-male": "Deasaichidh e duilleagan na h-uicidh",
        "gender-female": "Deasaichidh i duilleagan na h-Uicipeid",
        "recentchangeslinked-feed": "Mùthaidhean buntainneach",
        "recentchangeslinked-toolbox": "Mùthaidhean buntainneach",
        "recentchangeslinked-title": "Mùthaidhean co-cheangailte ri \"$1\"",
-       "recentchangeslinked-summary": "Seo liosta nam mùthaidhean a chaidh a chur air duilleagan a tha a' ceangal o dhuilleag shònraichte (no ri buill ann an roinn-seòrsa sònraichte).\nTha duilleagan air [[Special:Watchlist|do chlàr-faire]] ann an litrichean <strong>troma</strong>.",
+       "recentchangeslinked-summary": "Seo liosta nam mùthaidhean a chaidh a chur air duilleagan a tha a' ceangal o dhuilleag shònraichte (no ri buill ann an roinn-seòrsa sònraichte).\nTha duilleagan air a' [[Special:Watchlist|chlàr-fhaire]] agad ann an litrichean <strong>troma</strong>.",
        "recentchangeslinked-page": "Ainm na duilleige:",
        "recentchangeslinked-to": "Seall mùthaidhean nan duilleagan a tha a' ceangal ris an duilleag sin 'na àite",
        "upload": "Luchdaich suas faidhle",
        "allpagesto": "Seall duilleagan a tha a' crìochnachadh aig:",
        "allarticles": "A h-uile duilleag",
        "allinnamespace": "A h-uile duilleag (ainm-spàs $1)",
-       "allpagessubmit": "Rach",
+       "allpagessubmit": "Siuthad",
        "allpagesprefix": "Seall na duilleagan leis an ro-leasachan:",
        "allpagesbadtitle": "Chaidh tiotal duilleige mì-dhligheach a thoirt seachad no bha ro-leasachan eadar-cànain no eadar-uicidh aige.\nFaodaidh gu bheil aon no barrachd charactaran ann nach urrainn dhut a chleachdadh ann an tiotal.",
        "allpages-bad-ns": "Chan eil an t-ainm-spàs \"$1\" aig {{SITENAME}}.",
        "watchlistanontext": "$1 gus nithean air a' chlàr-fhaire agad a shealltainn no a dheasachadh.",
        "watchnologin": "Chan eil thu air logadh a-steach",
        "addwatch": "Cuir air a' chlàr-fhaire",
-       "addedwatchtext": "Chaidh an duilleag \"[[:$1]]\" a chur ri [[Special:Watchlist|do chlàr-faire]].\nNochdaidh mùthaidhean a nithear air an duilleag seo 's air an duilleag deasbaireachd a tha co-cheangailte ris an-seo san àm ri teachd.",
+       "addedwatchtext": "Chaidh an duilleag \"[[:$1]]\" a chur ris a' [[Special:Watchlist|chlàr-fhaire]] agad.\nNochdaidh mùthaidhean a nithear air an duilleag seo 's air an duilleag deasbaireachd a tha co-cheangailte ris an-seo san àm ri teachd.",
        "addedwatchtext-short": "Chaidh an duilleag \"$1\" a chur ris a' chlàr-fhaire agad.",
        "removewatch": "Thoir air falbh on chlàr-fhaire",
-       "removedwatchtext": "Chaidh an duilleag \"[[:$1]]\" a thoirt air falbh o [[Special:Watchlist|do chlàr-faire]].",
+       "removedwatchtext": "Chaidh an duilleag \"[[:$1]]\" a thoirt air falbh on [[Special:Watchlist|chlàr-fhaire]] agad.",
        "removedwatchtext-short": "Chaidh an duilleag \"$1\" a thoirt ait falbh on chlàr-fhaire agad.",
        "watch": "Cum sùil air",
        "watchthispage": "Cum sùil air an duilleag seo",
        "tooltip-preview": "Ro-sheall na mùthaidhean agad; saoil an cleachd thu seo mus sàbhail thu iad?",
        "tooltip-diff": "Seall na mùthaidhean a chuir mi air an teacs",
        "tooltip-compareselectedversions": "Seall an diofar eadar an dà mhùthadh dhen duilleag seo a thagh thu",
-       "tooltip-watch": "Cuir an duilleag seo air do chlàr-faire",
+       "tooltip-watch": "Cuir an duilleag seo ris a' chlàr-fhaire agad",
        "tooltip-watchlistedit-normal-submit": "Thoir tiotalan air falbh",
        "tooltip-watchlistedit-raw-submit": "Ùraich an clàr-faire",
        "tooltip-recreate": "Ath-chruthaich an duilleag seo ged a chaidh a sguabadh às",
        "exif-xresolution": "Dùmhlachd-bhreacaidh chòmhnard",
        "exif-yresolution": "Dùmhlachd-bhreacaidh inghearach",
        "exif-stripoffsets": "Ionad dàta an deilbh",
+       "exif-jpeginterchangeformat": "Frith-àireamh gu JPEG SOI",
        "exif-jpeginterchangeformatlength": "Baidhtichean de dhàta JPEG",
+       "exif-ycbcrcoefficients": "Co-èifeachdan a' mheatraigs atharrachaidh airson an spàs datha",
+       "exif-referenceblackwhite": "Càraid de luachan iomraidh dubh is geal",
        "exif-datetime": "Ceann-là 's àm aig atharrachadh an fhaidhle",
        "exif-imagedescription": "Tiotal an deilbh",
        "exif-make": "Dèanadair a' chamara",
        "exif-copyright": "Seilbheadair na còrach-lethbhreac",
        "exif-exifversion": "Tionndadh de Exif",
        "exif-flashpixversion": "An tionndadh de Flashpix ris an cuirear taic",
+       "exif-colorspace": "Spàs datha",
+       "exif-componentsconfiguration": "Ciall aig gach co-phàirt",
        "exif-compressedbitsperpixel": "Modh dùmhlachd-bhreacaidh an deilbh",
        "exif-pixelydimension": "Leud an deilbh",
        "exif-pixelxdimension": "Àirde an deilbh",
        "exif-relatedsoundfile": "Faidhle fuaime co-cheangailte ris",
        "exif-datetimeoriginal": "Ceann-là 's àm a chaidh an dàta a chruthachadh",
        "exif-datetimedigitized": "Ceann-là 's àm a chaidh cruth digiteach a chur air an dàta",
+       "exif-subsectime": "Fo-dhiogan cinn-là 's ama",
+       "exif-subsectimeoriginal": "Fo-dhiogan cinn-là 's ama thùsail",
+       "exif-subsectimedigitized": "Fo-dhiogan cinn-là 's ama an dreach digitich",
+       "exif-exposuretime": "Ùine deisearais",
        "exif-exposuretime-format": "$1 diog ($2)",
+       "exif-fnumber": "Àireamh F",
+       "exif-fnumber-format": "f/$1",
+       "exif-exposureprogram": "Prògram deisearais",
+       "exif-spectralsensitivity": "Mothalachd speictreach",
+       "exif-isospeedratings": "Rangachadh astar ISO",
+       "exif-shutterspeedvalue": "Luaths siutair APEX",
+       "exif-aperturevalue": "Fosgladh APEX",
+       "exif-brightnessvalue": "Soilleireachd APEX",
+       "exif-exposurebiasvalue": "Claonadh deisearais APEX",
+       "exif-subjectdistance": "Astar a' chuspair",
+       "exif-meteringmode": "Modh meidheachaidh",
+       "exif-lightsource": "Tùs an t-solais",
        "exif-flash": "Solas-boillsgidh",
+       "exif-focallength": "Faid fòcas an lionsa",
        "exif-focallength-format": "$1 mm",
+       "exif-subjectarea": "Raon a' chuspair",
+       "exif-flashenergy": "Lùths an t-solais boillsgidh",
+       "exif-focalplanexresolution": "Dùmhlachd-bhreacaidh X aig plèana an fhòcais",
+       "exif-focalplaneyresolution": "Dùmhlachd-bhreacaidh Y aig plèana an fhòcais",
+       "exif-focalplaneresolutionunit": "Aonad dùmhlachd-breacaidh aig plèana an fhòcais",
+       "exif-subjectlocation": "Ionad a' chuspair",
+       "exif-exposureindex": "Inneacs deisearais",
+       "exif-sensingmethod": "Dòigh a' mhothaicheir",
        "exif-filesource": "Tùs an fhaidhle",
+       "exif-scenetype": "Seòrsa an t-seallaidh",
+       "exif-customrendered": "Pròiseasadh gnàthaichte an deilbh",
+       "exif-exposuremode": "Modh deisearais",
+       "exif-whitebalance": "Meidh na gile",
+       "exif-digitalzoomratio": "Co-mheas an t-sùma dhigitich",
+       "exif-focallengthin35mmfilm": "Faid fòcas an am film 35 mm",
+       "exif-scenecapturetype": "Seòrsa glacaidh-sgrìn",
+       "exif-gaincontrol": "Smachd air an t-seallaidh",
+       "exif-contrast": "Iomsgaradh",
+       "exif-saturation": "Sàthachd",
+       "exif-sharpness": "Geurad",
        "exif-devicesettingdescription": "Tuairisgeul aig roghainnean an uidheim",
+       "exif-subjectdistancerange": "Rainse astar a' chuspair",
+       "exif-imageuniqueid": "ID fa leth an deilbh",
+       "exif-gpsversionid": "Tionndadh dhen taga GPS",
+       "exif-gpslatituderef": "Domhan-leud tuath no deas",
+       "exif-gpslatitude": "Domhan-leud",
+       "exif-gpslongituderef": "Domhan-fhad ear no siar",
+       "exif-gpslongitude": "Domhan-fhad",
+       "exif-gpsaltituderef": "Iomradh na h-àirde",
+       "exif-gpsaltitude": "Àirde",
+       "exif-gpstimestamp": "Àm GPS (uaireadair atomach)",
+       "exif-gpssatellites": "Saidealan a chaidh a chleachdadh airson an tomhais",
+       "exif-gpsstatus": "Staid a' ghlacadair",
+       "exif-gpsmeasuremode": "Modh an tomhais",
+       "exif-gpsdop": "Pongalachd an tomhais",
+       "exif-gpsspeedref": "Aonad an luaiths",
+       "exif-gpsspeed": "Luaths a' ghlacadair GPS",
+       "exif-gpstrackref": "Iomradh airson comhair a' ghluasaid",
+       "exif-gpstrack": "Comhair a' ghluasaid",
+       "exif-gpsimgdirectionref": "Iomradh airson comhair an deilbh",
+       "exif-gpsimgdirection": "Comhair an deilbh",
+       "exif-gpsdestlatituderef": "Iomradh airson domhan-leud a' chinn-uidhe",
+       "exif-gpsdestlatitude": "Domhan-leud a' chinn-uidhe",
+       "exif-gpsdestlongituderef": "Iomradh airson domhan-fhad a' chinn-uidhe",
+       "exif-gpsdestlongitude": "Domhan-fhad a' chinn-uidhe",
+       "exif-gpsdestbearingref": "Iomradh airson comhair a' chinn-uidhe",
+       "exif-gpsdestbearing": "Comhair a' chinn-uidhe",
+       "exif-gpsdestdistanceref": "Iomradh airson astar on cheann-uidhe",
+       "exif-gpsdestdistance": "Astar on cheann-uidhe",
+       "exif-gpsprocessingmethod": "Ainm air modh pròiseasadh GPS",
+       "exif-gpsareainformation": "Ainm raon GPS",
+       "exif-gpsdatestamp": "Ceann-là GPS",
+       "exif-gpsdifferential": "Ceartachadh diofarail GPS",
+       "exif-coordinate-format": "$1° $2′ $3″ $4",
+       "exif-jpegfilecomment": "Beachd faidhle JPEG",
+       "exif-keywords": "Facalan-luirg",
+       "exif-worldregioncreated": "An roinn-dùthcha san deach an dealbh a thogail",
+       "exif-countrycreated": "An dùthaich san deach an dealbh a thogail",
+       "exif-countrycodecreated": "Còd na dùthcha san deach an dealbh a thogail",
+       "exif-provinceorstatecreated": "An t-siorrachd no còigeamh san deach an dealbh a thogail",
+       "exif-citycreated": "Am baile san deach an dealbh a thogail",
+       "exif-sublocationcreated": "An t-ionad sa bhaile san deach an dealbh a thogail",
+       "exif-worldregiondest": "Tha an roinn-dùthcha 'ga sealltainn",
+       "exif-countrydest": "Tha an dùthaich 'ga sealltainn",
+       "exif-countrycodedest": "Tha còd na dùthcha air 'ga sealltainn",
+       "exif-provinceorstatedest": "Tha an t-siorrachd no còigeamh 'ga sealltainn",
+       "exif-citydest": "Tha am baile 'ga shealltainn",
+       "exif-sublocationdest": "Tha an t-ionad sa bhaile 'ga shealltainn",
        "exif-objectname": "Tiotal goirid",
        "exif-specialinstructions": "Stiùireadh sònraichte",
        "exif-headline": "Ceann-sgrìobhadh",
        "exif-credit": "Cliù/Solaraiche",
        "exif-source": "Tùs",
        "exif-editstatus": "Staid deasachaidh an deilbh",
+       "exif-urgency": "Èiginneachd",
+       "exif-fixtureidentifier": "Ainm nì shocraichte",
+       "exif-locationdest": "An t-ionad san dealbh",
+       "exif-locationdestcode": "Còs an ionaid san dealbh",
+       "exif-objectcycle": "Àm an latha iomchaidh airson a' mheadhain",
        "exif-contact": "Fiosrachadh conaltraidh",
        "exif-writer": "Sgrìobhadair",
        "exif-languagecode": "Cànan",
+       "exif-iimversion": "Tionndadh de IIM",
        "exif-iimcategory": "Roinn-seòrsa",
        "exif-iimsupplementalcategory": "Roinnean-seòrsa foirlionach",
        "exif-datetimeexpires": "Na cleachd às dèidh",
        "exif-datetimereleased": "'Ga sgaoileadh o",
+       "exif-originaltransmissionref": "Còd ionaid tùsail an tar-chuir",
        "exif-identifier": "Aithnichear",
+       "exif-lens": "An lionsa a chaidh a chleachdadh",
+       "exif-serialnumber": "Àireamh shreathach a' chamara",
        "exif-cameraownername": "Seilbheadair a' chamara",
        "exif-label": "Leubail",
+       "exif-datetimemetadata": "An ceann-là a chaidh am meata-dàta atharrachadh an turas mu dheireadh",
        "exif-nickname": "Ainm neo-fhoirmeil an deilbh",
        "exif-rating": "Rangachadh (a-mach à 5)",
+       "exif-rightscertificate": "Teisteanas rianachd chòraichean",
        "exif-copyrighted": "Staid na còrach-lethbhreac",
        "exif-copyrightowner": "Seilbheadair na còrach-lethbhreac",
        "exif-usageterms": "Teirmichean a' chleachdaidh",
        "exif-contentwarning": "Rabhadh susbainte",
        "exif-giffilecomment": "Beachd faidhle GIF",
        "exif-intellectualgenre": "Seòrsa na susbainte",
+       "exif-subjectnewscode": "Còd a' chuspair",
+       "exif-scenecode": "Còd seallaidh IPTC",
        "exif-event": "Tachartas san dealbh",
        "exif-organisationinimage": "Buidheann san dealbh",
        "exif-personinimage": "Neach sa dealbh",
        "exif-contact-value": "$1\n\n$2\n<div class=\"adr\">\n$3\n\n$4, $5, $6 $7\n</div>\n$8",
        "exif-subjectnewscode-value": "$2 ($1)",
        "exif-compression-1": "Gun dùmhlachadh",
+       "exif-compression-3": "Còdachadh facs CCITT Group 3",
+       "exif-compression-4": "Còdachadh facs CCITT Group 4",
        "exif-compression-5": "LZW",
        "exif-compression-6": "JPEG (sean)",
        "exif-compression-7": "JPEG",
        "exif-exposureprogram-0": "Gun mhìneachadh",
        "exif-exposureprogram-1": "A làimh",
        "exif-exposureprogram-2": "Prògram àbhaisteach",
+       "exif-exposureprogram-3": "Prìomhachas fosglaidh",
+       "exif-exposureprogram-4": "Prìomhachas siutair",
+       "exif-exposureprogram-5": "Prògram cruthachail (le claonadh gu doimhne an raoin)",
+       "exif-exposureprogram-6": "Prògram gluasaid (le claonadh gu siutair luath)",
+       "exif-exposureprogram-7": "Modh portraid (airson dealbhan faisg gun fhòcas air a' chùlaibh)",
+       "exif-exposureprogram-8": "Modh crutha-tìre (airson dealbhan crutha-tìre le fòcas air a' chùlaibh)",
        "exif-subjectdistance-value": "$1 {{PLURAL:$1|mheatair|mheatair|meatairean|meatair}}",
        "exif-meteringmode-0": "Chan eil fhios",
        "exif-meteringmode-1": "Cuibheasach",
+       "exif-meteringmode-2": "Cuibheas le cuideam sa bheadhan",
+       "exif-meteringmode-3": "Spot",
+       "exif-meteringmode-4": "Iomadh-spot",
+       "exif-meteringmode-5": "Pàtran",
+       "exif-meteringmode-6": "Leth-phàirteach",
        "exif-meteringmode-255": "Eile",
        "exif-lightsource-0": "Chan eil fhios",
+       "exif-lightsource-1": "Eile",
+       "exif-lightsource-2": "Fluaraiseach",
+       "exif-lightsource-3": "Tungstan (solas-dealain)",
        "exif-lightsource-4": "Solas-boillsgidh",
+       "exif-lightsource-9": "Deagh shìde",
+       "exif-lightsource-10": "Sìde neulach",
+       "exif-lightsource-11": "Sgàil",
+       "exif-lightsource-12": "Fluaraiseach solas an latha (D 5700 – 7100K)",
+       "exif-lightsource-13": "Fluaraiseach geal an latha (N 4600 – 5400K)",
+       "exif-lightsource-14": "Fluaraiseach geal fuair (W 3900 – 4500K)",
+       "exif-lightsource-15": "Fluaraiseach geal (WW 3200 – 3700K)",
+       "exif-lightsource-17": "Solas stannardach A",
+       "exif-lightsource-18": "Solas stannardach B",
+       "exif-lightsource-19": "Solas stannardach C",
        "exif-lightsource-20": "D55",
        "exif-lightsource-21": "D65",
        "exif-lightsource-22": "D75",
        "exif-lightsource-23": "D50",
-       "exif-flash-mode-2": "bacadh riatanach air an t-solas-boillsgidh",
+       "exif-lightsource-24": "Tungstan stiùideo ISO",
+       "exif-lightsource-255": "Tùs solais eile",
+       "exif-flash-fired-0": "Cha deach an solas-boillsgidh air",
+       "exif-flash-fired-1": "Chaidh an solas-boillsgidh air",
+       "exif-flash-return-0": "gun fhoincsean mothachaidh airson an t-solais-bhoillsgidh",
+       "exif-flash-return-2": "cha deach solas-boillsgidh a mhothachadh",
+       "exif-flash-return-3": "chaidh solas-boillsgidh a mhothachadh",
+       "exif-flash-mode-1": "solas-boillsgidh riatanach",
+       "exif-flash-mode-2": "bacadh riatanach air an t-solas-bhoillsgidh",
        "exif-flash-mode-3": "modh fèin-obrachail",
+       "exif-flash-function-1": "Gun solas-boillsgidh",
+       "exif-flash-redeye-1": "modh lùghdachadh nan sùilean dearga",
        "exif-focalplaneresolutionunit-2": "òirleach",
        "exif-sensingmethod-1": "Gun mhìneachadh",
+       "exif-sensingmethod-2": "Mothaichear raon datha aon-sgeilbe",
+       "exif-sensingmethod-3": "Mothaichear raon datha dà-sgeilbe",
+       "exif-sensingmethod-4": "Mothaichear raon datha trì-sgeilbe",
+       "exif-sensingmethod-5": "Mothaichear raon datha sreathach",
+       "exif-sensingmethod-7": "Mothaichear trì-loidhneach",
+       "exif-sensingmethod-8": "Mothaichear datha sreathach loidhneach",
+       "exif-filesource-3": "Camara dhealbhan digiteach",
+       "exif-scenetype-1": "Dealbh a chaidh a thogail gu dìreach",
+       "exif-customrendered-0": "Pròiseas àbhaisteach",
+       "exif-customrendered-1": "Pròiseas gnàthaichte",
+       "exif-exposuremode-0": "Deisearas fèin-obrachail",
+       "exif-exposuremode-1": "Deisearas a làimh",
+       "exif-exposuremode-2": "Bracaid fèin-obrachail",
+       "exif-whitebalance-0": "Meidh na gile fèin-obrachail",
+       "exif-whitebalance-1": "Meidh na gile a làimh",
+       "exif-scenecapturetype-0": "Stannardach",
        "exif-scenecapturetype-1": "Dreach-tìre",
        "exif-scenecapturetype-2": "Portraid",
+       "exif-scenecapturetype-3": "Sealladh oidhche",
        "exif-gaincontrol-0": "Chan eil gin",
+       "exif-gaincontrol-1": "Buannachd ìosal suas",
+       "exif-gaincontrol-2": "Buannachd àrd suas",
+       "exif-gaincontrol-3": "Buannachd ìosal sìos",
+       "exif-gaincontrol-4": "Buannachd àrd sìos",
+       "exif-contrast-0": "Àbhaisteach",
+       "exif-contrast-1": "Lag",
+       "exif-contrast-2": "Cruaidh",
+       "exif-saturation-0": "Àbhaisteach",
+       "exif-saturation-1": "Sàthachd ìosal",
+       "exif-saturation-2": "Sàthachd àrd",
+       "exif-sharpness-0": "Àbhaisteach",
+       "exif-sharpness-1": "Lag",
+       "exif-sharpness-2": "Cruaidh",
+       "exif-subjectdistancerange-0": "Chan eil fios",
+       "exif-subjectdistancerange-1": "Macro",
+       "exif-subjectdistancerange-2": "Sealladh dlùth",
+       "exif-subjectdistancerange-3": "Sealladh aig astar",
+       "exif-gpslatitude-n": "Domhan-leud tuath",
+       "exif-gpslatitude-s": "Domhan-leud deas",
+       "exif-gpslongitude-e": "Domhan-fhad ear",
+       "exif-gpslongitude-w": "Domhan-fhad siar",
+       "exif-gpsaltitude-above-sealevel": "$1 {{PLURAL:$1|mheatair|mheatair|meatairean|meatair}} os cionn àirde na mara",
+       "exif-gpsaltitude-below-sealevel": "$1 {{PLURAL:$1|mheatair|mheatair|meatairean|meatair}} fo àirde na mara",
+       "exif-gpsstatus-a": "'Ga thomhas",
+       "exif-gpsstatus-v": "Comas eadar-obrachadh an tomhais",
+       "exif-gpsmeasuremode-2": "Tomhas air 2 dhimeinsean",
+       "exif-gpsmeasuremode-3": "Tomhas air 3 dimeinseanan",
        "exif-gpsspeed-k": "Cilemeatair san uair",
        "exif-gpsspeed-m": "Mìle gach uair",
        "exif-gpsspeed-n": "Mìle-mara san uair",
        "exif-gpsdestdistance-k": "Cilemeatair",
        "exif-gpsdestdistance-m": "Mìle",
        "exif-gpsdestdistance-n": "Mìle-mara",
+       "exif-gpsdop-excellent": "Sgoinneil ($1)",
+       "exif-gpsdop-good": "Math ($1)",
+       "exif-gpsdop-moderate": "Meadhanach ($1)",
+       "exif-gpsdop-fair": "Ceart gu leòr ($1)",
+       "exif-gpsdop-poor": "Dona ($1)",
+       "exif-objectcycle-a": "Sa madainn a-mhàin",
+       "exif-objectcycle-p": "Feasgar a-mhàin",
+       "exif-objectcycle-b": "An dà chuid sa mhadainn 's feasgar",
+       "exif-gpsdirection-t": "Fìor-chomhair",
+       "exif-gpsdirection-m": "Comhair mhagnaiteach",
+       "exif-ycbcrpositioning-1": "Meadhanaichte",
        "exif-dc-contributor": "Deasaichean",
+       "exif-dc-coverage": "Sgòp na h-aite no ama aig a' mheadhan",
        "exif-dc-date": "Ceann-là",
        "exif-dc-publisher": "Foillsichear",
        "exif-dc-relation": "Meadhanan co-cheangailte",
        "exif-rating-rejected": "Air a dhiùltadh",
        "exif-isospeedratings-overflow": "Nas motha na 65535",
        "exif-maxaperturevalue-value": "$1 APEX (f/$2)",
+       "exif-iimcategory-ace": "Na h-ealain, cultar 's dibhearsan",
+       "exif-iimcategory-clj": "Eucoir 's lagha",
+       "exif-iimcategory-dis": "Dunaidh 's tubhaistean",
+       "exif-iimcategory-fin": "Eaconamaidh 's gnìomhachas",
+       "exif-iimcategory-edu": "Foghlam",
+       "exif-iimcategory-evn": "An àrainneachd",
+       "exif-iimcategory-hth": "Slàinte",
+       "exif-iimcategory-hum": "Daoine",
+       "exif-iimcategory-lab": "Obair",
+       "exif-iimcategory-lif": "Dòigh-bheatha 's cur-seachad",
+       "exif-iimcategory-pol": "Polataigs",
+       "exif-iimcategory-rel": "Creideamh",
+       "exif-iimcategory-sci": "Saidheans 's teicneolas",
+       "exif-iimcategory-soi": "Cuspairean sòisealta",
+       "exif-iimcategory-spo": "Spòrs",
+       "exif-iimcategory-war": "Cogadh, còmhstri 's aramach",
+       "exif-iimcategory-wea": "Aimsir",
+       "exif-urgency-normal": "Àbhaisteach ($1)",
+       "exif-urgency-low": "Ìosal ($1)",
+       "exif-urgency-high": "Àrd ($1)",
+       "exif-urgency-other": "Prìomhachas gnàthaiche ($1)",
        "watchlistall2": "na h-uile",
        "namespacesall": "na h-uile",
        "monthsall": "na h-uile",
-       "confirmemail": "Dearbh an seòladh puist-dhealain",
+       "confirmemail": "Dearbhaich an seòladh puist-dhealain",
        "confirmemail_noemail": "Cha dug thu seachad seòladh puist-d dligheach ann an [[Special:Preferences|roghainnean a' chleachdaiche]] agad.",
-       "confirmemail_text": "Iarraidh {{SITENAME}} ort gun dearbh thu an seòladh puist-d agad mus cleachd thu feartan puist-d.\nCleachd am putan gu h-ìosal gus post-d dearbhaidh a chur dhan t-seòladh agad.\nBidh ceangal le còd sa phost-d ud;\nluchdaich an ceangal sa bhrabhsair agad airson dearbhadh gu bheil an seòladh puist-d agad dligheach.",
+       "confirmemail_text": "Iarraidh {{SITENAME}} ort gun dearbhaich thu an seòladh puist-d agad mus cleachd thu feartan puist-d.\nCleachd am putan gu h-ìosal gus post-d dearbhaidh a chur dhan t-seòladh agad.\nBidh ceangal le còd sa phost-d ud;\nluchdaich an ceangal sa bhrabhsair agad airson dearbhadh gu bheil an seòladh puist-d agad dligheach.",
        "confirmemail_pending": "Chaidh còd dearbhaidh a chur thugad air a' phost-d mar-thà;\nma tha thu air a' chunntas agad a chruthachadh o chionn goirid, 's math dh'fhaoidte gum b' feairrde thu feitheamh mionaid no dhà ach an ruig e thu mus iarr thu còd ùr.",
        "confirmemail_send": "Cuir còd dearbhaidh thugam",
        "confirmemail_sent": "Chaidh post-d dearbhaidh a chur.",
        "feedback-error3": "Mearachd: Cha d' fhuair sinn freagairt on API",
        "feedback-thanks": "Mòran taing! Chaidh do bheachd a phostadh air an duilleag \"[$2 $1]\".",
        "feedback-close": "Dèanta",
-       "feedback-bugcheck": "Taghta! Dearbh nach eil e air [$1 liosta nam bugaichean air a bheil sinn eòlach] mar-thà.",
+       "feedback-bugcheck": "Taghta! Dearbhaich nach eil e air [$1 liosta nam bugaichean air a bheil sinn eòlach] mar-thà.",
        "feedback-bugnew": "Dhearbh mi seo. Dèan aithris air buga ur",
        "searchsuggest-search": "Lorg",
        "searchsuggest-containing": "anns a bheil...",
index d72e97a..bf20771 100644 (file)
        "talkpagelinktext": "Conversa",
        "specialpage": "Páxina especial",
        "personaltools": "Ferramentas persoais",
-       "postcomment": "Nova sección",
        "articlepage": "Ver a páxina de contido",
        "talk": "Conversa",
        "views": "Vistas",
        "externaldberror": "Ou ben se produciu un erro da base de datos na autenticación externa ou ben non se lle permite actualizar a súa conta externa.",
        "login": "Acceder ao sistema",
        "nav-login-createaccount": "Rexistro",
-       "loginprompt": "Debe habilitar as cookies para acceder a {{SITENAME}}.",
        "userlogin": "Rexistro",
        "userloginnocreate": "Rexistro",
        "logout": "Saír ao anonimato",
        "revdelete-text-text": "As revisións borradas seguirán aparecendo no historial da páxina, pero partes do seu contido serán inaccesibles para o público.",
        "revdelete-text-file": "As revisións borradas do ficheiro seguirán aparecendo no historial do ficheiro, pero partes do seu contido serán inaccesibles para o público.",
        "logdelete-text": "Os rexistros de eventos borrados seguirán aparecendo nos rexistros, pero partes do seu contido serán inaccesibles para o público.",
-       "revdelete-text-others": "Os outros administradores de {{SITENAME}} seguirán tendo acceso aos contidos agochados e poderán restauralos a través desta mesma interface, a menos que se definan restricións adicionais.",
+       "revdelete-text-others": "Os outros administradores seguirán tendo acceso aos contidos agochados e poderán restauralos, a menos que se definan restricións adicionais.",
        "revdelete-confirm": "Por favor, confirme que quere levar a cabo esta acción, que comprende as consecuencias e que o fai de acordo [[{{MediaWiki:Policy-url}}|coas políticas]].",
        "revdelete-suppress-text": "A eliminación '''unicamente''' debería utilizarse nos seguintes casos:\n* Información potencialmente difamatoria\n* Información persoal inapropiada\n*: ''domicilios e números de teléfono, números da seguridade social etc.''",
        "revdelete-legend": "Aplicar restricións de visibilidade",
        "revdelete-offender": "Autor da revisión:",
        "suppressionlog": "Rexistro de supresións",
        "suppressionlogtext": "A continuación móstrase unha lista coas eliminacións e cos bloqueos recentes, que inclúen contido oculto dos administradores.\nOlle a [[Special:BlockList|lista de bloqueos]] para comprobar os bloqueos vixentes.",
-       "mergehistory": "Fusionar os historiais das páxinas",
-       "mergehistory-header": "Esta páxina permítelle fusionar revisións dos historiais da páxina de orixe nunha nova páxina.\nAsegúrese de que esta modificación da páxina mantén a continuidade histórica.",
+       "mergehistory": "Fusionar os historiais de páxinas",
+       "mergehistory-header": "Esta páxina permítelle fusionar as revisións dos historiais da páxina de orixe nunha nova páxina.\nAsegúrese de que esta modificación mantén a continuidade histórica da páxina.",
        "mergehistory-box": "Fusionar as revisións de dúas páxinas:",
        "mergehistory-from": "Páxina de orixe:",
        "mergehistory-into": "Páxina de destino:",
-       "mergehistory-list": "Historial de edicións fusionables",
-       "mergehistory-merge": "As revisións seguintes de [[:$1]] pódense fusionar con [[:$2]]. Use a columna de botóns de selección para fusionar só as revisións creadasen e antes da hora indicada. Teña en conta que se usa as ligazóns de navegación a columna limparase.",
+       "mergehistory-list": "Historial de edicións que se pode fusionar",
+       "mergehistory-merge": "As seguintes revisións de \"[[:$1]]\" pódense fusionar con \"[[:$2]]\".\nUtilice a columna de caixas de selección para fusionar só as revisións creadas ata a hora indicada, esta incluída.\nTeña en conta que o uso das ligazóns de navegación ha borrar a selección da columna.",
        "mergehistory-go": "Mostrar as edicións que se poden fusionar",
        "mergehistory-submit": "Fusionar as revisións",
        "mergehistory-empty": "Non hai revisións que se poidan fusionar.",
-       "mergehistory-success": "{{PLURAL:$3|Unha revisión|$3 revisións}} de [[:$1]] {{PLURAL:$3|fusionouse|fusionáronse}} sen problemas en [[:$2]].",
-       "mergehistory-fail": "Non se puido fusionar o historial; comprobe outra vez os parámetros de páxina e hora.",
+       "mergehistory-success": "{{PLURAL:$3|Unha revisión|$3 revisións}} de \"[[:$1]]\" {{PLURAL:$3|fusionouse|fusionáronse}} sen problemas con \"[[:$2]]\".",
+       "mergehistory-fail": "Non se puido fusionar o historial; comprobe outra vez os parámetros de páxina e data.",
+       "mergehistory-fail-toobig": "Non se puido fusionar o historial, xa que supón trasladar máis revisións que o límite de $1 {{PLURAL:$1|revisión|revisións}}.",
        "mergehistory-no-source": "Non existe a páxina de orixe \"$1\".",
        "mergehistory-no-destination": "Non existe a páxina de destino \"$1\".",
        "mergehistory-invalid-source": "A páxina de orixe ten que ter un título válido.",
        "mergehistory-invalid-destination": "A páxina de destino ten que ter un título válido.",
-       "mergehistory-autocomment": "\"[[:$1]]\" fusionouse en \"[[:$2]]\"",
-       "mergehistory-comment": "\"[[:$1]]\" fusionouse en \"[[:$2]]\": $3",
-       "mergehistory-same-destination": "A orixe das páxinas e o seu destino non poden ser os mesmos",
+       "mergehistory-autocomment": "\"[[:$1]]\" fusionouse con \"[[:$2]]\"",
+       "mergehistory-comment": "\"[[:$1]]\" fusionouse con \"[[:$2]]\": $3",
+       "mergehistory-same-destination": "A páxina de orixe e a páxina de destino non pode ser a mesma",
        "mergehistory-reason": "Motivo:",
        "mergelog": "Rexistro de fusións",
-       "pagemerge-logentry": "fusionou \"[[$1]]\" con \"[[$2]]\" (revisións até o $3)",
+       "pagemerge-logentry": "fusionou \"[[$1]]\" con \"[[$2]]\" (revisións ata o $3)",
        "revertmerge": "Desfacer a fusión",
        "mergelogpagetext": "A continuación hai unha lista coas fusións máis recentes do historial dunha páxina co doutra.",
        "history-title": "Historial de revisións de \"$1\"",
        "right-deletedtext": "Ver texto borrado e cambios entre revisións eliminadas",
        "right-browsearchive": "Procurar páxinas borradas",
        "right-undelete": "Restaurar unha páxina",
-       "right-suppressrevision": "Revisar e restaurar as revisións agochadas dos administradores",
+       "right-suppressrevision": "Revisar, agochar e restaurar revisións específicas de páxinas de calquera usuario",
+       "right-viewsuppressed": "Ver revisións agochadas por calquera usuario",
        "right-suppressionlog": "Ver rexistros privados",
        "right-block": "Bloquear outros usuarios fronte á edición",
        "right-blockemail": "Bloquear un usuario fronte ao envío dun correo electrónico",
        "largefileserver": "Este ficheiro é de maior tamaño ca o permitido pola configuración do servidor.",
        "emptyfile": "O ficheiro que cargou semella estar baleiro.\nIsto pode deberse a un erro ortográfico no seu nome.\nPor favor, verifique se realmente quere cargar este ficheiro.",
        "windows-nonascii-filename": "Este wiki non soporta os nomes de ficheiros con caracteres especiais.",
-       "fileexists": "Xa existe un ficheiro con ese nome. Por favor, comprobe \"<strong>[[:$1]]</strong>\" se non está seguro de querer cambialo.\n[[$1|thumb]]",
+       "fileexists": "Xa existe un ficheiro con ese nome. Por favor, comprobe \"<strong>[[:$1]]</strong>\" se non está {{GENDER:|seguro|segura}} de querer cambialo.\n[[$1|thumb]]",
        "filepageexists": "A páxina de descrición deste ficheiro xa foi creada en <strong>[[:$1]]</strong>, pero polo de agora non existe ningún ficheiro con este nome.\nO resumo que escribiu non aparecerá na páxina de descrición.\nPara facer que o resumo apareza alí, necesitará editar a páxina manualmente.\n[[$1|thumb]]",
        "fileexists-extension": "Xa existe un ficheiro cun nome semellante: [[$2|thumb]]\n* Nome do ficheiro que intenta cargar: <strong>[[:$1]]</strong>\n* Nome de ficheiro existente: <strong>[[:$2]]</strong>\nPor favor, escolla un nome diferente.",
        "fileexists-thumbnail-yes": "Semella que o ficheiro é unha imaxe de tamaño reducido ''(miniatura)''.\n[[$1|thumb]]\nPor favor, comprobe o ficheiro <strong>[[:$1]]</strong>.\nSe o ficheiro seleccionado é a mesma imaxe en tamaño orixinal non é preciso enviar unha miniatura adicional.",
        "license": "Licenza:",
        "license-header": "Licenza",
        "nolicense": "Ningunha seleccionada",
+       "licenses-edit": "Editar as opcións de licenza",
        "license-nopreview": "(A vista previa non está dispoñible)",
        "upload_source_url": "  (un URL válido e accesible publicamente)",
        "upload_source_file": "  (un ficheiro no seu ordenador)",
+       "listfiles-delete": "borrar",
        "listfiles-summary": "Esta páxina especial mostra todos os ficheiros cargados.",
        "listfiles_search_for": "Buscar polo nome do ficheiro multimedia:",
        "imgfile": "ficheiro",
        "filedelete-maintenance": "Os borrados e restauracións de ficheiros están desactivados temporalmente durante o mantemento.",
        "filedelete-maintenance-title": "Non se pode borrar o ficheiro",
        "mimesearch": "Busca MIME",
-       "mimesearch-summary": "Esta páxina permite filtrar os ficheiros segundo o seu tipo MIME.\nEntrada: tipodecontido/subtipo, por exemplo <code>image/jpeg</code>.",
+       "mimesearch-summary": "Esta páxina permite filtrar os ficheiros segundo o seu tipo MIME.\nEntrada: tipodecontido/subtipo ou tipodecontido/*; por exemplo, <code>image/jpeg</code>.",
        "mimetype": "Tipo MIME:",
        "download": "descargar",
        "unwatchedpages": "Páxinas non vixiadas",
        "wantedpages-badtitle": "Título inválido fixado nos resultados: $1",
        "wantedfiles": "Ficheiros requiridos",
        "wantedfiletext-cat": "Os seguintes ficheiros están en uso, pero non existen. É posible que aparezan ficheiros de repositoroios externos, malia que existan. Calquera falso positivo estará <del>riscado</del>. Ademais, as páxinas que inclúen ficheiros que non existen están listadas en [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Os seguintes ficheiros están en uso, pero non existen. Ademais, as páxinas que inclúen ficheiros que non existen están listadas en [[:$1]].",
        "wantedfiletext-nocat": "Os seguintes ficheiros están en uso, pero non existen. É posible que aparezan ficheiros de repositoroios externos, malia que existan. Calquera falso positivo estará <del>riscado</del>.",
+       "wantedfiletext-nocat-noforeign": "Os seguintes ficheiros están en uso, pero non existen.",
        "wantedtemplates": "Modelos requiridos",
        "mostlinked": "Páxinas máis ligadas",
        "mostlinkedcategories": "Categorías máis ligadas",
-       "mostlinkedtemplates": "Modelos máis ligados",
+       "mostlinkedtemplates": "Modelos máis transcluídos",
        "mostcategories": "Páxinas con máis categorías",
        "mostimages": "Ficheiros máis usados",
        "mostinterwikis": "Páxinas con máis interwikis",
        "markedaspatrollederror-noautopatrol": "Non está permitido que un mesmo marque as propias edicións como revisadas.",
        "markedaspatrollednotify": "A modificación feita en \"$1\" marcouse como revisada.",
        "markedaspatrollederrornotify": "Erro ao marcar como revisada.",
-       "patrol-log-page": "Rexistro de revisións",
+       "patrol-log-page": "Rexistro de revisións patrulladas",
        "patrol-log-header": "Este é un rexistro das revisións patrulladas.",
        "log-show-hide-patrol": "$1 o rexistro de patrullas",
        "deletedrevision": "A revisión vella $1 foi borrada.",
        "watchlisttools-raw": "Editar a lista de vixilancia simple",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|conversa]])",
        "unknown_extension_tag": "Etiqueta de extensión descoñecida \"$1\"",
-       "duplicate-defaultsort": "'''Aviso:''' A clave de ordenación por defecto \"$2\" anula a clave de ordenación anterior por defecto \"$1\".",
+       "duplicate-defaultsort": "<strong>Aviso:</strong> A clave de ordenación por defecto \"$2\" anula a clave de ordenación anterior por defecto \"$1\".",
+       "duplicate-displaytitle": "'''Aviso:''' O título mostrado \"$2\" anula o título anterior \"$1\".",
        "version": "Versión",
        "version-extensions": "Extensións instaladas",
+       "version-skins": "Aparencias instaladas",
        "version-specialpages": "Páxinas especiais",
        "version-parserhooks": "Asociadores analíticos",
        "version-variables": "Variables",
        "version-antispam": "Prevención contra spam",
-       "version-skins": "Aparencias",
        "version-other": "Outros",
        "version-mediahandlers": "Executadores de multimedia",
        "version-hooks": "Asociadores",
        "version-hook-name": "Nome do asociador",
        "version-hook-subscribedby": "Subscrito por",
        "version-version": "($1)",
+       "version-no-ext-name": "[sen nome]",
        "version-license": "Licenza de MediaWiki",
        "version-ext-license": "Licenza",
        "version-ext-colheader-name": "Extensión",
+       "version-skin-colheader-name": "Aparencia",
        "version-ext-colheader-version": "Versión",
        "version-ext-colheader-license": "Licenza",
        "version-ext-colheader-description": "Descrición",
        "expand_templates_remove_nowiki": "Suprimir as etiquetas <nowiki> no resultado",
        "expand_templates_generate_xml": "Mostrar as árbores de análise XML",
        "expand_templates_generate_rawhtml": "Mostrar o HTML en bruto",
-       "expand_templates_preview": "Vista previa"
+       "expand_templates_preview": "Vista previa",
+       "pagelanguage": "Selector de lingua da páxina",
+       "pagelang-name": "Páxina",
+       "pagelang-language": "Lingua",
+       "pagelang-use-default": "Utilizar a lingua por defecto",
+       "pagelang-select-lang": "Seleccionar a lingua",
+       "right-pagelang": "Cambiar a lingua da páxina",
+       "action-pagelang": "cambiar a lingua da páxina",
+       "log-name-pagelang": "Rexistro de cambios de lingua",
+       "log-description-pagelang": "Este é un rexistro dos cambios na lingua das páxinas.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|cambiou}} a lingua da páxina \"$3\" do $4 ao $5."
 }
index d47eab5..579df7a 100644 (file)
        "permalink": "Bschtändigi URL",
        "print": "Drucke",
        "view": "Aaluege",
+       "view-foreign": "Uf $1 aaluege",
        "edit": "Ändere",
+       "edit-local": "Lokali Bschrybig bearbeite",
        "create": "Erstelle",
+       "create-local": "Lokali Bschrybig zuefiege",
        "editthispage": "Syte bearbeite",
        "create-this-page": "Die Syte afange",
        "delete": "Lesche",
        "talkpagelinktext": "Diskussion",
        "specialpage": "Spezialsyte",
        "personaltools": "Persönlichi Wärkzüg",
-       "postcomment": "Neje Abschnitt",
        "articlepage": "Syte",
        "talk": "Diskussion",
        "views": "Wievylmol agluegt",
        "jumptonavigation": "Navigation",
        "jumptosearch": "Suech",
        "view-pool-error": "Excusez, d Server sin zur Zyt iberlaschtet.\nS versueche grad zvyl Benutzer die Syte aazluege.\nBitte wart e paar Minute, voreb Du s nomol versuechsch.\n\n$1",
+       "generic-pool-error": "Excusez, d Server sin zur Zyt iberlaschtet.\nS versueche grad zvyl Benutzer die Ressource aazluege.\nBitte wart e paar Momänt, voreb Du s nomol versuechsch.",
        "pool-timeout": "\nDi maximal Wartezyt fir e Lock isch umme",
        "pool-queuefull": "D Warteschlang isch voll",
        "pool-errorunknown": "Nit bekannte Fähler",
+       "pool-servererror": "Dr Poolzellerdienscht isch nit verfiegbar ($1).",
        "aboutsite": "Über {{GRAMMAR:akkusativ|{{SITENAME}}}}",
        "aboutpage": "Project:Über {{UCFIRST:{{GRAMMAR:akkusativ|{{SITENAME}}}}}}",
        "copyright": "Dr Inhalt vu dere Syte stoht unter dr Lizänz $1, wänn s nit andersch aagee isch.",
        "externaldberror": "Entwäder s lit e Fähler bi dr externe Authentifizierung vor, oder Du derfsch Dyy extern Benutzerkonto nid aktualisiere.",
        "login": "Aamälde",
        "nav-login-createaccount": "Aamälde / Konto aalege",
-       "loginprompt": "<small>Für di bir {{SITENAME}} aazmälde, muesch Cookies erloube!</small>",
        "userlogin": "Aamälde/Konto aalege",
        "userloginnocreate": "Aamälde",
        "logout": "Abmälde",
        "gotaccountlink": "»Login fir Benutzer, wu scho aagmäldet sin«",
        "userlogin-resetlink": "Hesch Dyy Aamäldedate vergässe?",
        "userlogin-resetpassword-link": "Passwort vergässe?",
+       "userlogin-helplink2": "Hilf bim Aamälde",
        "userlogin-loggedin": "Du bisch scho as {{GENDER:$1|$1}} aagmäldet.\nBruuch s Formular unte go Di unter eme andere Benutzername aamälde.",
        "userlogin-createanother": "En ander Benutzerkonto aalege",
        "createacct-emailrequired": "E-Mail-Adräss",
        "user-mail-no-addy": "Es isch versuecht worde e E-Mail ohni Angab vunere E-Mail-Adräss z verschigge.",
        "user-mail-no-body": "S isch versuecht wore, ne E-Mail mit eme lääre oder z churze Tekscht z verschicke.",
        "changepassword": "Passwort ändere",
-       "resetpass_announce": "Aamäldig mit em Code, wu per Mail zuegschickt woren isch. Zum d Aamäldig abzschliesse, muesch jetz e nej Passwort wehle.",
+       "resetpass_announce": "Go d Aamäldig abzschließe, muesch e nej Passwort feschtlege.",
        "resetpass_text": "<!-- Tue do dr Text ergänze -->",
        "resetpass_header": "Passwort zrucksetze",
        "oldpassword": "Alts Passwort",
        "retypenew": "Nöis Passwort (es zwöits Mal)",
        "resetpass_submit": "Passwort ibermittle un aamälde",
        "changepassword-success": "Dyy Passwort isch erfolgryych gänderet wore.",
+       "changepassword-throttled": "Du hesch z vilmol versuecht Di aazmälde. Bitte wart $1, voreb Du s non emol versuechsch.",
        "resetpass_forbidden": "S Passwort cha nid gänderet wäre.",
        "resetpass-no-info": "Du muesch Di aamälde zum uf die Syte diräkt zuegryfe z chenne.",
        "resetpass-submit-loggedin": "Passwort ändere",
        "resetpass-submit-cancel": "Abbräche",
        "resetpass-wrong-oldpass": "S temporär oder aktuäll Passwort isch nimi giltig.\nVillicht hesch Dyy Passwort scho gänderet oder e nej temporär Passwort aagforderet.",
+       "resetpass-recycled": "Bitte due Dy Passwort ändere.",
+       "resetpass-temp-emailed": "Du hesch Di mit eme temporäre E-Mail-Code aagmäldet.\nGo d Aamäldig abzschließe, muesch e jetz no ne nej Passwort feschtlege:",
        "resetpass-temp-password": "Temporär Passwort:",
        "resetpass-abort-generic": "D Passwortänderig isch dur e Erwyterig abbroche wore.",
+       "resetpass-expired": "Dy Passwort isch abglofe. Bitte leg e nej Passwort fir d Aamäldig fescht.",
        "passwordreset": "Passwort zruggsetze",
        "passwordreset-text-one": "Fill des Formular uus go Dy Passwort zrucksetze.",
        "passwordreset-text-many": "{{PLURAL:$1|Fill eis vu dr Fälder uus go Dy Passwort zrucksetze.}}",
        "duplicate-defaultsort": "Obacht: Dr Sortierigsschlüssel „$2“ iberschrybt dr vorig brucht Schlüssel „$1“.",
        "version": "Version",
        "version-extensions": "Installierti Erwyterige",
+       "version-skins": "Benutzeroberflechine",
        "version-specialpages": "Spezialsyte",
        "version-parserhooks": "Parser-Schnittstelle",
        "version-variables": "Variable",
        "version-antispam": "Spamschutz",
-       "version-skins": "Benutzeroberflechine",
        "version-other": "Anders",
        "version-mediahandlers": "Medie-Handler",
        "version-hooks": "Schnittstelle ''(Hook)''",
index d4e2ecf..d7d77c3 100644 (file)
        "talkpagelinktext": "שיחה",
        "specialpage": "דף מיוחד",
        "personaltools": "כלים אישיים",
-       "postcomment": "פסקה חדשה",
        "articlepage": "צפייה בדף התוכן",
        "talk": "שיחה",
        "views": "צפיות",
        "externaldberror": "הייתה שגיאה בבסיס הנתונים של ההזדהות, או שאינכם רשאים לעדכן את חשבונכם החיצוני.",
        "login": "כניסה לחשבון",
        "nav-login-createaccount": "כניסה לחשבון / הרשמה",
-       "loginprompt": "לפני הכניסה לחשבון ב{{grammar:תחילית|{{SITENAME}}}}, עליכם לוודא כי ה\"עוגיות\" (Cookies) מופעלות.",
        "userlogin": "כניסה לחשבון / הרשמה",
        "userloginnocreate": "כניסה לחשבון",
        "logout": "יציאה מהחשבון",
        "revdelete-text-text": "גרסאות שנמחקו עדיין תופענה בהיסטוריית הדף, אך חלקים מהתוכן שלהן לא יהיו זמינים לציבור.",
        "revdelete-text-file": "גרסאות קבצים שנמחקו עדיין תופענה בהיסטוריית הקובץ, אך חלקים מהתוכן שלהן לא יהיו זמינים לציבור.",
        "logdelete-text": "פעולות יומן שנמחקו עדיין תופענה בדפי היומנים, אך חלקים מהתוכן שלהן לא יהיו זמינים לציבור.",
-       "revdelete-text-others": "×\9eפע×\99×\9c×\99 ×\9eער×\9bת ×\90×\97ר×\99×\9d ×\91×\90תר ×¢×\93×\99×\99×\9f ×\99×\95×\9b×\9c×\95 ×\9c×\92שת ×\9cת×\95×\9b×\9f ×\94נסתר ×\95×\99×\95×\9b×\9c×\95 ×\9cש×\97×\96ר ×\90×\95ת×\95 ×©×\95×\91 ×\93ר×\9a ×\94×\9e×\9eשק ×\94×\96×\94, אלא אם כן תוגדרנה הגבלות נוספות.",
+       "revdelete-text-others": "×\9eפע×\99×\9c×\99 ×\9eער×\9bת ×\90×\97ר×\99×\9d ×¢×\93×\99×\99×\9f ×\99×\95×\9b×\9c×\95 ×\9c×\92שת ×\9cת×\95×\9b×\9f ×\94נסתר ×\9b×\93×\99 ×\9cש×\97×\96ר ×\90×\95ת×\95, אלא אם כן תוגדרנה הגבלות נוספות.",
        "revdelete-confirm": "אנא אשרו שזה אכן מה שאתם מתכוונים לעשות, שאתם מבינים את התוצאות של מעשה כזה, ושהמעשה מבוצע בהתאם ל[[{{MediaWiki:Policy-url}}|נוהלי האתר]].",
        "revdelete-suppress-text": "יש להשתמש בהסתרה מלאה '''אך ורק''' במקרים הבאים:\n* מידע שעלול להיות לשון הרע\n* חשיפת מידע אישי\n*: '''כתובות בתים ומספרי טלפון, מספרי זיהוי מדינתיים, וכדומה'''",
        "revdelete-legend": "הגדרת הגבלות התצוגה",
        "right-deletedtext": "צפייה בטקסט מחוק ובהבדלים בין גרסאות מחוקות",
        "right-browsearchive": "חיפוש דפים מחוקים",
        "right-undelete": "שחזור דף מחוק",
-       "right-suppressrevision": "בדיקה ושחזור של גרסאות המוסתרות ממפעילי המערכת",
+       "right-suppressrevision": "הצגה, הסתרה וביטול הסתרה של גרסאות מסוימות של דפים מכל המשתמשים",
+       "right-viewsuppressed": "הצגת גרסאות שמוסתרות מכל המשתמשים",
        "right-suppressionlog": "צפייה ביומנים פרטיים",
        "right-block": "חסימת משתמשים אחרים מעריכה",
        "right-blockemail": "חסימת משתמש משליחת דואר אלקטרוני",
        "license": "רישיון:",
        "license-header": "רישיון",
        "nolicense": "אין",
+       "licenses-edit": "עריכת אפשרויות רישיון",
        "license-nopreview": "(תצוגה מקדימה לא זמינה)",
        "upload_source_url": "(כתובת URL תקפה ונגישה)",
        "upload_source_file": "(קובץ במחשב שלך)",
+       "listfiles-delete": "מחיקה",
        "listfiles-summary": "דף מיוחד זה מציג את כל הקבצים שהועלו.",
        "listfiles_search_for": "חיפוש קובץ מדיה בשם:",
        "imgfile": "קובץ",
        "wantedpages-badtitle": "כותרת בלתי תקינה ברשימת התוצאות: $1",
        "wantedfiles": "קבצים מבוקשים",
        "wantedfiletext-cat": "הקבצים הבאים נמצאים בשימוש, אך אינם קיימים. ייתכן שקבצים ממאגרים חיצוניים יהיו רשומים אף על פי שהם קיימים, אך שגיאות כאלה יהיו <del>מחוקות</del>. בנוסף, דפים שמשתמשים בקבצים שאינם קיימים רשומים בדף [[:$1]].",
+       "wantedfiletext-cat-noforeign": "הקבצים הבאים נמצאים בשימוש, אבל אינם קיימים. כמו־כן, דפים שמשתמשים בקבצים שאינם קיימים רשומים בדף [[:$1]].",
        "wantedfiletext-nocat": "הקבצים הבאים נמצאים בשימוש, אך אינם קיימים. ייתכן שקבצים ממאגרים חיצוניים יהיו רשומים אף על פי שהם קיימים, אך שגיאות כאלה יהיו <del>מחוקות</del>.",
+       "wantedfiletext-nocat-noforeign": "הקבצים הבאים נמצאים בשימוש, אבל אינם קיימים.",
        "wantedtemplates": "תבניות מבוקשות",
        "mostlinked": "הדפים המקושרים ביותר",
        "mostlinkedcategories": "הקטגוריות המקושרות ביותר",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|שיחה]])",
        "unknown_extension_tag": "תגית בלתי ידועה: \"$1\"",
        "duplicate-defaultsort": "'''אזהרה:''' המיון הרגיל \"$2\" דורס את המיון הרגיל המוקדם ממנו \"$1\".",
+       "duplicate-displaytitle": "<strong>אזהרה:</strong> כותרת התצוגה \"$2\" דורסת את כותרת התצוגה הקודמת \"$1\".",
        "version": "גרסת התוכנה",
        "version-extensions": "הרחבות מותקנות",
        "version-skins": "עיצובים מותקנים",
index 6845717..8ff0b40 100644 (file)
        "view": "दर्शाव",
        "view-foreign": "$1 पर देखें",
        "edit": "सम्पादन",
+       "edit-local": "स्थानीय विवरण सम्पादन",
        "create": "बनाएँ",
+       "create-local": "स्थानीय विवरण निर्माण",
        "editthispage": "इस पृष्ठ को बदलें",
        "create-this-page": "यह पृष्ठ बनाएँ",
        "delete": "हटाएँ",
        "talkpagelinktext": "चर्चा",
        "specialpage": "विशेष पृष्ठ",
        "personaltools": "वैयक्तिक औज़ार",
-       "postcomment": "नया अनुभाग",
        "articlepage": "सामग्री पृष्ठ देखें",
        "talk": "चर्चा",
        "views": "दर्शाव",
        "jumptonavigation": "भ्रमण",
        "jumptosearch": "खोज",
        "view-pool-error": "क्षमा करें, इस समय सर्वरों पर अतिभार है।\nबहुत सारे प्रयोक्ता इस पृष्ठ को देखने का प्रयास कर रहे हैं।\nकृपया कुछ समय प्रतीक्षा कर फिर से इस पृष्ठ को देखने का प्रयास करें।\n\n$1",
+       "generic-pool-error": "क्षमा करें, इस समय सर्वरों पर अत्यधिक भार है।\nइस सामग्री को बहुत अधिक प्रयोक्ता देखने का प्रयत्न कर रहे हैं।\nकृपया इसे देखने का पुनः यत्न कुछ समय पश्चात करें।",
        "pool-timeout": "तालाबन्दी के लिए प्रतीक्षा समय समाप्त",
        "pool-queuefull": "पूल पंक्ति भरी हुई है",
        "pool-errorunknown": "अज्ञात त्रुटि",
        "externaldberror": "या तो प्रमाणिकरण डाटाबेस में त्रुटि हुई है या फिर आपको अपना बाह्य खाता अपडेट करने की अनुमति नहीं है।",
        "login": "लॉग इन",
        "nav-login-createaccount": "सत्रारंभ / खाता खोलें",
-       "loginprompt": "{{SITENAME}} पर लॉग इन करने के लिए अपने ब्राउज़र पर कुकीज़ (cookies) सक्षम करें।",
        "userlogin": "सत्रारंभ / खाता खोलें",
        "userloginnocreate": "लॉग इन",
        "logout": "सत्रांत",
        "gotaccountlink": "लॉग इन",
        "userlogin-resetlink": "अपनी प्रवेश जानकारी भूल गए हैं?",
        "userlogin-resetpassword-link": "अपना पासवर्ड भूल गए?",
+       "userlogin-helplink2": "लॉग इन करने में सहायता",
        "userlogin-loggedin": "आप {{GENDER:$1|$1}} के रूप में पहले से लॉग्ड इन हैं।\nकिसी अन्य सदस्य के रूप में लॉग इन करने के लिए निम्नलिखित फ़ॉर्म का प्रयोग करें।",
        "userlogin-createanother": "एक अन्य खाता खोलें",
        "createacct-emailrequired": "ई-मेल पता",
        "edit-gone-missing": "पृष्ठ अद्यतित न किया जा सका।\nलगता है यह हटा दिया गया है।",
        "edit-conflict": "संपादन अंतर्विरोध",
        "edit-no-change": "आपने कोई बदलाव ही नहीं किए, अतः आपके इस संपादन को नज़रंदाज़ कर दिया गया है।",
+       "postedit-confirmation-created": "पृष्ठ निर्मित किया गया है।",
+       "postedit-confirmation-restored": "पृष्ठ पुरानी स्थिति पर लाया गया है।",
        "postedit-confirmation-saved": "आपका सम्पादन सहेजा गया है।",
        "edit-already-exists": "नया पृष्ठ बनाया नहीं जा सका।\nयह पहले से मौजूद है।",
        "defaultmessagetext": "संदेश का डिफ़ॉल्ट पाठ",
        "parser-template-loop-warning": "साँचा चक्र मिला: [[$1]]",
        "parser-template-recursion-depth-warning": "साँचा पुनरावर्ती गहराई सीमा पार ($1)",
        "language-converter-depth-warning": "भाषा कन्वर्टर गहराई सीमा से बाहर गया ( $1 )",
-       "node-count-exceeded-category": "पृष्ठ जिनमें नोड-संख्या पार की गई है",
+       "node-count-exceeded-category": "पृष्ठ जिनमें नोड-संख्या सीमा पार की गई है",
+       "node-count-exceeded-category-desc": "यह उन पृष्ठों की श्रेणी है जिनमें नोड-संख्या सीमा पार की गयी है।",
        "node-count-exceeded-warning": "पृष्ठ ने नोड-संख्या पार की है",
        "expansion-depth-exceeded-category": "पृष्ठ जिनमें विस्तार गहराई पार की गई है",
+       "expansion-depth-exceeded-category-desc": "यह उन पृष्ठों की श्रेणी है जिनमें विस्तार गहराई पार की गयी है।",
        "expansion-depth-exceeded-warning": "पृष्ठ में विस्तार गहराई पार की गई है",
        "parser-unstrip-loop-warning": "Unstrip लूप पाया गया",
        "parser-unstrip-recursion-limit": "Unstrip पुनरावर्तन सीमा पार की गई ($1)",
        "currentrev": "सद्य अवतरण",
        "currentrev-asof": "$1 के समय का अवतरण",
        "revisionasof": "$1 का अवतरण",
-       "revision-info": "$2 द्वारा परिवर्तित $1 का अवतरण",
+       "revision-info": "{{GENDER:$6|$2}} द्वारा परिवर्तित $1 का अवतरण$7",
        "previousrevision": "← पुराना अवतरण",
        "nextrevision": "नया अवतरण →",
        "currentrevisionlink": "वर्तमान अवतरण",
        "revdelete-no-file": "निर्दिष्ट फ़ाइल मौजूद नहीं है।",
        "revdelete-show-file-confirm": "क्या आप वाकई फ़ाइल \"<nowiki>$1</nowiki>\" के $2 को $3 बजे बने, हटाए जा चुके अवतरण को देखना चाहते हैं?",
        "revdelete-show-file-submit": "हाँ",
+       "revdelete-selected-text": "[[:$2]] {{PLURAL:$1|का|के}} चयनित अवतरण:",
+       "revdelete-selected-file": "[[:$2]] {{PLURAL:$1|का|के}} चयनित फ़ाइल अवतरण:",
        "logdelete-selected": "{{PLURAL:$1|चुना हुआ|चुने हुए}} लॉग इवेंट:",
        "revdelete-confirm": "पुष्टि करें कि आप यह कार्य करना चाहते हैं, आप इसका परिणाम समझते हैं, और आप ये [[{{MediaWiki:Policy-url}}|नीति]] के अनुसार कर रहे हैं।",
        "revdelete-suppress-text": "छिपाने का प्रयोग <strong>केवल</strong> इन परिस्थितियों में होना चाहिए:\n* संभावित अपमानजनक जानकारी\n* अनुपयुक्त निजी जानकारी\n*: <em>घर के पते व दूरभाष, राष्ट्रीय पहचान क्रमांक आदि।</em>",
        "right-move": "पृष्ठ स्थानांतरित करें",
        "right-move-subpages": "पृष्ठ उपपृष्ठों सहित स्थानांतरीत करें",
        "right-move-rootuserpages": "मूल सदस्य पृष्ठ स्थानांतरित करें",
+       "right-move-categorypages": "श्रेणी पृष्ठ स्थानांतरित करें",
        "right-movefile": "संचिकाएँ स्थानांतरित करें",
        "right-suppressredirect": "पृष्ठ स्थानांतरित करते समय पुनर्निर्देश ना छोड़ें",
        "right-upload": "फ़ाइल अपलोड करें",
        "action-createpage": "पृष्ठ बनाने",
        "action-createtalk": "वार्ता पृष्ठ बनाने",
        "action-createaccount": "यह सदस्य खाता खोलने",
+       "action-history": "इस पृष्ठ का इतिहास देखने",
        "action-minoredit": "इस बदलाव को छोटा बदलाव चिन्हित करने",
        "action-move": "इस पृष्ठ को स्थानांतरित करने",
        "action-move-subpages": "इस पृष्ठ व इसके उप-पृष्ठों को स्थानांतरित करने",
        "action-move-rootuserpages": "मूल सदस्य पृष्ठों को स्थानांतरित करने",
+       "action-move-categorypages": "श्रेणी पृष्ठ स्थानांतरित करने",
        "action-movefile": "इस फ़ाइल को स्थानांतरित करने",
        "action-upload": "इस फ़ाइल को अपलोड करने",
        "action-reupload": "मौजूदा फ़ाइल के स्थान पर नई सामग्री डालने",
        "windows-nonascii-filename": "यह विकि विशेष कैरैक्टरों के साथ फ़ाइल के नामों को स्वीकार नहीं करता।",
        "fileexists": "इस नाम की फ़ाइल पहले से मौजूद है, यदि यह फ़ाइल बदलने में आप साशंक हैं तो कृपया <strong>[[:$1]]</strong> देखें। [[$1|thumb]]",
        "filepageexists": "इस फ़ाइल के लिए विवरण पृष्ठ पहले ही <strong>[[:$1]]</strong> पर बनाया जा चुका है, पर इस नाम की कोई फ़ाइल अभी उपस्थित नहीं है। \nआप जो विवरण देंगे वह विवरण पृष्ठ पर नहीं दिखेगा। \nआपको अपने विवरण को वहाँ डालने के लिए उसका हस्त्य सम्पादन करना पड़ेगा।\n[[$1|thumb]]",
-       "fileexists-extension": "à¤\87स à¤¨à¤¾à¤® à¤¸à¥\87 à¤®à¤¿à¤²à¤¤à¥\87-à¤\9cà¥\81लतà¥\87 à¤¨à¤¾à¤® à¤\95à¥\80 à¤\8fà¤\95 à¤«à¤¼à¤¾à¤\87ल à¤ªà¤¹à¤²à¥\87 à¤¸à¥\87 à¤¹à¥\88: [[$2|thumb]]\n* à¤\85पलà¥\8bड à¤¹à¥\8b à¤°à¤¹à¥\80 à¤«à¤¼à¤¾à¤\87ल à¤\95ा à¤¨à¤¾à¤®: <strong>[[:$1]]</strong>\n* à¤®à¥\8cà¤\9cà¥\82दा à¤«à¤¼à¤¾à¤\87ल à¤\95ा à¤¨à¤¾à¤®: <strong>[[:$2]]</strong>\nà¤\95à¥\83पया à¤\85नà¥\8dय à¤¨à¤¾à¤® à¤\9aà¥\81नà¥\87à¤\82।",
+       "fileexists-extension": "à¤\87स à¤¨à¤¾à¤® à¤¸à¥\87 à¤®à¤¿à¤²à¤¤à¥\87-à¤\9cà¥\81लतà¥\87 à¤¨à¤¾à¤® à¤\95à¥\80 à¤\8fà¤\95 à¤«à¤¼à¤¾à¤\87ल à¤ªà¤¹à¤²à¥\87 à¤¸à¥\87 à¤¹à¥\88: [[$2|thumb]]\n* à¤\85पलà¥\8bड à¤¹à¥\8b à¤°à¤¹à¥\80 à¤«à¤¼à¤¾à¤\87ल à¤\95ा à¤¨à¤¾à¤®: <strong>[[:$1]]</strong>\n* à¤®à¥\8cà¤\9cà¥\82दा à¤«à¤¼à¤¾à¤\87ल à¤\95ा à¤¨à¤¾à¤®: <strong>[[:$2]]</strong>\nशायद à¤\86प à¤\87ससà¥\87 à¤µà¤¿à¤¶à¤¿à¤·à¥\8dà¤\9f à¤¨à¤¾à¤® à¤\95ा à¤ªà¥\8dरयà¥\8bà¤\97 à¤\95रना à¤\9aाहà¥\87à¤\82à¤\97à¥\87?",
        "fileexists-thumbnail-yes": "यह फ़ाइल बड़े चित्र का छोटा आकार ''(अंगूठाकार)'' प्रतीत होता है। [[$1|thumb]]\n<strong>[[:$1]]</strong> फ़ाइल को देखें।\nअगर जाँची गई फ़ाइल इसी आकार की है तो छोटे आकार की फ़ाइल अपलोड करने की आवश्यकता नहीं है।",
        "file-thumbnail-no": "इस फ़ाइल का नाम <strong>$1</strong> से शुरू हो रहा है।\nयह आकार घटाई हुई ''(अंगूठाकार)'' हो सकती है।\nअगर यह चित्र अपने मूल आकार में है तो इसे अपलोड करें, नहीं तो फ़ाइल बदलें।",
        "fileexists-forbidden": "इस नाम की फ़ाइल पहले ही मौजूद है, और इसकी जगह और नहीं अपलोड की जा सकती।\nयदि आप इस फ़ाइल को फिर भी अपलोड करना चाहते हैं, तो कृपया वापस जा के इसके लिए कोई अन्य नाम चुनें।\n[[File:$1|thumb|center|$1]]",
        "uploaddisabledtext": "फ़ाइल अपलोड अक्षम हैं।",
        "php-uploaddisabledtext": "पी॰एच॰पी में फ़ाइल अपलोड बंद हैं।\nकृपया file_uploads जमाव की जाँच करें।",
        "uploadscripted": "इस फ़ाइल में एच॰टी॰एम॰एल या स्क्रिप्ट कोड है, जो वेब ब्राउज़र द्वारा गलत पढ़ा जा सकता है।",
+       "uploadscriptednamespace": "इस एस॰वी॰जी फ़ाइल में अमान्य नामस्थान \"$1\" है।",
        "uploadinvalidxml": "अपलोड की गई फ़ाइल में स्थित XML पार्स नहीं की जा सकी।",
        "uploadvirus": "इस फ़ाइल में व्हाईरस हैं! अधिक जानकारी: $1",
        "uploadjava": "यह फ़ाइल एक ज़िप फ़ाइल है जिसमें एक जावा .class फ़ाइल है।\nजावा फ़ाइलों को अपलोड करना वर्जित है, क्योंकि इनके कारण सुरक्षा बाधाएँ पार की जा सकती हैं।",
        "license": "लाइसेन्सिंग:",
        "license-header": "लाइसेन्सिंग",
        "nolicense": "कुछ भी नहीं चुना",
+       "licenses-edit": "लाइसेंस विकल्प सम्पादन",
        "license-nopreview": "(झलक उपलब्ध नहीं है)",
        "upload_source_url": " (एक वैध, सभी जगहों से उपलब्ध यू॰आर॰एल)",
        "upload_source_file": " (आपके कम्प्यूटर से फ़ाइल)",
+       "listfiles-delete": "हटाएँ",
        "listfiles-summary": "यह विशेष पृष्ठ सभी अपलोड की गई फ़ाइलें दर्शाता है।",
        "listfiles_search_for": "मीडिया नाम के लिये खोजें:",
        "imgfile": "फ़ाइल",
        "filedelete-maintenance": "रखरखाव चल रहा है और रखरखाव के दौरान फ़ाइलों को हटाना और पुनर्स्थापित करना अक्षम है।",
        "filedelete-maintenance-title": "फ़ाइल हटा नहीं सकते",
        "mimesearch": "MIME खोज",
-       "mimesearch-summary": "MIME-प्रकारों के अनुसार फ़ाइलें खोजने के लिये इस पृष्ठ का इस्तेमाल किया जा सकता है।\nइनपुट: फ़ाइल का प्रकार/उपप्रकार, उदा. <code>image/jpeg</code>.",
+       "mimesearch-summary": "MIME-प्रकारों के अनुसार फ़ाइलें खोजने के लिये इस पृष्ठ का इस्तेमाल किया जा सकता है।\nइनपुट: फ़ाइल का प्रकार/उपप्रकार या प्रकार/*, उदा. <code>image/jpeg</code>।",
        "mimetype": "MIME प्रकार:",
        "download": "डाउनलोड",
        "unwatchedpages": "ध्यान न दिये हुए पृष्ठ",
        "wantedtemplates": "वांछित साँचे",
        "mostlinked": "सर्वाधिक से जुड़े हुए पृष्ठ",
        "mostlinkedcategories": "सर्वाधिक से जुड़ी हुई श्रेणियाँ",
-       "mostlinkedtemplates": "सरà¥\8dवाधिà¤\95 à¤¸à¥\87 à¤\9cà¥\81ड़à¥\87 à¤¹à¥\81à¤\8f à¤¸à¤¾à¤\81à¤\9aà¥\87",
+       "mostlinkedtemplates": "सरà¥\8dवाधिà¤\95 à¤\9fà¥\8dराà¤\82सà¤\95à¥\8dलà¥\82ड à¤\95ियà¥\87 à¤\97यà¥\87 à¤ªà¥\83षà¥\8dठ",
        "mostcategories": "सर्वाधिक श्रेणियों वाले पृष्ठ",
        "mostimages": "सर्वाधिक से जुड़ी हुई फ़ाइलें",
        "mostinterwikis": "सर्वाधिक अंतरविकी कड़ियों वाले पृष्ठ",
        "duplicate-defaultsort": "'''Warning:''' पुरानी मूल क्रमांकन कुंजी \"$1\" के बजाय अब मूल क्रमांकन कुंजी \"$2\" होगी।",
        "version": "रूपान्तर",
        "version-extensions": "इन्स्टॉल की हुई एक्स्टेंशन",
+       "version-skins": "इन्स्टॉल की गयी त्वचाएँ",
        "version-specialpages": "विशेष पृष्ठ",
        "version-parserhooks": "पार्सर हूक",
        "version-variables": "वेरिएबल",
        "version-antispam": "अवांछित-ईमेल रोकथाम",
-       "version-skins": "त्वचाएं",
        "version-other": "अन्य",
        "version-mediahandlers": "मीडिया संचालक",
        "version-hooks": "हूक",
index 53180a8..62fd035 100644 (file)
        "talkpagelinktext": "razgovor",
        "specialpage": "Posebna stranica",
        "personaltools": "Osobni alati",
-       "postcomment": "Novi odlomak",
        "articlepage": "Vidi članak",
        "talk": "Razgovor",
        "views": "Pogledi",
        "externaldberror": "Došlo je do pogreške s vanjskom autorizacijom ili Vam nije dopušteno osvježavanje vanjskog suradničkog računa.",
        "login": "Prijavi se",
        "nav-login-createaccount": "Prijavi se",
-       "loginprompt": "Za prijavu na sustav {{SITENAME}} morate u pregledniku uključiti kolačiće (cookies).",
        "userlogin": "Prijavi se / stvori račun",
        "userloginnocreate": "Prijavi se",
        "logout": "Odjavi se",
        "powersearch-togglelabel": "Uključi:",
        "powersearch-toggleall": "Sve",
        "powersearch-togglenone": "Ništa",
+       "powersearch-remember": "Zapamti izbor za buduća pretraživanja",
        "search-external": "Vanjski pretraživač",
        "searchdisabled": "<p>Oprostite! Pretraga po cjelokupnoj bazi je zbog bržeg rada projekta {{SITENAME}} trenutačno onemogućena. Možete se poslužiti tražilicom Google.</p>",
        "preferences": "Postavke",
        "listfiles_size": "Veličina (u bajtovima)",
        "listfiles_description": "Opis",
        "listfiles_count": "Inačice",
+       "listfiles-show-all": "Uključujući starije inačice slika",
        "listfiles-latestversion-yes": "Da",
        "listfiles-latestversion-no": "Ne",
        "file-anchor-link": "Slika",
index 4567ce3..8203833 100644 (file)
@@ -54,7 +54,7 @@
        "tog-watchdeletion": "Az általam törölt lapok és fájlok felvétele a figyelőlistámra",
        "tog-minordefault": "Alapértelmezetten minden szerkesztésemet jelölje aprónak",
        "tog-previewontop": "Előnézet megjelenítése a szerkesztőablak előtt",
-       "tog-previewonfirst": "Előnézet első szerkesztésnél",
+       "tog-previewonfirst": "Előnézet mutatása az első szerkesztésnél",
        "tog-enotifwatchlistpages": "Kapjak értesítést e-mailben, ha egy általam figyelt lap vagy fájl megváltozik",
        "tog-enotifusertalkpages": "Kapjak értesítést e-mailben, ha megváltozik a vitalapom",
        "tog-enotifminoredits": "Kapjak értesítést e-mailben a lapok és fájlok apró változtatásairól",
        "talkpagelinktext": "vitalap",
        "specialpage": "Speciális lap",
        "personaltools": "Személyes eszközök",
-       "postcomment": "Új szakasz",
        "articlepage": "Szócikk megtekintése",
        "talk": "Vitalap",
        "views": "Nézetek",
        "externaldberror": "Hiba történt a külső adatbázis hitelesítése közben, vagy nem vagy jogosult a külső fiókod frissítésére.",
        "login": "Bejelentkezés",
        "nav-login-createaccount": "Bejelentkezés / fiók létrehozása",
-       "loginprompt": "Engedélyezned kell a sütiket (''cookie''), hogy bejelentkezhess a(z) {{SITENAME}} wikibe.",
        "userlogin": "Bejelentkezés / fiók létrehozása",
        "userloginnocreate": "Bejelentkezés",
        "logout": "Kijelentkezés",
        "sp-contributions-search": "Közreműködések szűrése",
        "sp-contributions-username": "IP-cím vagy felhasználónév:",
        "sp-contributions-toponly": "Csak a jelenleg utolsónak számító változtatásokat mutassa",
+       "sp-contributions-newonly": "Csak az új oldalt létrehozó szerkesztéseket mutassa",
        "sp-contributions-submit": "Keresés",
        "whatlinkshere": "Mi hivatkozik erre",
        "whatlinkshere-title": "A(z) „$1” lapra hivatkozó lapok",
index 63fd98e..514b944 100644 (file)
@@ -11,7 +11,8 @@
                        "Shirayuki",
                        "Yfdyh000",
                        "לערי ריינהארט",
-                       "아라"
+                       "아라",
+                       "Carlosedepaula"
                ]
        },
        "tog-underline": "Sublinear ligamines:",
        "talkpagelinktext": "Discussion",
        "specialpage": "Pagina special",
        "personaltools": "Instrumentos personal",
-       "postcomment": "Nove section",
        "articlepage": "Vider pagina de contento",
        "talk": "Discussion",
        "views": "Representationes",
        "externaldberror": "O il occurreva un error in le base de datos de authentication, o tu non ha le autorisation de actualisar tu conto externe.",
        "login": "Aperir session",
        "nav-login-createaccount": "Aperir session / crear conto",
-       "loginprompt": "Tu debe haber activate le cookies pro poter aperir un session in {{SITENAME}}.",
        "userlogin": "Aperir session / crear conto",
        "userloginnocreate": "Aperir session",
        "logout": "Clauder session",
        "revdelete-text-text": "Versiones delite continua a apparer in le historia del pagina, ma parte de lor contento essera inaccessibile pro le publico.",
        "revdelete-text-file": "Versiones delite de un file continua a apparer in le historia del file, ma parte de lor contento essera inaccessibile pro le publico.",
        "logdelete-text": "Eventos delite continua a apparer in le registros, ma parte de lor contento essera inaccessibile pro le publico.",
-       "revdelete-text-others": "Altere administratores in {{SITENAME}} continua a poter acceder al contento abscondite e pote restaurar lo per medio de iste mesme interfacie, a minus que additional restrictiones ha essite definite.",
+       "revdelete-text-others": "Altere administratores continua a poter acceder al contento celate e restaurar lo, a minus que additional restrictiones ha essite definite.",
        "revdelete-confirm": "Per 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 politica]].",
        "revdelete-suppress-text": "Le suppression debe '''solmente''' esser usate pro le sequente casos:\n* Information potentialmente diffamatori\n* Information personal inappropriate\n*: ''adresses de domicilio e numeros de telephono, numeros de securitate social, etc.''",
        "revdelete-legend": "Definir restrictiones de visibilitate",
        "right-deletedtext": "Vider texto delite e differentias inter versiones delite",
        "right-browsearchive": "Cercar in paginas delite",
        "right-undelete": "Restaurar un pagina",
-       "right-suppressrevision": "Revider e restaurar versiones celate ab administratores",
+       "right-suppressrevision": "Vider, celar e revelar versiones specific de paginas de qualcunque usator",
+       "right-viewsuppressed": "Vider versiones celate de qualcunque usator",
        "right-suppressionlog": "Vider registros private",
        "right-block": "Blocar altere usatores de facer modificationes",
        "right-blockemail": "Blocar un usator de inviar e-mail",
        "license": "Licentia:",
        "license-header": "Licentia",
        "nolicense": "Nulle licentia seligite",
+       "licenses-edit": "Modificar optiones de licentia",
        "license-nopreview": "(Previsualisation non disponibile)",
        "upload_source_url": " (un adresse URL valide e publicamente accessibile)",
        "upload_source_file": " (un file in tu computator)",
+       "listfiles-delete": "deler",
        "listfiles-summary": "Iste pagina special monstra tote le files incargate.",
        "listfiles_search_for": "Cercar un nomine de media:",
        "imgfile": "file",
        "wantedpages-badtitle": "Titulo invalide in le gruppo de resultatos: $1",
        "wantedfiles": "Files desirate",
        "wantedfiletext-cat": "Le sequente files es usate ma non existe. Le files ab repositorios externe pote esser listate malgrado que illos existe. Omne tal false positivos essera <del>cancellate</del>. In addition, paginas que incorpora files que non existe es listate in [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Le sequente files es usate ma non existe. In addition, paginas que incorpora files que non existe es listate in [[:$1]].",
        "wantedfiletext-nocat": "Le sequente files es usate ma non existe. Files ab repositorios externe pote esser listate malgrado que illos existe. Omne tal false positivos essera <del>cancellate</del>.",
+       "wantedfiletext-nocat-noforeign": "Le sequente files es usate ma non existe.",
        "wantedtemplates": "Patronos desirate",
        "mostlinked": "Paginas le plus ligate",
        "mostlinkedcategories": "Categorias le plus ligate",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discussion]])",
        "unknown_extension_tag": "Etiquetta de extension incognite \"$1\"",
        "duplicate-defaultsort": "Attention: Le clave de ordination predefinite \"$2\" supplanta le anterior clave de ordination predefinite \"$1\".",
+       "duplicate-displaytitle": "<strong>Attention:</strong> Le titulo a monstrar \"$2\" supplanta le ancian titulo a monstrar \"$1\".",
        "version": "Version",
        "version-extensions": "Extensiones installate",
        "version-skins": "Apparentias installate",
        "expand_templates_remove_nowiki": "Supprimer le etiquettas <nowiki> in le resultato",
        "expand_templates_generate_xml": "Monstrar arbore syntactic XML",
        "expand_templates_generate_rawhtml": "Monstrar HTML brute",
-       "expand_templates_preview": "Previsualisation"
+       "expand_templates_preview": "Previsualisation",
+       "pagelanguage": "Selector de lingua de pagina",
+       "pagelang-name": "Pagina",
+       "pagelang-language": "Lingua",
+       "pagelang-use-default": "Usar lingua predefinite",
+       "pagelang-select-lang": "Selige lingua",
+       "right-pagelang": "Cambiar lingua del pagina",
+       "action-pagelang": "cambiar le lingua del pagina",
+       "log-name-pagelang": "Registro de cambios de lingua",
+       "log-description-pagelang": "Isto es un registro de cambios de lingua in paginas.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|cambiava}} le lingua del pagina $3 de $4 a $5."
 }
index b23e77e..87985cc 100644 (file)
        "talkpagelinktext": "bicara",
        "specialpage": "Halaman istimewa",
        "personaltools": "Peralatan pribadi",
-       "postcomment": "Bagian baru",
        "articlepage": "Lihat halaman isi",
        "talk": "Pembicaraan",
        "views": "Tampilan",
        "externaldberror": "Telah terjadi kesalahan otentikasi basis data eksternal atau Anda tidak diizinkan melakukan kemaskini terhadap akun eksternal Anda.",
        "login": "Masuk log",
        "nav-login-createaccount": "Masuk log / buat akun",
-       "loginprompt": "Anda harus mengaktifkan kuki untuk dapat masuk log ke {{SITENAME}}.",
        "userlogin": "Masuk log / buat akun",
        "userloginnocreate": "Masuk log",
        "logout": "Keluar log",
        "mergehistory-empty": "Tidak ada revisi yang dapat digabung.",
        "mergehistory-success": "$3 {{PLURAL:$3|revisi|revisi}} dari [[:$1]] berhasil digabungkan ke [[:$2]].",
        "mergehistory-fail": "Tidak dapat melakukan penggabungan, harap periksa kembali halaman dan parameter waktu.",
+       "mergehistory-fail-toobig": "Tidak dapat melakukan penggabungan sebagai lebih dari batas dari $1 {{PLURAL:$1|revisi|revisi}} akan dipindahkan.",
        "mergehistory-no-source": "Halaman sumber $1 tidak ada.",
        "mergehistory-no-destination": "Halaman tujuan $1 tidak ada.",
        "mergehistory-invalid-source": "Judul halaman sumber haruslah judul yang berlaku.",
        "largefileserver": "Berkas ini lebih besar dari pada yang diizinkan server.",
        "emptyfile": "Berkas yang Anda muatkan kelihatannya kosong. Hal ini mungkin disebabkan karena adanya kesalahan ketik pada nama berkas. Silakan pastikan apakah Anda benar-benar ingin memuatkan berkas ini.",
        "windows-nonascii-filename": "Wiki ini tidak mendukung nama berkas dengan karakter istimewa.",
-       "fileexists": "Suatu berkas dengan nama tersebut telah ada, harap periksa <strong>[[:$1]]</strong> jika Anda tidak yakin untuk mengubahnya.\n[[$1|thumb]]",
+       "fileexists": "Suatu berkas dengan nama tersebut telah ada, harap periksa <strong>[[:$1]]</strong> jika {{GENDER:|Anda}} tidak yakin untuk mengubahnya.\n[[$1|thumb]]",
        "filepageexists": "Halaman deskripsi untuk berkas ini telah dibuat di <strong>[[:$1]]</strong>, tapi saat ini tak ditemukan berkas dengan nama tersebut. Ringkasan yang Anda masukkan tidak akan tampil pada halaman deskripsi. Untuk memunculkannya, Anda perlu untuk menyuntingnya secara manual.\n[[$1|thumb]]",
-       "fileexists-extension": "Berkas dengan nama serupa telah ada: [[$2|thumb]]\n* Nama berkas yang akan dimuat: <strong>[[:$1]]</strong>\n* Nama berkas yang telah ada: <strong>[[:$2]]</strong>\nMohon gunakan nama yang berbeda.",
+       "fileexists-extension": "Berkas dengan nama serupa telah ada: [[$2|thumb]]\n* Nama berkas yang akan dimuat: <strong>[[:$1]]</strong>\n* Nama berkas yang telah ada: <strong>[[:$2]]</strong>\nApakah Anda mungkin ingin menggunakan nama yang lebih khas?",
        "fileexists-thumbnail-yes": "Berkas ini tampaknya merupakan gambar yang ukurannya diperkecil ''(miniatur)''. [[$1|thumb]]\nHarap periksa berkas <strong>[[:$1]]</strong> tersebut.\nJika berkas tersebut memang merupakan gambar dalam ukuran aslinya, Anda tidak perlu untuk memuat kembali miniatur lainnya.",
        "file-thumbnail-no": "Nama berkas dimulai dengan <strong>$1</strong>.\nTampaknya berkas ini merupakan gambar dengan ukuran diperkecil ''(miniatur)''.\nJika Anda memiliki versi resolusi penuh dari gambar ini, harap muatkan berkas tersebut. Jika tidak, harap ubah nama berkas ini.",
        "fileexists-forbidden": "Suatu berkas dengan nama ini telah ada dan tak dapat ditimpa.\nJika Anda masih ingin memuat berkas Anda, silakan kembali dan gunakan nama baru. [[File:$1|thumb|center|$1]]",
        "license-nopreview": "(Pratayang tak tersedia)",
        "upload_source_url": " (suatu URL valid yang dapat diakses publik)",
        "upload_source_file": " (suatu berkas di komputer Anda)",
+       "listfiles-delete": "hapus",
        "listfiles-summary": "Halaman istimewa ini menampilkan semua berkas yang telah diunggah.\nKetika disaring oleh pengguna, hanya versi berkas terbaru dari berkas yang diunggah oleh pengguna tersebut yang ditampilkan.",
        "listfiles_search_for": "Cari nama berkas:",
        "imgfile": "berkas",
        "filedelete-maintenance": "Penghapusan dan pengembalian berkas sementara dinonaktifkan selama perawatan.",
        "filedelete-maintenance-title": "Tidak dapat menghapus berkas",
        "mimesearch": "Pencarian MIME",
-       "mimesearch-summary": "Halaman ini menyediakan fasilitas menyaring berkas berdasarkan tipe MIME-nya. Masukkan: contenttype/subtype, misalnya <code>image/jpeg</code>.",
+       "mimesearch-summary": "Halaman ini menyediakan fasilitas menyaring berkas berdasarkan tipe MIME-nya. Masukkan: contenttype/subtype atau contenttype/*, misalnya <code>image/jpeg</code>.",
        "mimetype": "Tipe MIME:",
        "download": "unduh",
        "unwatchedpages": "Halaman yang tak dipantau",
        "wantedpages-badtitle": "Judul tak valid dalam himpunan hasil: $1",
        "wantedfiles": "Berkas yang diinginkan",
        "wantedfiletext-cat": "Berkas-berkas berikut digunakan tetapi tidak ada. Berkas dari repositori asing mungkin tercantum meskipun ada. Setiap \"false positive\" akan <del>dicoret</del>. Selain itu, halaman yang menggunakan berkas yang tidak ada akan dicantumkan dalam [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Berkas berikut ini digunakan tetapi tidak ada. Selain itu, halaman yang menanamkan berkas yang tidak ada tercantum dalam [[:$1]].",
        "wantedfiletext-nocat": "Berkas-berkas berikut digunakan tetapi tidak ada. Berkas dari repositori asing mungkin tercantum meskipun ada. Setiap \"false positive\" akan <del>dicoret</del>.",
+       "wantedfiletext-nocat-noforeign": "Berkas berikut ini digunakan tetapi tidak ada.",
        "wantedtemplates": "Templat yang diinginkan",
        "mostlinked": "Halaman yang tersering dituju",
        "mostlinkedcategories": "Kategori yang tersering digunakan",
-       "mostlinkedtemplates": "Templat yang tersering digunakan",
+       "mostlinkedtemplates": "Halaman yang paling ditransklusikan",
        "mostcategories": "Halaman dengan kategori terbanyak",
        "mostimages": "Berkas yang tersering digunakan",
        "mostinterwikis": "Halaman dengan interwiki terbanyak",
        "timezone-utc": "UTC",
        "unknown_extension_tag": "Tag ekstensi tidak dikenal \"$1\"",
        "duplicate-defaultsort": "Peringatan: Kunci pengurutan baku \"$2\" mengabaikan kunci pengurutan baku \"$1\" sebelumnya.",
+       "duplicate-displaytitle": "<strong>Peringatan:</strong> Menampilkan judul \"$2\" menimpa judul tampilan \"$1\" sebelumnya.",
        "version": "Versi",
        "version-extensions": "Ekstensi terinstal",
-       "version-skins": "Kulit",
+       "version-skins": "Kulit yang diinstal",
        "version-specialpages": "Halaman istimewa",
        "version-parserhooks": "Kait parser",
        "version-variables": "Variabel",
        "version-hook-name": "Nama kait",
        "version-hook-subscribedby": "Dilanggani oleh",
        "version-version": "(Versi $1)",
+       "version-no-ext-name": "[tanpa nama]",
        "version-svn-revision": "(r$2)",
        "version-license": "Lisensi MediaWiki",
        "version-ext-license": "Lisensi",
        "version-ext-colheader-name": "Ekstensi",
+       "version-skin-colheader-name": "Kulit",
        "version-ext-colheader-version": "Versi",
        "version-ext-colheader-license": "Lisensi",
        "version-ext-colheader-description": "Deskripsi",
        "expand_templates_remove_nowiki": "Tidak menampilkan tag <nowiki> pada hasilnya",
        "expand_templates_generate_xml": "Tampilkan pohon parser XML",
        "expand_templates_generate_rawhtml": "Tampilkan HTML mentah",
-       "expand_templates_preview": "Pratayang"
+       "expand_templates_preview": "Pratayang",
+       "pagelanguage": "Pemilih bahasa halaman",
+       "pagelang-name": "Halaman",
+       "pagelang-language": "Bahasa",
+       "pagelang-use-default": "Gunakan bahasa default",
+       "pagelang-select-lang": "Pilih bahasa",
+       "right-pagelang": "Ubah bahasa halaman",
+       "action-pagelang": "mengubah bahasa halaman",
+       "log-name-pagelang": "Ubah bahasa log",
+       "log-description-pagelang": "Ini adalah log perubahan dalam bahasa halaman.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|mengubah}} bahasa halaman $3 dari $4 menjadi $5."
 }
index 617110a..74eec5e 100644 (file)
                ]
        },
        "tog-underline": "Pinag-ugisan ti silpo:",
-       "tog-hideminor": "Ilemmeng dagiti bassit a panagbaliw kadagiti naudi a sinuk-sukatan",
-       "tog-hidepatrolled": "Ilemmeng dagiti napatruliaan nga inurnos kadagiti naudi a sinuk-sukatan",
+       "tog-hideminor": "Ilemmeng dagiti bassit a inurnos iti kaudian a balbaliw",
+       "tog-hidepatrolled": "Ilemmeng dagiti napatruliaan nga inurnos iti kaudian a balbaliw",
        "tog-newpageshidepatrolled": "Ilemmeng dagiti napatruliaan a panid manipud ti baro a listaan ti panid",
-       "tog-extendwatchlist": "Ipalawa ti listaan ti bambantayan tapno maipakita amin a nasukatan, tapno saan laeng a dagiti nabiit",
-       "tog-usenewrc": "Dagiti grupo a panagbaliw babaen ti panid kadagiti kinaudi a panagbaliw ken banbantayan",
+       "tog-extendwatchlist": "Ipalawa ti listaan ti bambantayan tapno maipakita amin a nasukatan, saan laeng a ti kabiitan",
+       "tog-usenewrc": "Dagiti grupo a panagbaliw babaen ti panid ti kaudian a balbaliw ken listaan ti bambantayan",
        "tog-numberheadings": "Automatiko a pabilangan dagiti paulo",
        "tog-showtoolbar": "Ipakita ti baras ti ramit ti panag-urnos",
        "tog-editondblclick": "Urnosen dagiti panid iti mamindua a panagpindut",
-       "tog-editsectiononrightclick": "Pakabaelan ti panag-urnos ti paset babaen ti kanawan a panagpindut kadagiti titulo ti paset",
-       "tog-watchcreations": "Agnayon kadagiti panid a pinartuatko ken papeles nga inkargak idiay listaan ti bambantayak",
-       "tog-watchdefault": "Agnayon kadagiti panid ken papeles nga inurnosko idiay listaan ti bambantayak",
-       "tog-watchmoves": "Agnayon kadagiti panid ken papeles nga inyalisko idiay listaan ti bambantayak",
-       "tog-watchdeletion": "Agnayon kadagiti panid ken papeles nga inikkatko idiay listaan ti bambantayak",
-       "tog-minordefault": "Markaan amin nga inurnos a kas sigud a bassit",
+       "tog-editsectiononrightclick": "Pakabaelan ti panag-urnos iti paset babaen ti panagpindut iti kanawan kadagiti titulo ti paset",
+       "tog-watchcreations": "Agnayon kadagiti panid a pinartuatko ken papeles nga inkargak iti listaan ti bambantayak",
+       "tog-watchdefault": "Agnayon kadagiti panid ken papeles nga inurnosko iti listaan ti bambantayak",
+       "tog-watchmoves": "Agnayon kadagiti panid ken papeles nga inyalisko iti listaan ti bambantayak",
+       "tog-watchdeletion": "Agnayon kadagiti panid ken papeles nga inikkatko iti listaan ti bambantayak",
+       "tog-minordefault": "Markaan amin dagiti inurnos a kas bassit babaen ti kasisigud",
        "tog-previewontop": "Ipakita ti panagipadas sakbay ti pagurnosan a kahon",
        "tog-previewonfirst": "Ipakita ti pinadas iti umuna a panag-urnos",
-       "tog-enotifwatchlistpages": "Esuratannak no mabaliwan ti panid wenno papeles idiay listaan dagiti bambantayak",
+       "tog-enotifwatchlistpages": "Esuratannak no mabaliwan ti panid wenno papeles iti listaan dagiti bambantayak",
        "tog-enotifusertalkpages": "Esuratannak no mabaliwan ti panid ti tungtungak",
        "tog-enotifminoredits": "Esuratannak pay para kadagiti bassit a panag-urnos kadagiti panid ken papeles",
-       "tog-enotifrevealaddr": "Iparang ti pagtaengan ti esuratko kadagiti panagipakaaammo nga esurat",
+       "tog-enotifrevealaddr": "Iparang ti pagtaengan ti esuratko iti panagipakaaammo kadagiti esurat",
        "tog-shownumberswatching": "Ipakita ti bilang dagiti agbuybuya nga agar-aramat",
        "tog-oldsig": "Ti adda a pirma:",
-       "tog-fancysig": "Tratuen ti pirma a kas wikitext (nga awan ti automatiko a panagsilpo)",
-       "tog-uselivepreview": "Usaren ti agdama a panagipadas (eksperimento)",
-       "tog-forceeditsummary": "Pakaammuannak no sumrek ti blanko a pakabuklan ti panag-urnos",
+       "tog-fancysig": "Tratuen ti pirma a kas wikitext (nga awan ti automatiko a silpo)",
+       "tog-uselivepreview": "Usaren ti agdama a panagipadas (eksperimental)",
+       "tog-forceeditsummary": "Pakaammuannak no sumrek iti blanko a pakabuklan ti panag-urnos",
        "tog-watchlisthideown": "Ilemmeng dagiti inurnosko manipud ti listaan ti bambantayan",
        "tog-watchlisthidebots": "Ilemmeng dagiti inurnos ti bot manipud ti listaan ti bambantayan",
        "tog-watchlisthideminor": "Ilemmeng dagiti bassit nga inurnos manipud ti listaan ti bambantayan",
-       "tog-watchlisthideliu": "Ilemmeng dagiti inurnos ti nakasterk nga agar-aramat manipud ti listaan ti bambantayan",
-       "tog-watchlisthideanons": "Ilemmeng dagiti inurnos ti di am-ammo nga agar-aramat manipud ti listaan ti bambantayan",
+       "tog-watchlisthideliu": "Ilemmeng dagiti inurnos babaen dagiti nakastrek nga agar-aramat manipud ti listaan ti bambantayan",
+       "tog-watchlisthideanons": "Ilemmeng dagiti inurnos babaen dagiti di ammo nga agar-aramat manipud ti listaan ti bambantayan",
        "tog-watchlisthidepatrolled": "Ilemmeng dagiti napatruliaan nga inurnos manipud ti listaan ti bambantayan",
-       "tog-ccmeonemails": "Patulodandak kadagiti kopia ti esurat nga ipatulodko kadagiti sabsabali nga agar-aramat",
+       "tog-ccmeonemails": "Patulodandak kadagiti kopia ti esurat nga ipatulodko kadagiti sabali nga agar-aramat",
        "tog-diffonly": "Saan nga iparang ti linaon ti panid dita baba dagiti pagiddiatan",
        "tog-showhiddencats": "Ipakita dagiti nailemmeng a kategoria",
        "tog-norollbackdiff": "Laksiden ti paggiddiatan kalpasan ti panagaramid ti panagisubli",
-       "tog-useeditwarning": "Pakaunaannak no pumanawak iti maysa pagurnosan a panid no adda ti saan a naidulin a sinuksukatan",
-       "tog-prefershttps": "Kankanayon nga agusar ti natalged a pannakaisilpo no nakastrek",
+       "tog-useeditwarning": "Pakaunaannak no pumanawak iti maysa pagurnosan a panid nga addaan iti saan a naidulin a sinuksukatan",
+       "tog-prefershttps": "Kankanayon nga agusar ti natalged a koneksion no nakastrek",
        "underline-always": "Kanayon",
        "underline-never": "Saan uray kaanoman",
-       "underline-default": "Kasisigud a kudil wenno pagbasabasa",
-       "editfont-style": "Urnosen ti kita ti letra iti lugar:",
+       "underline-default": "Kudil wenno kasisigud a pagbasabasa",
+       "editfont-style": "Estilo ti kita ti letra ti pagurnosan a lugar:",
        "editfont-default": "Kasisigud a pagbasabasa",
        "editfont-monospace": "Monospaced a kita ti letra",
        "editfont-sansserif": "Sans-serif a kita ti letra",
        "editfont-serif": "Serif a kita ti letra",
-       "sunday": "Dominggo",
+       "sunday": "Domingo",
        "monday": "Lunes",
        "tuesday": "Martes",
        "wednesday": "Mierkoles",
@@ -66,9 +66,9 @@
        "sun": "Dom",
        "mon": "Lun",
        "tue": "Mar",
-       "wed": "Mie",
+       "wed": "Mier",
        "thu": "Hue",
-       "fri": "Bie",
+       "fri": "Bier",
        "sat": "Sab",
        "january": "Enero",
        "february": "Pebrero",
        "category_header": "Pampanid iti kategoria \"$1\"",
        "subcategories": "Dagiti subkategoria",
        "category-media-header": "Dagiti midia iti kategoria \"$1\"",
-       "category-empty": "''Daytoy a kategoria ket agdama a saan nga aglaon kadagiti panid wenno midia.''",
+       "category-empty": "<em>Daytoy a kategoria ket agdama a saan nga aglaon kadagiti panid wenno midia.</em>",
        "hidden-categories": "{{PLURAL:$1|Nailemmeng a kategoria|Nailemmeng a katkategoria}}",
        "hidden-category-category": "Nailemmeng a katkategoria",
-       "category-subcat-count": "{{PLURAL:$2|Daytoy a kategoria ket adda laeng ti sumaganad a subkategoria.|Daytoy a kategoria ket addaan ti sumaganad a {{PLURAL:$1|a subkategoria|$1 a subkatkategoria}}, manipud ti $2 a dagup.}}",
+       "category-subcat-count": "{{PLURAL:$2|Daytoy a kategoria ket addaan laeng ti sumaganad a subkategoria.|Daytoy a kategoria ket addaan ti sumaganad a {{PLURAL:$1|a subkategoria|$1 a subkatkategoria}}, manipud ti $2 a dagup.}}",
        "category-subcat-count-limited": "Daytoy a kategoria ket addaan ti sumaganad a {{PLURAL:$1|a subkategoria|$1 a subkatkategoria}}.",
        "category-article-count": "{{PLURAL:$2|Daytoy a kategoria ket aglaon laeng ti sumaganad a panid.|Ti sumaganad a {{PLURAL:$1|a panid ket|$1 a pampanid ket dagiti}} adda iti daytoy a kategoria, manipud ti $2 a dagup.}}",
        "category-article-count-limited": "Ti sumaganad a {{PLURAL:$1|panid |$1 a pampanid}} ket adda iti agdama a kategoria.",
        "category-file-count-limited": "Ti sumaganad a {{PLURAL:$1|papeles|$1 a pappapeles}} ket adda iti agdama a kategoria.",
        "listingcontinuesabbrev": "tuloy.",
        "index-category": "Naipagsurotan a pampanid",
-       "noindex-category": "Di naipasurotan a pampanid",
-       "broken-file-category": "Pampanid nga adda nadadael a silsilpo kadagiti papeles",
+       "noindex-category": "Di naipagsurotan a pampanid",
+       "broken-file-category": "Pampanid nga addaan kadagiti nadadael a silpo ti papeles",
        "about": "Maipanggep",
        "article": "Naglaon a panid",
-       "newwindow": "(aglukat iti sabali a tawa)",
+       "newwindow": "(aglukat iti baro a tawa)",
        "cancel": "Ukasen",
        "moredotdotdot": "Adu pay...",
        "morenotlisted": "Daytoy a listaan ket saan a kompleto.",
        "actions": "Dagiti aramid",
        "namespaces": "Dagiti nagan ti espasio",
        "variants": "Sab-sabali a pagsasao",
-       "navigation-heading": "Pagdaliasatan ti pagpilian",
+       "navigation-heading": "Listaan ti pagdaliasatan",
        "errorpagetitle": "Biddut",
        "returnto": "Agsubli idiay $1.",
        "tagline": "Naggapo idiay {{SITENAME}}",
        "view-foreign": "Kitaen idiay $1",
        "edit": "Urnosen",
        "edit-local": "Urnosen ti lokal a deskripsion",
-       "create": "Agaramid",
+       "create": "Agpartuat",
        "create-local": "Agnayon ti lokal a deskripsion",
        "editthispage": "Urnosen daytoy a panid",
        "create-this-page": "Partuaten daytoy a panid",
        "talkpagelinktext": "Tungtungan",
        "specialpage": "Espesial a panid",
        "personaltools": "Bukod a ram-ramit",
-       "postcomment": "Baro a paset",
        "articlepage": "Kitaen ti naglaon a panid",
        "talk": "Pagtungtungan",
        "views": "Dagiti pangkitaan",
        "categorypage": "Kitaen ti panid ti kategoria",
        "viewtalkpage": "Kitaen ti pagtungtungan",
        "otherlanguages": "Kadagiti sabali a pagsasao",
-       "redirectedfrom": "(Naibaw-ing manipud idiay $1)",
+       "redirectedfrom": "(Naibaw-ing manipud iti $1)",
        "redirectpagesub": "Baw-ing a panid",
-       "lastmodifiedat": "Daytoy a panid ket naudi a nabaliwan idi $1, idi $2.",
-       "viewcount": "Naserrekan daytoy a panid {{PLURAL:$1|iti naminsan|kadagiti $1 a beses}}.",
+       "lastmodifiedat": "Daytoy a panid ket naudi a nabaliwan idi $1, $2.",
+       "viewcount": "Naserrekanen daytoy a panid {{PLURAL:$1|iti naminsan|kadagiti $1 a beses}}.",
        "protectedpage": "Nasalakniban a panid",
        "jumpto": "Lumaktaw idiay:",
        "jumptonavigation": "pagdaliasatan",
        "jumptosearch": "biruken",
-       "view-pool-error": "Pasensian, dagiti servers ket nadagsenan unay tattan.\nAdu unay dagiti agar-aramat nga agbuy-buya ti daytoy a panid.\nPangaasi nga agurayka met bassit sakbay a padasem manen ti mangserrek daytoy a panid.\n\n$1",
-       "generic-pool-error": "Pasensian, dagiti server ket agdama a nadagsenan unay.\nAdu unay dagiti agar-aramat nga agbuybuya ti daytoy a rekurso.\nPangngaasi nga agurayka bassit sakbay a padasem manen a serrekan daytoy a rekurso.",
+       "view-pool-error": "Pasensian, dagiti server ket nadagsenan unay iti agdama.\nAdu unay dagiti agar-aramat nga agpadpadas nga agbuya iti daytoy a panid.\nPangngaasi nga agurayka bassit sakbay a padasem manen a serrekan daytoy a panid.\n\n$1",
+       "generic-pool-error": "Pasensian, dagiti server ket agdama a nadagsenan iti agdama.\nAdu unay dagiti agar-aramat nga agpadpadas nga agbuya iti daytoy a rekurso.\nPangngaasi nga agurayka bassit sakbay a padasem manen a serrekan daytoy a rekurso.",
        "pool-timeout": "Madamdama agur-uray para iti kandado",
-       "pool-queuefull": "Napunnon ti nagyanan ti pagur-urayan",
-       "pool-errorunknown": "Di am-ammo a biddut",
-       "pool-servererror": "Ti serbisio ti pagbilangan ti pisina ket saan a magun-od ($1).",
+       "pool-queuefull": "Napunnon ti pagyanan ti pagur-urayan",
+       "pool-errorunknown": "Di ammo a biddut",
+       "pool-servererror": "Ti serbisio ti pagbilangan ti pagyanan ti pagur-urayan ket saan a magun-od ($1).",
        "aboutsite": "Maipanggep ti {{SITENAME}}",
        "aboutpage": "Project:Maipanggep",
        "copyright": "Ti linaon ket magun-od babaen ti $1 malaksid no adda sabali a naibaga.",
        "privacypage": "Project:Annuroten ti kinapribado",
        "badaccess": "Biddut ti pammalubos",
        "badaccess-group0": "Awan pammalubosmo a mangpataray ti kiniddawmo nga aramid.",
-       "badaccess-groups": "Ti kiniddawmo nga aramid ket limitado laeng kadagiti agar-aramat {{PLURAL:$2|iti grupo|iti maysa kadagiti grupo}}: ti $1.",
+       "badaccess-groups": "Ti kiniddawmo nga aramid ket limitado laeng kadagiti agar-aramat {{PLURAL:$2|iti grupo|iti maysa kadagiti grupo}}: $1.",
        "versionrequired": "Masapul ti bersion $1 ti MediaWiki",
        "versionrequiredtext": "Masapul ti bersion $1 ti MediaWiki tapno maaramat daytoy a panid. \nKitaen ti [[Special:Version|panid ti bersion]].",
        "ok": "Sige",
        "retrievedfrom": "Naala manipud idiay \"$1\"",
-       "youhavenewmessages": "Addaanka ti $1 ($2).",
-       "youhavenewmessagesfromusers": "Adda $1 manipud {{PLURAL:$3|ti sabali nga agar-aramat|kadagiti $3 a sabsabali nga agar-aramat}} ($2).",
-       "youhavenewmessagesmanyusers": "Adda $1 manipud kadagiti adu nga agar-aramat ($2).",
-       "newmessageslinkplural": "{{PLURAL:$1|a baro a mensahem|999=a baro a menmensahem}}",
-       "newmessagesdifflinkplural": "kinaudi a {{PLURAL:$1|sinukatan|999=sinuksukatan}}",
-       "youhavenewmessagesmulti": "Adda dagiti baro a mensahem iti $1",
+       "youhavenewmessages": "{{PLURAL:$3|Addaanka}} $1 ($2).",
+       "youhavenewmessagesfromusers": "{{PLURAL:$4|Addaanka}} $1 manipud {{PLURAL:$3|ti sabali nga agar-aramat|kadagiti $3 a sabali nga agar-aramat}} ($2).",
+       "youhavenewmessagesmanyusers": "Addaanka $1 manipud kadagiti adu nga agar-aramat ($2).",
+       "newmessageslinkplural": "{{PLURAL:$1|iti baro a mensahe|999=kadagiti baro a mensahe}}",
+       "newmessagesdifflinkplural": "naudi a {{PLURAL:$1|sinukatan|999=sinuksukatan}}",
+       "youhavenewmessagesmulti": "Addaanka kadagiti baro a mensahe iti $1",
        "editsection": "urnosen",
        "editold": "urnosen",
        "viewsourceold": "kitaen ti taudan",
        "hidetoc": "ilemmeng",
        "collapsible-collapse": "Rebbaen",
        "collapsible-expand": "Palawaen",
-       "thisisdeleted": "Kitaen wenno isubli ti $1?",
-       "viewdeleted": "Kitaen ti $1?",
+       "thisisdeleted": "Kitaen wenno ipulang $1?",
+       "viewdeleted": "Kitaen $1?",
        "restorelink": "{{PLURAL:$1|ti maysa a naikkat a naurnos|dagiti $1 a naikkat a naurnos}}",
        "feedlinks": "Pakan:",
        "feed-invalid": "Imbalido a kita ti suskrision a pakan.",
        "feed-unavailable": "Saan a magun-od dagiti sindikasion ti pakan",
-       "site-rss-feed": "$1 a pakan ti RSS",
-       "site-atom-feed": "$1 a pakan ti Atom",
-       "page-rss-feed": "\"$1\" a pakan ti RSS",
-       "page-atom-feed": "Pakan nga Atom ti \"$1\"",
+       "site-rss-feed": "Pakan ti RSS ti $1",
+       "site-atom-feed": "Pakan ti Atom ti $1",
+       "page-rss-feed": "Pakan ti RSS ti \"$1\"",
+       "page-atom-feed": "Pakan ti Atom ti \"$1\"",
        "red-link-title": "$1 (awan ti panid)",
        "sort-descending": "Ilasin nga agpababa",
        "sort-ascending": "Ilasin nga agpangato",
        "nstab-help": "Panid ti tulong",
        "nstab-category": "Kategoria",
        "nosuchaction": "Awan ti kasta nga aramid",
-       "nosuchactiontext": "Ti tignay a nainaganan babaen ti URL ket imbalido.\nMabalin a madi ti naimakiniliam nga URL, wenno sinurotmo ti saan nga agpayso a silpo.\nMabalin a daytoy ket kiteb ti sopwer nga us-usaren babaen ti {{SITENAME}}.",
+       "nosuchactiontext": "Ti aramid a nainaganan babaen ti URL ket imbalido.\nMabalin a madi ti naimakiniliam nga URL, wenno sinurotmo ti saan a nasayaat a silpo.\nMabalinmo pay nga ibaga ti parikut ti sopwer nga us-usaren babaen ti {{SITENAME}}.",
        "nosuchspecialpage": "Awan ti kasta nga espesial a panid",
-       "nospecialpagetext": "<strong>Nagkiddawka ti imbalido nga espesial a panid.</strong>\n\nMasarakan ti listaan dagiti umisu nga espesial a pampanid iti [[Special:SpecialPages|{{int:specialpages}}]].",
+       "nospecialpagetext": "<strong>Nagkiddawka ti imbalido nga espesial a panid.</strong>\n\nTi listaan dagiti umisu nga espesial a pampanid ket mabirukan iti [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Biddut",
        "databaseerror": "Biddut iti database",
-       "databaseerror-text": "Adda napasamak a biddut ti usisa ti database.\nDaytoy ket mabalin a mangibagbaga ti parikut ti sopwer.",
-       "databaseerror-textcl": "Adda napasamak a biddut ti usisa ti database.",
+       "databaseerror-text": "Adda napasamak a biddut ti panagusisa ti database.\nDaytoy ket mabalin a mangibagbaga ti parikut ti sopwer.",
+       "databaseerror-textcl": "Adda napasamak a biddut ti pangusisa ti database.",
        "databaseerror-query": "Usisa: $1",
        "databaseerror-function": "Annong: $1",
        "databaseerror-error": "Biddut: $1",
-       "laggedslavemode": "'''Ballaag:''' Ti panid ket mabalin a saan nga aglaon kadagiti kinaudi a panagpabaro.",
+       "laggedslavemode": "<strong>Ballaag:</strong> Ti panid ket mabalin a saan nga aglaon kadagiti kinaudi a panagpabaro.",
        "readonly": "Narikepan ti database",
-       "enterlockreason": "Agikabil ti rason para iti pannakarikep, agraman ti maysa a karkulo no kaanonto a maluktan",
-       "readonlytext": "Ti database ket agdama a nairikpan kadagiti baro a panagikabil ken panagbaliw, mabalin a gapu dagiti kadawyan a pagsimpa, no malpas kadawyanto nga agsubli.\n\nTi administrador a nangrikep ket nangited ti daytoy a palawag: $1",
-       "missing-article": "Ti database ket saan a nakabiruk ti testo ti panid a mabirukanna koma, a napanaganan ti \"$1\" $2.\n\nDaytoy ket kadawyan a gapuanan babaen ti sumaganad a baak a paggiddiatan wenno silpo ti pakasaritaan ti maysa panid a dati a naikkat.\n\nNo saan a kasta, mabalin a nakasarakka ti kiteb ti sopwer.\n\nPangngaasi nga ipadamagmo kadagiti [[Special:ListUsers/sysop|administrador]], isuratmo ti pakaammo dayta nga URL.",
-       "missingarticle-rev": "(binaliwan#: $1)",
-       "missingarticle-diff": "(Sabali: $1, $2)",
-       "readonly_lag": "Automatiko a narikpan ti database kabayatan a dagiti tagabu a database server ket kumamakam iti agturay",
+       "enterlockreason": "Agikabil ti rason para iti pannakarikep, mangiraman ti maysa a karkulo no kaanonto a malukatan",
+       "readonlytext": "Ti database ket agdama a narikpan kadagiti baro a panagikabil ken panagbaliw, mabalin a gapu dagiti kadawyan a pagsimpa, kalpasanna a normalto nga agsubli.\n\nTi administrador a nangrikep ket nangited iti daytoy a palawag: $1",
+       "missing-article": "Ti database ket saan a nakabiruk ti testo ti panid a mabirukanna koma, a nanaganan ti \"$1\" $2.\n\nDaytoy ket kadawyan a gapuanan babaen ti sumaganad a baak a paggiddiatan wenno silpo ti pakasaritaan ti maysa panid a dati a naikkat.\n\nNo saan a kasta, mabalin a nakasarakka ti parikut ti sopwer.\n\nPangngaasi nga ipadamagmo kadagiti [[Special:ListUsers/sysop|administrador]], isuratmo ti pakaammo dayta nga URL.",
+       "missingarticle-rev": "(rebision#: $1)",
+       "missingarticle-diff": "(Dip: $1, $2)",
+       "readonly_lag": "Automatiko a narikpan ti database kabayatan a dagiti tagabu a server ti database ket kumamakam iti agturay",
        "internalerror": "Akin-uneg a biddut",
        "internalerror_info": "Akin-uneg a biddut: $1",
        "filecopyerror": "Saan a makopia ti papeles $1 iti $2.",
        "filerenameerror": "Saan a managanan manen ti papeles \"$1\" iti \"$2\".",
-       "filedeleteerror": "Saan a maikkat ti papeles  \"$1\".",
-       "directorycreateerror": "Saan a maaramid ti direktorio \"$1\".",
+       "filedeleteerror": "Saan a maikkat ti papeles \"$1\".",
+       "directorycreateerror": "Saan a mapartuat ti direktorio \"$1\".",
        "filenotfound": "Saan a mabirukan ti papeles \"$1\".",
-       "unexpected": "Di mapakpakadaaan a pateg: \"$1\"=\"$2\".",
+       "unexpected": "Di nanamnama a pateg: \"$1\"=\"$2\".",
        "formerror": "Biddut: saan a maited ti porma.",
        "badarticleerror": "Saan a matungpal daytoy nga aramid iti daytoy a panid.",
-       "cannotdelete": "Ti panid wenno ti papeles \"$1\" ket saan a maikkat.\nAmangan no adda sabali a nangikkaten.",
-       "cannotdelete-title": "Saan a maikkat ti panid  \"$1\"",
-       "delete-hook-aborted": "Inukas ti kawit ti panagborra.\nAwan ti intedna a palawag.",
-       "no-null-revision": "Saan a makaaramid ti awan serbina a panagbaliw para iti panid \"$1\"",
+       "cannotdelete": "Ti panid wenno papeles ti \"$1\" ket saan a maikkat.\nAmangan no adda sabali a nangikkaten.",
+       "cannotdelete-title": "Saan a maikkat ti panid ti \"$1\"",
+       "delete-hook-aborted": "Pinasardeng ti panagikkat babaen ti kawit.\nAwan ti intedna a palawag.",
+       "no-null-revision": "Saan a makapartuat ti awan serbina a panagbaliw para iti panid ti \"$1\"",
        "badtitle": "Madi a titulo",
-       "badtitletext": "Ti kiniddaw idi a titulo ti panid ket imbalido, blanko, wenno maysa a saan nga husto a naisilpo a silpo ti pagsasao wenno interwiki a titulo.\nMabalin nga aglaon ti a maysa wenno ad-adu a karakter a saan a mausar kadagiti titulo.",
+       "badtitletext": "Ti kiniddaw idi a titulo ti panid ket imbalido, blanko, wenno maysa a saan a husto a naisilpo a silpo ti pagsasao wenno interwiki a titulo.\nMabalin nga aglaon ti a maysa wenno ad-adu a karakter a saan a mausar kadagiti titulo.",
        "perfcached": "Ti sumaganad a datos ket naidulin ken mabalin a saan a napabaro. Ti kaadu {{PLURAL:$1|iti maysa a nagbanagan|dagiti $1 a nagbanagan}} ket magun-od idiay nagidulinan.",
-       "perfcachedts": "Ti sumaganad a datos ket naidulin, ken naudi a napabaro idi $1. Ti kaadu a {{PLURAL:$4|iti maysa a nagbanagan |dagiti $4 nagbanagan}} ket magun-od idiay pagidulinan.",
-       "querypage-no-updates": "Dagiti panangpabaro iti daytoy a panid ket agdama a nabaldado. \nSaan a mipasaradiwa ita dagiti datos ditoy.",
+       "perfcachedts": "Ti sumaganad a datos ket naidulin, ken naudi a napabaro idi $1. Ti kaadu a {{PLURAL:$4|iti maysa a nagbanagan|dagiti $4 nagbanagan}} ket magun-od idiay pagidulinan.",
+       "querypage-no-updates": "Dagiti panangpabaro iti daytoy a panid ket agdama a nabaldado. \nSaan a mapasadiwa ita dagiti datos ditoy.",
        "viewsource": "Kitaen ti taudan",
        "viewsource-title": "Kitaen ti taudan para iti $1",
        "actionthrottled": "Napabuntog ti aramid",
        "actionthrottledtext": "Para iti pagkontra ti spam, naipatinggaka nga agramid iti daytoy a tignay iti adu unay a beses iti nasiket nga oras, ken nalabsamon daytoy a patingga.\nPangngaasi nga ipadasmo manen no madamdama.",
        "protectedpagetext": "Nasalakniban daytoy a panid tapno mapawilan ti panag-urnos wenno dagiti dadduma pay a tignay.",
        "viewsourcetext": "Mabalinmo a kitaen ken tuladen ti taudan daytoy a panid:",
-       "viewyourtext": "Mabalinmo a makita ken tuladen ti taudan dagiti '''inurnosmo''' ditoy a panid:",
-       "protectedinterface": "Daytoy a panid ket mangited ti testo nga interface para iti sopwer iti daytoy a wiki, ken nasalakniban tapno mapawilan ti panag-abuso.\nTi aginayon wenno panagibaliw kadagiti panagipatarus para kadagiti amin a wiki,  pangngaasi nga usaren ti [//translatewiki.net/ translatewiki.net], ti lokalisasion a gandat ti MediaWiki.",
-       "editinginterface": "'''Ballaag:''' Ur-urnosem ti maysa a panid a maar-aramat a mangted iti testo ti interface para iti sopwer.\nDagiti panagsukat iti daytoy a panid ket maarigan ti langa ti panagaramat nga interface dagiti sabali nga agar-aramat iti daytoy a wiki.\nTi aginayon wenno panagibaliw kadagiti panagipatarus para kadagiti amin a wiki,  pangngaasi nga usaren ti [//translatewiki.net/ translatewiki.net], ti lokalisasion a gandat ti MediaWiki.",
-       "cascadeprotected": "Daytoy a panid ket nasalakniban para iti panag-urnos ngamin ket nairaman kadagiti sumaganad {{PLURAL:$1|a panid, a|a pampanid, a}} nasalakniban nga adda ti napili nga \"agsariap\"  :\n$2",
-       "namespaceprotected": "Awan ti pammalubosmo nga agurnos kadagiti panid iti '''$1''' a nagan ti espasio.",
-       "customcssprotected": "Awan ti pammalubosmo nga agurnos iti daytoy panid ti CSS, ngamin ket adda linaonna a tagikua dagiti agar-aramat ti sabali a kasasaad.",
-       "customjsprotected": "Awan ti pammalubosmo nga agurnos iti daytoy a panid ti JavaScript, ngamin ket adda linaonna a tagikua dagiti agar-aramat ti sabali a kasasaad.",
+       "viewyourtext": "Mabalinmo a makita ken tuladen ti taudan dagiti <strong>inurnosmo</strong> iti daytoy panid:",
+       "protectedinterface": "Daytoy a panid ket mangited ti testo ti interface para iti sopwer iti daytoy a wiki, ken nasalakniban tapno mapawilan ti panag-abuso.\nTi aginayon wenno panagibaliw kadagiti panagipatarus para kadagiti amin a wiki,  pangngaasi nga usaren ti [//translatewiki.net/ translatewiki.net], ti lokalisasion a gandat ti MediaWiki.",
+       "editinginterface": "<strong>Ballaag:</strong> Ur-urnosem ti maysa a panid a maar-aramat a mangted iti testo ti interface para iti sopwer.\nDagiti panagsukat iti daytoy a panid ket maarigan ti langa ti interface ti agar-aramat para kadagiti sabali nga agar-aramat iti daytoy a wiki.\nTi aginayon wenno panagibaliw kadagiti panagipatarus para kadagiti amin a wiki,  pangngaasi nga usaren ti [//translatewiki.net/ translatewiki.net], ti lokalisasion a gandat ti MediaWiki.",
+       "cascadeprotected": "Daytoy a panid ket nasalaknibanen para iti panag-urnos ngamin ket nairaman kadagiti sumaganad {{PLURAL:$1|a panid, a|a pampanid, a}} nasalakniban iti nalukatan a pagpilian ti \"sariap\":\n$2",
+       "namespaceprotected": "Awan ti pammalubosmo nga agurnos kadagiti panid iti nagan ti espasio ti <strong>$1</strong>.",
+       "customcssprotected": "Awan ti pammalubosmo nga agurnos iti daytoy panid ti CSS, ngamin ket naglaon ti personal a pannakaisaad iti sabali agar-aramat.",
+       "customjsprotected": "Awan ti pammalubosmo nga agurnos iti daytoy a panid ti JavaScript, ngamin ket naglaon ti personal a pannakaisaad iti sabali agar-aramat.",
        "mycustomcssprotected": "Awan pammalubosmo nga agurnos iti daytoy a panid ti CSS.",
        "mycustomjsprotected": "Awan pammalubosmo nga agurnos iti daytoy a panid ti JavaScript.",
        "myprivateinfoprotected": "Awan pammalubosmo nga agurnos iti pribado a pakaammom.",
        "mypreferencesprotected": "Awan pammalubosmo nga agurnos kadagiti kakaykayatam.",
        "ns-specialprotected": "Saan a mabalin nga urnosen dagiti espesial a panid.",
-       "titleprotected": "Daytoy a titulo ket nasalakniban manipud ti panakapartuat babaen ni [[User:$1|$1]].\nTi naited a rason ket ''$2''.",
-       "filereadonlyerror": "Di nabaliwan ti papeles \"$1\" gapu ket ti repositorio ti papeles \"$2\" ket mabasa laeng a moda.\n\nTi administrador a nangserra ket nagited iti daytoy a panagilawlawag \"''$3''\".",
+       "titleprotected": "Daytoy a titulo ket nasalakniban manipud ti pannakapartuat babaen ni [[User:$1|$1]].\nTi naited a rason ket \"<em>$2</em>\".",
+       "filereadonlyerror": "Di nabaliwan ti papeles ti \"$1\" gapu ket ti repositorio ti papeles ti \"$2\" ket mabasa laeng a moda.\n\nTi administrador a nangserra ket nangited iti daytoy a panagilawlawag \"''$3''\".",
        "invalidtitle-knownnamespace": "Imbalido a titulo iti nagan ti espasio \"$2\" ken testo \"$3\"",
-       "invalidtitle-unknownnamespace": "Imbalido a titulo iti di-amammo a nagan ti espasio a numero $1 ken testo \"$2\"",
+       "invalidtitle-unknownnamespace": "Imbalido a titulo iti di ammo a nagan ti espasio a bilang $1 ken testo \"$2\"",
        "exception-nologin": "Saan a nakastrek",
        "exception-nologin-text": "Pangngaasi a [[Special:Userlogin|sumrek]] tapno maserrekam daytoy a panid wenno tignay.",
        "exception-nologin-text-manual": "Pangngaasi a $1 tapno maserrekan daytoy a panid wenno tignay.",
-       "virus-badscanner": "Madi di panaka-aramidna: Di am-ammo a birus a panagskan: \"$1\"",
-       "virus-scanfailed": "napaay ti panagskan (kodigo $1)",
-       "virus-unknownscanner": "di am-ammo a pagpaksiat ti \"birus\":",
-       "logouttext": "'''Nakaruarkan.'''\n\nLaglagipen nga adda met dagiti panid nga agtultuloy a maiparang a kasla nakastreka pay, aginggana no dalusam ti pannakaidulin ti pagbasabasam.",
+       "virus-badscanner": "Madi ti konpigurasion: Di ammo a panagsukimat ti birus: <em>$1</em>",
+       "virus-scanfailed": "napaay ti panagsukimat (kodigo $1)",
+       "virus-unknownscanner": "di ammmo nga antibirus:",
+       "logouttext": "<strong>Nakaruarkan.</strong>\n\nLaglagipen nga adda met dagiti panid nga agtultuloy a maiparang a kasla nakastrekka pay, aginggana no dalusam ti pannakaidulin ti pagbasabasam.",
        "welcomeuser": "Naragsak nga isasangbay, $1!",
-       "welcomecreation-msg": "Naaramiden ti pakabilangam.\nDimo liplipatan a sukatan dagiti kakaykayatam idiay [[Special:Preferences|{{SITENAME}} kakaykayatan]].",
+       "welcomecreation-msg": "Napartuaten ti pakabilangam.\nNo kayatmo mabaliwamon dagiti [[Special:Preferences|kakaykayatam]] ti {{SITENAME}}.",
        "yourname": "Nagan ti agar-aramat:",
        "userlogin-yourname": "Nagan ti agar-aramat",
        "userlogin-yourname-ph": "Ikabil ti naganmo nga agar-aramat",
        "yourpassword": "Kontrasenias:",
        "userlogin-yourpassword": "Kontrasenias",
        "userlogin-yourpassword-ph": "Ikabilmo ti kontrasenias",
-       "createacct-yourpassword-ph": "Agikabil ti kontrasenias",
-       "yourpasswordagain": "Uliten ti kontrasenias:",
+       "createacct-yourpassword-ph": "Ikabil ti kontrasenias",
+       "yourpasswordagain": "Imakinilya manen ti kontrasenias:",
        "createacct-yourpasswordagain": "Pasingkedan ti kontrasenias",
        "createacct-yourpasswordagain-ph": "Ikabil manen ti kontrasenias",
        "remembermypassword": "Laglagipem ti iseserrekko iti daytoy a pagbasabasa (para iti kapaut iti $1 {{PLURAL:$1|nga aldaw|nga al-aldaw}})",
        "userlogin-remembermypassword": "Taginayonennak nga iserrek",
-       "userlogin-signwithsecure": "Usaren ti natalged a pannakaisilpo",
-       "yourdomainname": "Ti bukodmo a pagturayan:",
-       "password-change-forbidden": "Saanmo a mabalin ti mangbaliw kadagiti kontrasenias iti daytoy a wiki.",
-       "externaldberror": "Adda biddut idi ti panakapasingked ti database wenno saanmo a mabalin ti agpabaro ti bukodmo nga akin-ruar a pakabilangan.",
+       "userlogin-signwithsecure": "Usaren ti natalged a koneksion",
+       "yourdomainname": "Ti bukodmo a dominio:",
+       "password-change-forbidden": "Saanmo a mabaliwan dagiti kontrasenias iti daytoy a wiki.",
+       "externaldberror": "Mabalin nga adda biddut iti pannakapasingked ti database wenno saanka a mapalubosan a mangpabaro ti akin-ruar a pakabilangam.",
        "login": "Sumrek",
-       "nav-login-createaccount": "Sumrek / agaramid ti pakabilangan",
-       "loginprompt": "Nasken a napakabaelam dagiti \"galietas\" tapno makastrekka iti {{SITENAME}}.",
-       "userlogin": "Sumrek / agaramid ti pakabilangan",
+       "nav-login-createaccount": "Sumrek / agpartuat ti pakabilangan",
+       "userlogin": "Sumrek / agpartuat ti pakabilangan",
        "userloginnocreate": "Sumrek",
        "logout": "Rummuar",
        "userlogout": "Rummuar",
        "userlogin-noaccount": "Awan ti pakabilangam?",
        "userlogin-joinproject": "Tumipon iti {{SITENAME}}",
        "nologin": "Awan pakabilangam? $1.",
-       "nologinlink": "Agaramid ti pakabilangan",
-       "createaccount": "Agaramid ti pakabilangan",
-       "gotaccount": "Addaanka kadin ti pakabilangam? $1.",
+       "nologinlink": "Agpartuat ti pakabilangan",
+       "createaccount": "Agpartuat ti pakabilangan",
+       "gotaccount": "Addaanka kadin iti pakabilangan? $1.",
        "gotaccountlink": "Sumrek",
-       "userlogin-resetlink": "Nalipatam dagiti salaysay ti pagserrekmo?",
+       "userlogin-resetlink": "Nalipatam dagiti salaysay ti panagserrekmo?",
        "userlogin-resetpassword-link": "Nalipatam ti kontraseniasmo?",
        "userlogin-helplink2": "Tulong iti panagserrek",
        "userlogin-loggedin": "Nakastrekkan a kas ni {{GENDER:$1|$1}}.\nUsaren ti porma dita baba tapno sumrek a kas sabali nga agar-aramat.",
-       "userlogin-createanother": "Agaramid pay ti sabali a pakabilangan",
+       "userlogin-createanother": "Agpartuat ti sabali a pakabilangan",
        "createacct-emailrequired": "Esurat a pagtaengan",
        "createacct-emailoptional": "Esurat a pagtaengan (pagpilian)",
        "createacct-email-ph": "Ikabil ti esurat a pagtaengam",
        "createacct-another-email-ph": "Ikabil ti esurat a pagtaengan",
-       "createaccountmail": "Agusar ti pugto a temporario a kontrasenias ken ipatulod idiay naisangayan nga esurat a pagtaengan",
+       "createaccountmail": "Agusar ti pugto a temporario a kontrasenias ken ipatulod iti naisangayan nga esurat a pagtaengan",
        "createacct-realname": "Pudno a nagan (pagpilian)",
        "createaccountreason": "Rason:",
        "createacct-reason": "Rason",
        "createacct-reason-ph": "Apay nga agparpartuatka manen ti sabali a pakabilangan",
-       "createacct-captcha": "Panagkita ti seguridad",
+       "createacct-captcha": "Panagpatalged ti seguridad",
        "createacct-imgcaptcha-ph": "Ikabil ti testo a makitam dita ngato",
        "createacct-submit": "Partuatem ti pakabilangam",
-       "createacct-another-submit": "Agaramid pay ti sabali a pakabilangan",
+       "createacct-another-submit": "Agpartuat ti sabali a pakabilangan",
        "createacct-benefit-heading": "Ti {{SITENAME}} ket inar-aramid babaen ti tattao a kasla kenka.",
        "createacct-benefit-body1": "{{PLURAL:$1|nga inurnos|nga inur-urnos}}",
        "createacct-benefit-body2": "{{PLURAL:$1|a panid|a pampanid}}",
        "createacct-benefit-body3": "nga agdama a {{PLURAL:$1|nagparawad|nagparparawad}}",
        "badretype": "Saan nga agpada dagiti inkabilmo a kontrasenias.",
-       "userexists": "Maus-usaren ti inkabilmo a nagan.\nPangngaasi nga agpilika ti sabali a nagan.",
+       "userexists": "Maus-usaren ti inkabilmo a nagan.\nPangngaasi nga agpilika iti sabali a nagan.",
        "loginerror": "Biddut ti iseserrek",
        "createacct-error": "Biddut ti panagpartuat ti pakabilangan",
-       "createaccounterror": "Saan a makaaramid ti pakabilangan: $1",
-       "nocookiesnew": "Naaramid ti pakabilangan ti agar-aramat, ngem saanka a nakastrek.\nTi {{SITENAME}} ket agus-usar kadagiti \"galietas\" tapno maiserrek dagiti agar-aramat.\nNabaldado dagiti galietam.\nPangngaasi a pakabaelam ida, ken sumrekka nga agusar ti baro a naganmo ken kontrasenias.",
+       "createaccounterror": "Saan a makapartuat ti pakabilangan: $1",
+       "nocookiesnew": "Napartuaten ti pakabilangan ti agar-aramat, ngem saanka a nakastrek.\nTi {{SITENAME}} ket agus-usar kadagiti galietas tapno maiserrek dagiti agar-aramat.\nNabaldado dagiti galietam.\nPangngaasi a pakabaelam ida, ken sumrekka nga agusar iti baro a naganmo ken kontrasenias.",
        "nocookieslogin": "Ti {{SITENAME}} ket agus-usar kadagiti galietas tapno maiserrek dagiti agar-aramat.\nNabaldado dagiti galietam.\nPangngaasi a pakabaelam ida ken padasem manen ti sumrek.",
-       "nocookiesfornew": "Ti pakabilangan ti agar-aramat ket saan a naaramid, saanmi a mapasingkedan ti taudanna.\nSiguraduem a napakabaelan dagita galietam, ikargam manen daytoy a panid ken padasem manen.",
-       "noname": "Saanmo a nainaganan ti agpayso a nagan ti agar-aramat.",
+       "nocookiesfornew": "Ti pakabilangan ti agar-aramat ket saan a napartuat, saanmi a mapasingkedan ti taudanna.\nSiguraduem a napakabaelan dagita galietam, ikarga manen daytoy a panid ken padasen manen.",
+       "noname": "Saanmo a nainaganan ti umisu a nagan ti agar-aramat.",
        "loginsuccesstitle": "Balligi ti panagserrek",
-       "loginsuccess": "'''Nakastrekkan iti {{SITENAME}} a kas ni \"$1\".'''",
-       "nosuchuser": "Awan ti agar-aramat nga agnagan iti \"$1\". \n\nDagiti nagan ti agar-aramat ket sensitibo ti kadakkel ti letra.\n\nKitaem ti panangiletra, wenno [[Special:UserLogin/signup|agaramidka ti baro a pakabilangan]].",
+       "loginsuccess": "<strong>Nakastrekkan iti {{SITENAME}} a kas ni \"$1\".</strong>",
+       "nosuchuser": "Awan ti agar-aramat nga agnagan ti \"$1\". \n\nDagiti nagan ti agar-aramat ket sensitibo ti kadakkel ti letra.\n\nKitaem ti panangiletram, wenno [[Special:UserLogin/signup|agpartuat ti baro a pakabilangan]].",
        "nosuchusershort": "Awan ti agar-aramat nga agnagan ti \"$1\".\nKitaem ti panangiletram.",
-       "nouserspecified": "Nasken nga agikabilka ti nagan ti agar-aramat.",
+       "nouserspecified": "Nasken nga inaganam ti nagan ti agar-aramat.",
        "login-userblocked": "Naserraan daytoy nga agar-aramat. Saan a mapalubosan ti sumrek.",
-       "wrongpassword": "Saan a husto ti naikabil a kontrasenias. \nPangngaasi a padasem manen.",
-       "wrongpasswordempty": "Blanko ti naikabil a kontrasenias. \nPangngaasi a padasem manen.",
+       "wrongpassword": "Saan a husto ti naikabil a kontrasenias. \nPangngaasi a padasen manen.",
+       "wrongpasswordempty": "Blanko ti naikabil a kontrasenias. \nPangngaasi a padasen manen.",
        "passwordtooshort": "Dagiti kontrasenias ket nasken a saan a basbasit ngem {{PLURAL:$1|1 a karakter|$1 a karkarakter}}.",
        "password-name-match": "Nasken a ti kontrasenias ket maigiddiat manipud ti naganmo.",
-       "password-login-forbidden": "Ti panag-usar ti daytoy a nagan ti agar-aramat ken kontrasenias ket naipariten.",
-       "mailmypassword": "Iyasentar manen ti kontrasenias",
+       "password-login-forbidden": "Ti panag-usar iti daytoy a nagan ti agar-aramat ken kontrasenias ket naipariten.",
+       "mailmypassword": "Isaad manen ti kontrasenias",
        "passwordremindertitle": "Baro a temporario a kontrasenias para iti {{SITENAME}}",
-       "passwordremindertext": "Adda maysa a tao (mabalin a sika met laeng, manipud iti IP a pagtaengan a $1) ket nagkiddaw ti baro\na kontrasenias para iti {{SITENAME}} ($4). Ti saan nga agnayon a kontrasenias ti agususar\n\"$2\" ket naaramiden ken naidisso iti \"$3\". No kastan ti kinayatmo,\nmasapul a sumrek ka ta agpili ka ti baro a kontrasenias.\nTi temporario a bukodmo a kontrasenias ket agpaso  {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\n\nNo sabali ti nagkiddaw, wenno no malagipmo pay ti kontrasenias mo ket dimon kayat a suktan daytoy, mabalin a dimo lattan ikaskaso daytoy a mensahe ket itultuloymo latta nga usaren ti daan a kontrasenias.",
-       "noemail": "Awan ti esurat a pagtaengan a nairehistro para  iti agar-aramat a ni \"$1\".",
+       "passwordremindertext": "Adda maysa a tao (mabalin a sika met laeng, manipud iti IP a pagtaengan a $1) ket nagkiddaw ti baro a kontrasenias para iti {{SITENAME}} ($4). Ti temporario a kontrasenias para kenni agar-aramat \"$2\" ket napartuaten ken naisaad iti \"$3\". No kastan ti kinayatmo, nasken itan a sumrekka ken agpili ti baro a kontrasenias.\nTi temporario a kontraseniasmo ket agpaso {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\n\nNo sabali ti nagkiddaw, wenno nalagipmon ti kontraseniasmo,\nken dimo kayaten a sukatan daytoy, mabalinmo a di ikaskaso daytoy a mensahe ken agtuloy nga usaren ti daan a kontraseniasmo.",
+       "noemail": "Awan ti esurat a pagtaengan a nairehistro para iti agar-aramat a ni \"$1\".",
        "noemailcreate": "Nasken a mangitedka ti pudno nga esurat a pagtaengan.",
        "passwordsent": "Naipatuloden ti baro a kontrasenias iti esurat a pagtaengan a nairehistro kenni \"$1\".\nPangngaasi a sumrekka manen kalpasan ti pannakaawatmo.",
-       "blocked-mailpassword": "Ti IP a pagtaengam ket naserraan manipud ti panag-urnos, isunga saan a mapalubosan nga agusar ti annong ti panagipulang ti kontrasenias tapno mapawilan ti panag-abuso.",
+       "blocked-mailpassword": "Ti IP a pagtaengam ket naserraan manipud ti panag-urnos, ken isu a saan a mapalubosan nga agusar ti annong ti panagipulang ti kontrasenias tapno mapawilan ti panag-abuso.",
        "eauthentsent": "Naipatuloden ti pammatalged nga esurat iti naikeddeng nga esurat a pagtaengan.\nSakbay a maipatulod ti aniaman nga esurat iti pakabilangan, masapul a surotem dagiti maibagbaga iti esurat, tapno mapatalgedan ti pakabilangan ket agpayso a kukuam.",
-       "throttled-mailpassword": "Ti panangiyasentar manen ti kontrasenias ket naipatuloden, iti kaunegan ti napalabas a {{PLURAL:$1|nga oras|$1 nga or-oras}}.\nTapno maipawilan ti panag-abuso, maysa laeng a panangiyasentar manen ti kontrasenias ti maipatulod iti kada {{PLURAL:$1|nga oras|$1 nga or-oras}}.",
+       "throttled-mailpassword": "Ti panangisaad manen ti kontrasenias ket naipatuloden, iti kaunegan ti napalabas a {{PLURAL:$1|nga oras|$1 nga or-oras}}.\nTapno maipawilan ti panag-abuso, maysa laeng a panangisaad manen ti kontrasenias ti maipatulod iti kada {{PLURAL:$1|nga oras|$1 nga or-oras}}.",
        "mailerror": "Biddut iti panangipatulod ti surat: $1",
-       "acct_creation_throttle_hit": "Dagiti sumarungkar ti daytoy a wiki nga agus-usar ti IP a pagtaengan ket nakaaramid {{PLURAL:$1|iti 1 a pakabilangan|kadagiti $1 a pakabilangan}} iti nasakbayan nga aldaw, nga isu laeng ti kaadu a maipalubos iti daytoy a paset ti panawen.\nA kas ti nagbanagan, dagiti agsarsarungkar nga agus-usar ti IP a pagtaengan ket agdama a saanda a mabalin a makaaramid kadagiti pakabilangan.",
-       "emailauthenticated": "Ti esurat a pagtaengam ket napatalgedan idi $2 idi $3.",
+       "acct_creation_throttle_hit": "Dagiti sumarungkar iti daytoy a wiki nga agus-usar ti IP a pagtaengan ket nakapartuat {{PLURAL:$1|iti 1 a pakabilangan|kadagiti $1 a pakabilangan}} iti nasakbayan nga aldaw, nga isu laeng ti kaadu a maipalubos iti daytoy a paset ti panawen.\nA kas ti nagbanagan, dagiti agsarsarungkar nga agus-usar ti IP a pagtaengan ket agdama a saanda a mabalin a makapartuat kadagiti pakabilangan.",
+       "emailauthenticated": "Ti esurat a pagtaengam ket napatalgedan idi $2, $3.",
        "emailnotauthenticated": "Saan pay a napatalgedan ti esuratmo a pagtaengan.\nAwanto ti esurat a maipatulod para kadagiti sumaganad a langa.",
        "noemailprefs": "Ipanaganan ti esurat a pagtaengan tapno agbalin dagitoy a langa.",
        "emailconfirmlink": "Pasingkedam ti esurat a pagtaengam",
        "invalidemailaddress": "Ti esurat a pagtaengan ket saan a maawat ngamin ket kasla adda ti saan a napudno a porma.\nPangngaasi nga agikabil ti nasayaat a porma ti pagtaengan wenno ikkaten amin a naikabil.",
        "cannotchangeemail": "Dagiti pakabilangan nga esurat a pagtaengan ket saan a mabaliwan iti daytoy a wiki.",
-       "emaildisabled": "Daytoy a pagsaaadan ket saan a makaipatulod kadagiti esurat.",
-       "accountcreated": "Naaramiden ti pakabilangan",
+       "emaildisabled": "Daytoy a sitio ket saan a makaipatulod kadagiti esurat.",
+       "accountcreated": "Napartuaten ti pakabilangan",
        "accountcreatedtext": "Ti pakabilangan ti agar-aramat para kenni [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|tungtungan]]) ket napartuaten.",
-       "createaccount-title": "Panagaramid ti pakabilangan para iti {{SITENAME}}",
-       "createaccount-text": "Adda nagaramid ti pakabilangan para iti esurat a pagtaengam idiay {{SITENAME}} ($4) nga agnagan  ti \"$2\", iti kontrasenias a \"$3\".\nNasken a sumrekka ken sukatam ti kontraseniasmo tattan.\n\nMabalinmo ti saan a mangikaskaso ti daytoy a mensahe, no biddut a naaramid daytoy a pakabilangan.",
-       "login-throttled": "Adu unay ti panagpadasmo a sumrek.\nPangngaasi nga agurayka ti $1 sakbay a padasem manen.",
+       "createaccount-title": "Panagpartuat ti pakabilangan para iti {{SITENAME}}",
+       "createaccount-text": "Adda nagpartuat ti pakabilangan para iti esurat a pagtaengam iti {{SITENAME}} ($4) nga agnagan  ti \"$2\", iti kontrasenias a \"$3\".\nNasken a sumrekka ken sukatam ti kontraseniasmo tattan.\n\nMabalinmo ti saan a mangikaskaso iti daytoy a mensahe, no biddut a naaramid daytoy a pakabilangan.",
+       "login-throttled": "Adu unay ti panagpadasmo a sumrek.\nPangngaasi nga agurayka ti $1 sakbay a padasen manen.",
        "login-abort-generic": "Napaay ti panagserrekmo - Napasardeng",
        "loginlanguagelabel": "Pagsasao: $1",
        "suspicious-userlogout": "Naiparit ti panagkiddawmo a rummuar ngamin ket kasla inpatulod ti nadadael a panagbasabasa wenno pannakaidulin a pannakbagi.",
        "createacct-another-realname-tip": "Saan a nasken ti pudno a nagan.\nNo kayatmo nga ited, mausarto daytoy para iti panangited ti pammadayaw para kadagiti obrada.",
        "pt-login": "Sumrek",
        "pt-login-button": "Sumrek",
-       "pt-createaccount": "Agaramid ti pakabilangan",
+       "pt-createaccount": "Agpartuat ti pakabilangan",
        "pt-userlogout": "Rummuar",
-       "php-mail-error-unknown": "Di ammo a biddut ti surat ti PHP() nga annong.",
-       "user-mail-no-addy": "Pinadas nga inpatulod ti esurat nga awan ti esurat a pagtaengan.",
-       "user-mail-no-body": "Pinadas nga inpatulod ti esurat nga awan linaonna wenno ababa laeng a bagi.",
+       "php-mail-error-unknown": "Di ammo a biddut iti surat ti annong ti PHP().",
+       "user-mail-no-addy": "Pinadas nga inpatulod ti esurat nga awan ti maysa nga esurat a pagtaengan.",
+       "user-mail-no-body": "Pinadas nga inpatulod ti esurat nga awan ti maysa a linaonna wenno ababa unay a bagi.",
        "changepassword": "Baliwan ti kontrasenias",
-       "resetpass_announce": "Tapno malpas ti panagserrek, nasken a mangiyasentarka ti baro a kontrasenias.",
+       "resetpass_announce": "Tapno malpas ti panagserrek, nasken a mangisaadka ti baro a kontrasenias.",
        "resetpass_header": "Sukatan ti kontrasenias ti pakabilangan",
        "oldpassword": "Daan a kontrasenias:",
        "newpassword": "Baro a kontrasenias:",
        "retypenew": "Imakinilya manen ti baro a kontrasenias:",
-       "resetpass_submit": "Ikabil ti kontrasenias ken sumrek",
+       "resetpass_submit": "Isaad ti kontrasenias ken sumrek",
        "changepassword-success": "Balligi a nasukatan ti kontraseniasmo!",
        "changepassword-throttled": "Nakaaramidka kadagiti adu unay a nabiit a panangipadas ti panagserrek.\nPangngaasi nga aguray ti $1 sakbay a padasen manen.",
        "resetpass_forbidden": "Saan a masukatan dagiti kontrasenias",
        "resetpass-submit-loggedin": "Sukatan ti kontrasenias",
        "resetpass-submit-cancel": "Ukasen",
        "resetpass-wrong-oldpass": "Imbalido ti temporario wenno agdama a kontrasenias.\nMabalin a nagballigi ti panagsukatmo ti kontrasenias wenno nagkiddaw ti baro a temporario a kontrasenias.",
-       "resetpass-recycled": "Pangngaasi nga iyasentar manen ti kontrasenias iti sabali ngem ti agdama a kontraseniasmo.",
-       "resetpass-temp-emailed": "Simrekka a nagusar ti temporario a naipatulod a kodigo.\nTapno malpas ti panagserrek, nasken a mangiyasentarka ti baro a kontrasenias ditoy:",
+       "resetpass-recycled": "Pangngaasi nga isaad manen ti kontrasenias iti sabali ngem ti agdama a kontraseniasmo.",
+       "resetpass-temp-emailed": "Simrekka a nagusar ti temporario a naipatulod a kodigo.\nTapno malpas ti panagserrek, nasken a mangisaadka ti baro a kontrasenias ditoy:",
        "resetpass-temp-password": "Temporario a kontrasenias:",
        "resetpass-abort-generic": "Ti panagsukat ti kontrasenias ket pinasardeng babaen ti maysa a pagpaatiddog.",
-       "resetpass-expired": "Nagpason ti kontraseniasmo. Pangngaasi a mangiyasentar ti baro a kontrasenias tapno makastrek.",
-       "resetpass-expired-soft": "Nagpason ti kontraseniasmo, ken nasken a maiyasentar manen. Pangngaasi nga agpili tattan ti baro a kontrasenias, wenno pinduten ti \"{{int:resetpass-submit-cancel}}\"  tapno maiyasentarto intono madamdama.",
-       "resetpass-validity-soft": "Saan nga umiso ti kontraseniasmo: $1\n\nAgpilika tattan ti baro a kontrasenias, wenno pinduten ti \"{{int:resetpass-submit-cancel}}\" tapno isaad intono madamdama.",
-       "passwordreset": "Iyasentar manen ti kontrasenias",
-       "passwordreset-text-one": "Lippasem daytoy a porma tapno maiyasentar manen ti bukodmo a kontrasenias.",
+       "resetpass-expired": "Nagpason ti kontraseniasmo. Pangngaasi a mangisaad ti baro a kontrasenias tapno makastrek.",
+       "resetpass-expired-soft": "Nagpason ti kontraseniasmo, ken nasken a maisaad manen. Pangngaasi nga agpili tattan ti baro a kontrasenias, wenno pinduten ti \"{{int:resetpass-submit-cancel}}\"  tapno maisaad intono madamdama.",
+       "resetpass-validity-soft": "Saan nga umiso ti kontraseniasmo: $1\n\nAgpilika tattan ti baro a kontrasenias, wenno pinduten ti \"{{int:resetpass-submit-cancel}}\" tapno maisaad intono madamdama.",
+       "passwordreset": "Isaad manen ti kontrasenias",
+       "passwordreset-text-one": "Kompletuen daytoy a porma tapno makaawat iti temporario a kontrasenias babaen ti esurat.",
        "passwordreset-text-many": "{{PLURAL:$1|Agpunno ti maysa kadagiti pagikabilan tapno makaawat ti temporario a kontrasenias babaen ti esurat.}}",
-       "passwordreset-legend": "Iyasentar manen ti kontrasenias",
-       "passwordreset-disabled": "Nabaldado dagiti panangiyasentar manen ti kontrasenias iti daytoy a wiki.",
+       "passwordreset-legend": "Isaad manen ti kontrasenias",
+       "passwordreset-disabled": "Nabaldado dagiti panangisaad manen ti kontrasenias iti daytoy a wiki.",
        "passwordreset-emaildisabled": "Dagiti langa ti esurat ket nabaldado iti daytoy a wiki.",
        "passwordreset-username": "Nagan ti agar-aramat:",
-       "passwordreset-domain": "Pagturayan:",
-       "passwordreset-capture": "Kitaen ti nagbanagan ti esurat?",
-       "passwordreset-capture-help": "No markaam daytoy a kahon, ti esurat (nga adda ti temporario a kontrasenias) ket maipakita kenka ken maipatulod iti agar-aramat.",
+       "passwordreset-domain": "Dominio:",
+       "passwordreset-capture": "Kitaen ti nagbanagan nga esurat?",
+       "passwordreset-capture-help": "No markaam daytoy a kahon, ti esurat (nga adda ti temporario a kontrasenias) ket maipakitanto kenka ken maipatulodto iti agar-aramat.",
        "passwordreset-email": "Esurat a pagtaengan:",
-       "passwordreset-emailtitle": "Salaysay ti pakabilangan iti {{SITENAME}}",
-       "passwordreset-emailtext-ip": "Adda (baka sika, ti naggapuan ti IP a pagtaengan $1) a nagkiddaw ti maysa a panangiyasentar manen ti kontrasenias para iti {{SITNAME}} ($4) . {{PLURAL:$3|Ti |Dagiti}} sumaganad a pakabilangan ti agar-aramat ket\nnakairaman iti daytoy nga esurat a pagtaengan:\n\n$2\n\n{{PLURAL:$3|Daytoy temporario a kontrasenias|Dagitoy temporario a kontrasenias}} ket agpaso {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\nSumrekka koman tapno agpilika ti baro a kontraseniasmo tattan. No adda met sabali a nagaramid daytoy a \npanagkiddaw, wenno malagipmo ti dati a kontraseniasmo, ket saanmo a kayaten a sukatan, saanmo nga ikaskaso daytoy a mensahe ken \nagtuloyka nga agusar ti daan a kontrasenias.",
-       "passwordreset-emailtext-user": "Daytoy nga agar-aramat $1 iti {{SITENAME}} ket nagkiddaw ti maysa a panangiyasentar manen ti bukod a kontrasenias para iti {{SITENAME}}\n($4) . {{PLURAL:$3|Ti|Dagiti}} sumaganad a pakabilanagan ti agar-aramat ket\nnakairaman iti daytoy nga esurat a pagtaengan:\n\n$2\n\n{{PLURAL:$3|Daytoy temporario a kontrasenias|Dagitoy temporario a kontrasenias}} ket agpaso {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\nSumrekka koman tapno agpili ka ti baro a kontraseniasmo tattan. No adda met sabali a nagaramid daytoy a \npanagkiddaw, wenno malagipmo ti dati a kontraseniasmo, ket saan mo a kayaten a sukatan, saanmo nga ikaskaso daytoy a mensahe ken \nagtuloykan nga agusar ti daan a kontraseniasmo.",
+       "passwordreset-emailtitle": "Dagiti salaysay ti pakabilangan iti {{SITENAME}}",
+       "passwordreset-emailtext-ip": "Adda (baka sika, ti naggapuan ti IP a pagtaengan $1) a nagkiddaw ti maysa a panangisaad manen ti kontrasenias para iti {{SITNAME}} ($4) . {{PLURAL:$3|Ti |Dagiti}} sumaganad a pakabilangan ti agar-aramat ket\nmainaig iti daytoy nga esurat a pagtaengan:\n\n$2\n\n{{PLURAL:$3|Daytoy temporario a kontrasenias|Dagitoy temporario a kontrasenias}} ket agpaso {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\nSumrekka koman tapno agpilika ti baro a kontraseniasmo tattan. No adda met sabali a nagaramid daytoy a \npanagkiddaw, wenno malagipmo ti dati a kontraseniasmo, ket saanmo a kayaten a sukatan, saanmo nga ikaskaso daytoy a mensahe ken \nagtuloyka nga agusar ti daan a kontrasenias.",
+       "passwordreset-emailtext-user": "Daytoy nga agar-aramat $1 iti {{SITENAME}} ket nagkiddaw ti maysa a panangisaad manen ti bukod a kontrasenias para iti {{SITENAME}}\n($4) . {{PLURAL:$3|Ti|Dagiti}} sumaganad a pakabilangan ti agar-aramat ket\nmainaig iti daytoy nga esurat a pagtaengan:\n\n$2\n\n{{PLURAL:$3|Daytoy temporario a kontrasenias|Dagitoy temporario a kontrasenias}} ket agpaso {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\nSumrekka koman tapno agpilika ti baro a kontraseniasmo tattan. No adda met sabali a nagaramid daytoy a \npanagkiddaw, wenno malagipmo ti dati a kontraseniasmo, ken saanmo a kayaten a sukatan, saanmo nga ikaskaso daytoy a mensahe ken \nagtuloykan nga agusar ti daan a kontraseniasmo.",
        "passwordreset-emailelement": "Nagan ti agar-aramat: $1\nTemporario a kontrasenias: $2",
-       "passwordreset-emailsent": "Ti maysa nga esurat ti panangiyasentar manen ti kontrasenias ket naipatuloden.",
-       "passwordreset-emailsent-capture": "Ti maysa nga esurat ti panangiyasentar manen ti kontrasenias ket naipatuloden, a napaikita dita baba.",
-       "passwordreset-emailerror-capture": "Naaramid ti maysa nga esurat a panangyasentar manen ti kontrasenias, a napaikita dita baba, ngem ti panangitulod kenni {{GENDER:$2|agar-aramat}} ket napaay: $1",
+       "passwordreset-emailsent": "Ti maysa nga esurat ti panangisaad manen ti kontrasenias ket naipatuloden.",
+       "passwordreset-emailsent-capture": "Ti maysa nga esurat ti panangisaad manen ti kontrasenias ket naipatuloden, a naipakita dita baba.",
+       "passwordreset-emailerror-capture": "Naaramid ti maysa nga esurat a panangisaad manen ti kontrasenias, a napaikita dita baba, ngem ti panangitulod kenni {{GENDER:$2|agar-aramat}} ket napaay: $1",
        "changeemail": "Sukatan ti esurat a pagtaengan",
        "changeemail-header": "Sukatan ti esurat a pagtaengan ti pakabilangan",
-       "changeemail-text": "Lippasem daytoy a porma ti panagsukat ti esurat a pagtaengam. Nasken nga ikabilmo ti kontrasenias tapno mapasingkedan daytoy a panagsukat.",
+       "changeemail-text": "Kompletuen daytoy a porma ti panagsukat ti esurat a pagtaengam. Nasken nga ikabilmo ti kontrasenias tapno mapasingkedan daytoy a panagsukat.",
        "changeemail-no-info": "Masapul a nakastrekka tapno dagus a makapan iti ditoy a panid.",
        "changeemail-oldemail": "Agdama nga esurat a pagtaengan:",
        "changeemail-newemail": "Baro nga esurat a pagtaengan:",
        "changeemail-submit": "Sukatan ti esurat",
        "changeemail-cancel": "Ukasen",
        "changeemail-throttled": "Adu unay ti panagpadasmo a sumrek.\nPangngaasi nga aguray ti $1 sakbay a padasen manen.",
-       "resettokens": "Iyasentar manen dagiti tandaan",
-       "resettokens-text": "Mabalinmo nga iyasentar dagiti tandaan a mangpalubos ti panagserrek ti naisangayan a pribado datos a mainaig ti pakabilangam ditoy.\n\nAramidem daytoy no aksidente nga inbingaymo dagitoy iti sabali wenno ti pakabilangam ket nakomprimiso.",
-       "resettokens-no-tokens": "Awan dagiti maiyasentar manen a tandaan.",
-       "resettokens-legend": "Iyasentar manen dagiti tandaan",
+       "resettokens": "Isaad manen dagiti tandaan",
+       "resettokens-text": "Mabalinmo nga isaad manen dagiti tandaan a mangpalubos ti panagserrek ti naisangayan a pribado datos a mainaig ti pakabilangam ditoy.\n\nAramidem daytoy no aksidente nga inbingaymo dagitoy iti sabali wenno ti pakabilangam ket nakomprimiso.",
+       "resettokens-no-tokens": "Awan dagiti maisaad manen a tandaan.",
+       "resettokens-legend": "Isaad manen dagiti tandaan",
        "resettokens-tokens": "Dagiti tandaan:",
        "resettokens-token-label": "$1 (agdama a pateg: $2)",
-       "resettokens-watchlist-token": "Tandaan para iti pakan ti web (Atom/RSS) kadagiti [[Special:Watchlist|panagbalbaliw ti pampanid idiay bambantayam]]",
-       "resettokens-done": "Naiyasentar manen dagiti tandaan.",
-       "resettokens-resetbutton": "Iyasentar manen  dagiti napili a tandaan",
+       "resettokens-watchlist-token": "Tandaan para iti pakan ti web (Atom/RSS) kadagiti [[Special:Watchlist|panagbalbaliw ti pampanid iti listaan ti bambantayam]]",
+       "resettokens-done": "Naisaad manen dagiti tandaan.",
+       "resettokens-resetbutton": "Isaad manen  dagiti napili a tandaan",
        "bold_sample": "Napuskol a testo",
        "bold_tip": "Napuskol a testo",
-       "italic_sample": "Nakairig a testo",
-       "italic_tip": "Nakairig a testo",
+       "italic_sample": "Italiko a testo",
+       "italic_tip": "Italiko a testo",
        "link_sample": "Titulo ti silpo",
        "link_tip": "Akin-uneg a silpo",
        "extlink_sample": "http://www.example.com titulo ti silpo",
-       "extlink_tip": "Akin-ruar a silpo (laglagipen ti http:// a pasaruno)",
+       "extlink_tip": "Akinruar a silpo (laglagipen ti http:// a pasakbay)",
        "headline_sample": "Testo ti paulo",
        "headline_tip": "Maika-2 nga agasmang ti paulo",
        "nowiki_sample": "Isengngat ti saan a naporma a testo ditoy",
-       "nowiki_tip": "Saan nga ikaskaso ti panakaporma ti wiki",
+       "nowiki_tip": "Saan nga ikaskaso ti pannakaporma ti wiki",
        "image_tip": "Naisengngat a papeles",
        "media_tip": "Silpo ti papeles",
-       "sig_tip": "Ti pirmam nga adda ti oras ken petsa",
-       "hr_tip": "Pakuros a linia (manmano laeng nga aramaten)",
+       "sig_tip": "Ti pirmam nga addaan iti oras ken petsa",
+       "hr_tip": "Horisontal a linia (manmano laeng nga aramaten)",
        "summary": "Pakabuklan:",
        "subject": "Suheto/paulo:",
        "minoredit": "Daytoy ket bassit a panag-urnos",
        "preview": "Ipadas",
        "showpreview": "Ipakita ti ipadas",
        "showdiff": "Ipakita dagiti sinukatan",
-       "anoneditwarning": "'''Ballaag:''' Saanka a nakastrek.\nMairehistro ti IP a pagtaengam iti pakasaritaan ti panagurnos iti daytoy a panid.",
-       "anonpreviewwarning": "\" Saanka a nakastrek. Ti panagidulin ket agirehistro ti IP a pagtaengam kadagitoy a  pakasaritaan ti panagurnos iti daytoy a panid.\"",
-       "missingsummary": "'''Palagip:''' Saanka a nakaited iti pakabuklan ti panag-urnos.\nNo ipindutmo ti manen ti \"{{int:savearticle}}\", maidulin ti inurnosmo nga awan ti pakabuklanna.",
+       "anoneditwarning": "<strong>Ballaag:</strong> Saanka a nakastrek.\nMairehistro ti IP a pagtaengam iti pakasaritaan ti panag-urnos iti daytoy a panid.",
+       "anonpreviewwarning": "<em>Saanka a nakastrek. Ti panagidulin ket agirehistro ti IP a pagtaengam kadagitoy a pakasaritaan ti panag-urnos iti daytoy a panid.</em>",
+       "missingsummary": "<strong>Palagip:</strong> Saanka a nakaited iti pakabuklan ti panag-urnos.\nNo pindutem manen ti \"{{int:savearticle}}\", maidulin ti inurnosmo nga awan ti pakabuklanna.",
        "missingcommenttext": "Pangngaasi nga agikabil ti komentario dita baba.",
-       "missingcommentheader": "'''Palagip:''' Saanka a nakaited  iti suheto/paulo para iti daytoy a komentario.\nNo ipindutmo manen ti \"{{int:savearticle}}\", maidulin ti inurnosmo nga awan ti pakabuklanna.",
-       "summary-preview": "Naipadas a  pakabuklan:",
+       "missingcommentheader": "<strong>Palagip:</strong> Saanka a nakaited  iti suheto/paulo para iti daytoy a komentario.\nNo pindutem manen ti \"{{int:savearticle}}\", maidulin ti inurnosmo nga awan ti pakabuklanna.",
+       "summary-preview": "Naipadas a pakabuklan:",
        "subject-preview": "Suheto/naipadas a paulo:",
        "blockedtitle": "Naseraan ti agar-aramat",
-       "blockedtext": "'''Naseraan ti naganmo nga agar-aramat wenno ti IP a pagtaengam.'''\n\nNi $1 ti nangserra kenka. \nTi rason ket ''$2''.\n\n* Rugi ti panangserra: $8\n* Panagpaso ti panangserra: $6\n* Ti koma serraanna: $7\n\nMabalinmo a kontaken ni $1 wenno sabali pay nga [[{{MediaWiki:Grouppage-sysop}}|administrador]] no kayatmo a maipalawag daytoy a panag-serra.\nDimo mabalin nga aramaten ti ramit nga esuratan daytoy nga agar-aramat malaksid no adda napudno nga esurat a pagtaengan a naipan iti [[Special:Preferences|pakabilangan ti kaykayatmo]] ken no saanka a naparitan nga agaramat iti daytoy.\nTi agdama nga IP a pagtaengam ket $3, ti naserraan nga ID ket #$5. Pangngaasi nga iramanmo nga ited ti aniaman wenno agpada kadagitoy iti aniaman a panagsaludsodmo.",
-       "autoblockedtext": "Ti IP a pagtaengam ket na-automatiko a naserraan ngamin ket inusar ti sabali nga agar-aramat, a sinerraan ni $1.\nTi rason nga inted ket:\n\n:''$2''\n\n* Rugi ti panag-serra: $8\n* Panagpaso ti panag-serra: $6\n* Ti serraanna koma: $7\n\nMabalinmo a kontaken ni $1 wenno maysa kadagiti [[{{MediaWiki:Grouppage-sysop}}|administrador]] tapno maipalawag daytoy a panag-serra.\n\nLaglagipem a saanmo a mabalin nga usaren ti \"esuratan daytoy nga agar-aramat\" a langa malaksid no addaanka ti napudno nga esurat a pagtaengan a nakarehistro idiay [[Special:Preferences|kakaykayatam]] ken saanka a naserraan manipud ti panag-usar daytoy.\n\nTi tatta nga IP a pagtaengam ket $3, ken ti ID ti naserraan ket #$5.\nPangaasi nga iramanmo amin dagiti salaysay kadagiti amin a panagsaludsodmo.",
+       "blockedtext": "<strong>Naseraan ti naganmo nga agar-aramat wenno ti IP a pagtaengam.</strong>\n\nTi serra ket inaramid babaen ni $1. \nTi rason a naited ket <em>$2</em>.\n\n* Rugi ti serra: $8\n* Panagpaso ti serra: $6\n* Naikeddeng a serraanna: $7\n\nMabalinmo a kontaken ni $1 wenno sabali pay nga [[{{MediaWiki:Grouppage-sysop}}|administrador]] no kayatmo a maipalawag daytoy a panagserra.\nDimo mabalin nga aramaten ti ramit nga esuratan daytoy nga agar-aramat malaksid no adda napudno nga esurat a pagtaengan a nainaganan iti [[Special:Preferences|pakabilangan ti kakaykayatm]] ken no saanka a naparitan nga agaramat iti daytoy.\nTi agdama nga IP a pagtaengam ket $3, ti naserraan nga ID ket #$5. \nPangngaasi nga iramanmo amin dagiti salaysay dita ngato kadagiti aniaman nga aramidem nga usisa.",
+       "autoblockedtext": "Ti IP a pagtaengam ket automatiko a naserraan ngamin ket inusar ti sabali nga agar-aramat, a sinerraan ni $1.\nTi rason nga inted ket:\n\n:<em>$2</em>\n\n* Rugi ti serra: $8\n* Panagpaso ti serra: $6\n* Naikeddenga a serraanna: $7\n\nMabalinmo a kontaken ni $1 wenno maysa kadagiti [[{{MediaWiki:Grouppage-sysop}}|administrador]] tapno maipalawag daytoy a panagserra.\n\nLaglagipem a saanmo a mabalin nga usaren ti \"esuratan daytoy nga agar-aramat\" a langa malaksid no addaanka ti napudno nga esurat a pagtaengan a nakarehistro iti [[Special:Preferences|kakaykayatam]] ken saanka a naserraan manipud ti panag-usar daytoy.\n\nTi tatta nga IP a pagtaengam ket $3, ken ti ID ti naserraan ket #$5.\nPangngaasi nga iramanmo amin dagiti salaysay dita ngato kadagiti aniaman nga aramidem nga usisa.",
        "blockednoreason": "awan ti naited a rason",
        "whitelistedittext": "Nasken ti $1 tapno maurnosmo dagitoy a panid.",
-       "confirmedittext": "Masapul a pasingkedam ti esurat sakbay a makaurnos kadagitoy a panid.\nPangngaasim nga ikabil ken ipapudnom ti esuratmo idiay [[Special:Preferences|kaykayat dagiti agar-aramat ]].",
+       "confirmedittext": "Masapul a pasingkedam ti esurat sakbay a makaurnos kadagitoy a panid.\nPangngaasi nga isaad ken ipapudnom ti esuratmo babaen ti [[Special:Preferences|kakaykayatan ti agar-aramat]].",
        "nosuchsectiontitle": "Saan a mabirukan ti paset",
        "nosuchsectiontext": "Pinadasmo nga inurnos ti awan a paset.\nMabalin a naiyalis wenno naikkat bayat idi kitkitaem ti panid.",
        "loginreqtitle": "Masapul ti sumrek",
        "loginreqlink": "sumrek",
-       "loginreqpagetext": "Naskenka a $1 tapno makakitaka kadagiti sabsabali a pampanid.",
-       "accmailtitle": "Naipatuloden ti kontrasenias.",
-       "accmailtext": "Ti pugto a napartuat a kontrasenias para kenni [[User talk:$1|$1]] ket naipatuloden idiay $2. Mabalin a masukatan idiay\n''[[Special:ChangePassword|pagsukatan ti kontrasenias]]'' a panid no sumrekka.",
+       "loginreqpagetext": "Pangngaasi a $1 tapno makitam dagiti sabali a panid.",
+       "accmailtitle": "Naipatuloden ti kontrasenias",
+       "accmailtext": "Ti pugto a napartuat a kontrasenias para kenni [[User talk:$1|$1]] ket naipatuloden iti $2. Mabalin a masukatan iti\n<em>[[Special:ChangePassword|pagsukatan ti kontrasenias]]</em> a panid no sumrekka.",
        "newarticle": "(Baro)",
-       "newarticletext": "Nasurotmo ti silpo ti awan pay a panid. \nTi mangpartuat ti panid, rugiamon ti agmakinilia iti kahon dita baba (kitaen ti [$1 panid ti tulong] para iti adu pay a pakaammo). \nNo addaka ditoy babaen ti biddut, pindutem ti buton ti <strong>agsubli</strong> ti pagbasabasam.",
-       "anontalkpagetext": "----\n''Daytoy ti pakitungtungan a panid para iti di am-ammo nga agar-aramat a saan pay a nakaaramid ti pakabilangan, wenno saanna nga us-usaren.\nDakami ket agusar kami ti numero nga IP a pagtaengan ti panangilasin dagiti lalaki/babai.\nTi kastoy nga IP a pagtaengan ket us-usaren a bingayan ti adu pay a sabsabali nga agar-aramat.\nNo sika ket maysa a di am-ammo nga agar-aramat ken dagiti awan ti kapategan a komentario ket napaitudo kenka, pangngaasi nga [[Special:UserLogin/signup|agaramid ka ti pakabilangam]] wenno [[Special:UserLogin|sumrekka]] \ntapno maawanan ti panakaulaw kadagiti sabali a di am-ammo nga agar-aramat.",
-       "noarticletext": "Awan ti agdama a testo daytoy a panid.\nMabalinmo ti [[Special:Search/{{PAGENAME}}|agsapul iti kastoy a titulo ti panid]] kadagiti sabsabali a pampanid,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} birukem dagiti mainaig a listaan],\nwenno [{{fullurl:{{NAMESPACE}}:{{PAGENAME}}|action=edit}} urnosem daytoy a panid].",
-       "noarticletext-nopermission": "Awan ti agdama  a linaon daytoy a panid.\nMabalinmo ti [[Special:Search/{{PAGENAME}}|agbiruk para iti titulo ti daytoy a panid]] kadagiti sabali a panid, wenno <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} agbiruk kadagiti mainaig a listaan]</span>, ngem awan ti pammalubosmo a mangpartuat ti daytoy a panid.",
+       "newarticletext": "Nasurotmo ti silpo ti awan pay a panid. \nTi mangpartuat ti panid, rugiamon ti agmakinilia iti kahon dita baba (kitaen ti [$1 panid ti tulong] para iti adu pay a pakaammo). \nNo addaka ditoy babaen ti biddut, pindutem ti buton ti <strong>back</strong> ti pagbasabasam.",
+       "anontalkpagetext": "----\n<em>Daytoy ti pakitungtungan a panid para iti di ammo nga agar-aramat a saan pay a nakapartuat ti pakabilangan, wenno saanna nga us-usaren.</em>\nIsu nga agusarkami ti numero nga IP a pagtaengan tapno mailasin isuda a lalaki/babai.\nTi kastoy nga IP a pagtaengan ket us-usaren a bingayan babaen ti nadumaduma nga agar-aramat.\nNo sika ket maysa a di ammo nga agar-aramat ken dagiti awan ti pategna a komentario ket napaitudo kenka, pangngaasi nga [[Special:UserLogin/signup|agpartuatka ti pakabilangam]] wenno [[Special:UserLogin|sumrekka]] \ntapno maliklikan ti pannakaiyallilaw kadagiti sabali a di ammo nga agar-aramat.",
+       "noarticletext": "Awan ti agdama a testo daytoy a panid.\nMabalinmo ti [[Special:Search/{{PAGENAME}}|agbiruk iti kastoy a titulo ti panid]] kadagiti sabali a panid,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} agbiruk kadagiti mainaig a listaan],\nwenno [{{fullurl:{{NAMESPACE}}:{{PAGENAME}}|action=edit}} urnosem daytoy a panid]</span>.",
+       "noarticletext-nopermission": "Awan ti agdama  a linaon daytoy a panid.\nMabalinmo ti [[Special:Search/{{PAGENAME}}|agbiruk para iti titulo ti daytoy a panid]] kadagiti sabali a panid, wenno <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} agbiruk kadagiti mainaig a listaan]</span>, ngem awan ti pammalubosmo a mangpartuat iti daytoy a panid.",
        "missing-revision": "Ti panagbalbaliw ti #$1 iti daytoy a panid a nanaganan ti \"{{FULLPAGENAME}}\" ket awan.\n\nDaytoy ket kadawyan a gapuanan babaen ti sumaganad a silpo ti baak a pakasaritaan iti maysa a naikkaten a panid.\nDagiti salaysay ket mabalin a mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
-       "userpage-userdoesnotexist": "Ti pakabilangan ti agar-aramat \"$1\" ket saan a nakarehistro. \nPangngaasi a kitaem no kayatmo ti agaramid/urnosen daytoy a panid.",
-       "userpage-userdoesnotexist-view": "Ti pakabilangan ti agar-aramat \"$1\" ket saan a nakarehistro.",
-       "blocked-notice-logextract": "Agdama a naserraan daytoy nga agar-aramat.\nTi naudi a listaan ti panaka-serra ket adda dita baba tapno mausar a reperensia:",
-       "clearyourcache": "'''Pakaammo:''' No nalpaskan nga agiduldulin, koma ket masapul nga ipalabas ti cahe ti pagbasabasam tapno makita dagiti sinukatam.\n* '''Firefox / Safari:''' Tenglen ti ''Sukatan'' bayat nga ipindut ti ''Ikarga manen'', wenno ipindut ti ''Ctrl-F5'' wenno''Ctrl-R'' (''⌘-R'' Mac)\n* '''Google Chrome:''' Ipindut ti ''Ctrl-Shift-R'' (''⌘-Shift-R'' iti Mac)\n* '''Internet Explorer:''' Tenglen ti ''Ctrl'' bayat nga ipindut ti ''Ipasaradiwa'', wenno ipindut ti ''Ctrl-F5''\n* '''Opera:''' Dalusan ti cache iti ''Ramramit → Kakaykayatan''",
-       "usercssyoucanpreview": "'''Paammo:''' Usaren ti \"{{int:showpreview}}\" a buton ti panagsubok ti baro a CSS sakbay nga idulinmo.",
-       "userjsyoucanpreview": "'''Paammo:''' Usaren ti \"{{int:showpreview}}\" a buton ti panagsubok ti baro a JavaScript sakbay nga idulinmo.",
-       "usercsspreview": "'''Laglagipem nga ipadpadasmo laeng daytoy a CSS.'''\n'''Saan pay a naidulin!'''",
-       "userjspreview": "'''Laglagipem nga ipadpadasmo laeng daytoy a JavaScript.'''\n'''Saan pay a naidulin!'''",
-       "sitecsspreview": "'''Laglagipem nga ipadpadasmo laeng daytoy a CSS.'''\n'''Saan pay a naidulin!'''",
-       "sitejspreview": "'''Laglagipem nga ipadpadasmo laeng ti kodigo daytoy a JavaScript.'''\n'''Saan pay nga naidulin!'''",
-       "userinvalidcssjstitle": "'''Ballaag:''' Awan ti kudil a \"$1\".\nAnnawid a .css ken .js dagiti titulo ket agususar ti babassit a letra, a kas dagiti {{ns:user}}:Foo/vector.css saan ket a {{ns:user}}:Foo/Vector.css.",
+       "userpage-userdoesnotexist": "Ti pakabilangan ti agar-aramat ni \"$1\" ket saan a nakarehistro. \nPangngaasi a kitaem no kayatmo ti agpartuat/agurnos iti daytoy a panid.",
+       "userpage-userdoesnotexist-view": "Ti pakabilangan ti agar-aramat ni \"$1\" ket saan a nakarehistro.",
+       "blocked-notice-logextract": "Agdama a naserraan daytoy nga agar-aramat.\nTi naudi a listaan ti pannakaserra ket naited dita baba para iti reperensia:",
+       "clearyourcache": "<strong>Nota:</strong> Kalpasan ti panangidulin, koma ket masapul nga ipalabas ti cahe ti pagbasabasam tapno makita dagiti sinukatam.\n* <strong>Firefox / Safari:</strong>  Tenglen ti <em>Shift</em> bayat a pinduten ti <em>Reload</em>, wenno talmegan ti <em>Ctrl-F5</em> wenno <em>Ctrl-R</em> (<em>⌘-R</em> iti Mac)\n* <strong>Google Chrome:</strong> Talmegan ti <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> iti Mac)\n* <strong>Internet Explorer:</strong> Tenglen ti <em>Ctrl</em> bayat a pinduten ti <em>Refresh</em>, wenno talmegan ti <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Dalusan ti cache iidiay <em>Tools → Preferences</em>",
+       "usercssyoucanpreview": "<strong>Paammo:</strong>  Usaren ti buton ti \"{{int:showpreview}}\" tapno masubokan ti baro a CSS sakbay nga agidulin.",
+       "userjsyoucanpreview": "<strong>Pammo:</strong> Usaren ti buton ti \"{{int:showpreview}}\" tapno masubokan ti baro a JavaScript sakbay nga agidulin.",
+       "usercsspreview": "<strong>Laglagipem nga ipadpadasmo laeng ti bukodmo a CSS ti agar-aramat.\nSaan pay a naidulin!</strong>",
+       "userjspreview": "<strong>Laglagipem a subsubokam/ipadpadasmo ti bukodmo a JavaScript ti agar-aramat.\nSaan pay a naidulin!</strong>",
+       "sitecsspreview": "<strong>Laglagipem nga ipadpadasmo laeng daytoy a CSS.\nSaan pay a naidulin!</strong>",
+       "sitejspreview": "<strong>Laglagipem nga ipadpadasmo laeng daytoy a kodigo ti JavaScript.\nSaan pay nga naidulin!</strong>",
+       "userinvalidcssjstitle": "<strong>Ballaag:</strong> Awan ti kudil a \"$1\".\nDagiti panid ti naiduma a .css ken .js ket agus-usar ti titulo ti bassit a letra, kas ti {{ns:user}}:Foo/vector.css saan a kas ti {{ns:user}}:Foo/Vector.css.",
        "updated": "(Napabaro)",
-       "note": "'''Paammo:'''",
-       "previewnote": "'''Laglagipem a daytoy ket panagipadas laeng.'''\nDagiti sinukatam ket saan pay a naidulin!",
+       "note": "<strong>Nota:</strong>",
+       "previewnote": "<strong>Laglagipem a daytoy ket panagipadas laeng.</strong>\nDagiti sinukatam ket saan pay a naidulin!",
        "continue-editing": "Mapan idiay pagurnosan a lugar",
-       "previewconflict": "Daytoy a panagpadas ket agiparang ti testo dita ngato a panagurnos a lugar a kasla agparang no kayatmo nga idulin.",
-       "session_fail_preview": "'''Pasensia! Saanmi a maaramid ti panag-urnos gapu ngamin ta naawanan ti gimong ti data.'''\nPangngaasi a padasem manen.\nNo saan pay a mabalin, padasem ti [[Special:UserLogout|rummuar]] ken sumrekka manen.",
-       "session_fail_preview_html": "'''Pasensia! Saanmi a maaramid ti panagurnosmo ngamin ket naawanan ti gimong ti datos.'''\n\n''Gapu ti {{SITENAME}} ket addaa ti nakilaw a HTML a nakapabaelan, ti panagpadas ket nailemmeng a kas pagan-annadan kadagiti panagraut ti dakes a JavaScript.''\n\n'''No daytoy ket pudno a panag-urnos, pangngaasi a padasem manen.'''\nNo saan pay a mabalin, padasem ti [[Special:UserLogout|rummuar]] ken sumrekka manen.",
-       "token_suffix_mismatch": "'''Ti panag-urnosmo ket saan a naawat ngamin ket ti klientem ket dinadaelna ti kuldit ti kababalin idiay panagpudno ti panag-urnos.'''\nTi panag-urnos ket saan a naawat tapno mapawilan ti panakadadael ti testo ti panid.\nMapasamak daytoy no agus-usarka ti saan a nasayaat a naibasta ti sapot a di ammo a pannakbagi a panagserbi.",
-       "edit_form_incomplete": "'''Adda dagiti paset ti panag-urnos a porma a saan a nakadanon dita server; kitkitaen nga dagiti panag-urnosmo ket saan a naikkatan ken padasem manen.'''",
+       "previewconflict": "Daytoy a panagpadas ket mangipakita ti testo iti lugar ti akin-ngato a pangurnosan ti testo a kasla agparang no piliem nga idulin.",
+       "session_fail_preview": "<strong>Pasensia! Saanmi a maproseso ti panag-urnosmo gapu ta naawanan ti sesion ti datos.</strong>\nPangngaasi a padasen manen.\nNo saan pay a mabalin, padasen ti [[Special:UserLogout|rummuar]] ken sumrek manen.",
+       "session_fail_preview_html": "<strong>Pasensia! Saanmi a maproseso ti panag-urnosmo gapu ta naawanan ti sesion ti datos.</strong>'\n\n<em>Gapu ta ti {{SITENAME}} ket addaan iti naata a HTML a nakapabaelan, ti panagpadas ket nailemmeng a kas pagan-annadan kadagiti panagraut ti dakes a JavaScript.</em>\n\n<strong>No daytoy ket pudno a panag-urnos, pangngaasi a padasem manen.</strong>\nNo saan pay a mabalin, padasen ti [[Special:UserLogout|rummuar]] ken sumrek manen.",
+       "token_suffix_mismatch": "<strong>Ti panag-urnosmo ket saan a naawat ngamin ket ti klientem ket dinadaelna dagiti karakter ti tuldek iti tandaan ti panag-urnos.</strong>\nTi panag-urnos ket saan a naawat tapno mapawilan ti pannakadadael ti testo ti panid.\nSagpaminsan a mapasamak daytoy no agus-usarka ti saan a nasayaat a naibatay ti web ti di ammo a pannakbagi a serbisio.",
+       "edit_form_incomplete": "<strong>Adda dagiti paset ti pagurnosan a porma a saan a nakadanon dita server; mamindua a kitaen dagiti panag-urnosmo ket sibubukel ken padasen manen.</strong>",
        "editing": "Ur-urnosen ti $1",
        "creating": "Agparpartuat ti $1",
        "editingsection": "Ur-urnosen ti $1 (paset)",
        "editingcomment": "Ur-urnosen ti $1 (baro a paset)",
-       "editconflict": "Adda kasinnungat ti panag-urnos: $1",
-       "explainconflict": "Adda sabali a nagsukat iti daytoy a panid idi nangrugika a nagurnos.\nTi ngato a lugar ti testo ket adda dagiti nagyanna a testo ti panid a kasla agdama a kitana.\nTi inurnosmo ket maipakita dita babba a lugar ti testo\nIpatiponmo dagiti sinukatam idiay lugar ti testo.\n'''Iti laeng''' testo dita ngato a lugar ti testo ti maidulin no pindutem ti \"{{int:savearticle}}\".",
+       "editconflict": "Kasinnungat ti panag-urnos: $1",
+       "explainconflict": "Adda sabali a nagsukat iti daytoy a panid idi nangrugika a nagurnos.\nTi akinngato a lugar ti testo ket aglaon ti testo ti panid iti agdama kaddana.\nDagiti sinukatam ket maipakita iti akinbabba a lugar ti testo.\nNasken nga itiponmoto dagiti sinukatam iti adda a testo.\nTi <strong>laeng</strong> testo iti akinngato a lugar ti testo ti maidulinto no talmegam ti \"{{int:savearticle}}\".",
        "yourtext": "Ti testom",
-       "storedversion": "Bersion a naidulin",
-       "nonunicodebrowser": "'''Ballaag: Ti  pabasabasam ket saan a naikeddeng ti Unicode .'''\nAdda sabali a mausar tapno makaurnoska kadagiti panid: Ti saan nga-ASCII a kababalin ket agparang iti pagurnosan a kahon a kas dagiti heksadesimal a kodigo.",
-       "editingold": "'''Ballag: Ur-urnosem ti daan a panag-baliw iti daytoy a panid.'''\nNo idulinmo, mapukaw amin a sinukatam iti daytoy a panag-baliw.",
-       "yourdiff": "Dagiti nagdudumaan",
-       "copyrightwarning": "Laglagipenyo koma, apo, nga amin a maiparawad iti {{SITENAME}} ket maibilang a mairuar babaen ti $2 (kitaen ti $1 para kadagiti salaysay). \nNo dimo kayat a ti sinuratmo ket maurnos nga awanan-asi ken maiwaras nga awan sungsungbatan kenka, saanmo laengen nga ip-ipan wenno ipabpablaak ditoy.<br />\nKasta met nga ikarim kadakami a bukodmo a sinurat wenno gapuanan daytoy, wenno tinuladmo manipud ti maysa a nawaya a pagturayan ti publiko wenno ti kapadpadana a nawaya a nagtaudan.\n '''Saan a mangited ti adda karbenganna a panagipablaak nga obra no awan ti  pammalubos!'''",
-       "copyrightwarning2": "Pangngaasiyo, apo, a laglagipen nga amin a maiparawad iti {{SITENAME}} ket mabalin a maurnos, masuktan, wenno ikkaten dagiti sabali pay nga agar-aramat.\nNo dimo kayat a ti sinuratmo ket maurnos nga awanan-asi ken maiwaras nga awan sungsungbatan kenka, saanmo laengen nga ip-ipan wenno ipabpablaak ditoy.<br />\nKasta met nga ikarim kadakami a bukodmo a sinurat wenno gapuanan daytoy, wenno tinuladmo manipud ti maysa a nawaya a pagturayan ti publiko wenno ti kapadpadana a nawaya a pagtaudan (kitaen ti $1 para iti salaysay).\n'''Saan a mangipan iti adda ti karbenganna a panagpablaak nga obra no awan ti  pammalubos!'''",
-       "longpageerror": "'''Biddut: Ti testo nga intedmo ket {{PLURAL:$1|maysa a kilobyte|$1 kil-kilobyte}} a katiddog, nga at-atiddog ngem ti kangatuan iti  {{PLURAL:$2|maysa a kilobyte|$2 kil-kilobyte}}.'''\nIsu ti gapuna a saan a maidulin.",
-       "readonlywarning": "'''Ballaag: Narikepan ti database tapno mataripatu, isu a saanmo a mabalin nga idulin dagita inurnosmo tattan.'''\nMabalinmo ti agkopia ken agikabil ti testom iti maysa a testo a papeles ken idulinmo para iti panagusar no madamdama.\n\nTi administrador a nangrikep ket nangited iti daytoy a palawag: $1",
-       "protectedpagewarning": "'''Ballaag:  Daytoy a panid ket nasalakniban tapno dagiti laeng agar-aramat nga adda ti gundaway nga administrador ti makaurnos ditoy.'''\nTi nakaudi a naikabil a listaan ket adda dita baba tapno usaren a reperensia:",
-       "semiprotectedpagewarning": "'''Pakaammo:'''Nasalakniban daytoy a panid tapno dagiti laeng nakarehistro nga agar-aramat ti makaurnos ditoy.\nTi naudi a naikabil a listaan ket adda dita baba tapno usaren a reperensia:",
-       "cascadeprotectedwarning": "'''Ballaag:''' Daytoy a panid ket nasalakniban tapno dagiti laeng administrador nga adda ti pammalubos ti makaurnos ngamin ket nairaman kadagiti sumaganad a nasalakniban iti sariap\n{{PLURAL:$1|a panid|a pampanid}}:",
-       "titleprotectedwarning": "'''Ballaag:  Nasalakniban daytoy a panid tapno [[Special:ListGroupRights|dagiti naisangayan a karbengan ]] ket nasken ti makapartuat iti daytoy.'''\nTi kinaudi a naikabil iti listaan ket naikabil dita baba tapno usaren a reperensia:",
+       "storedversion": "Rebision a naidulin",
+       "nonunicodebrowser": "<strong>Ballaag: Ti pabasabasam ket saan a maitunos iti Unicode .</strong>\nAdda sabali a mausar tapno makaurnoska kadagiti panid: Ti saan nga-ASCII a karakter ket agparang iti pagurnosan a kahon a kas dagiti heksadesimal a kodigo.",
+       "editingold": "<strong>Ballag: Ur-urnosem ti daan a rebision iti daytoy a panid.</strong>\nNo idulinmo, ti aniaman a naramid a binaliwan manipud iti daytoy a rebision ket mapukawto.",
+       "yourdiff": "Paggigiddiatan",
+       "copyrightwarning": "Pangngaasi a laglagipen nga amin a kontribusion iti {{SITENAME}} ket naikeddeng a naipablaak babaen ti babaen ti $2 (kitaen ti $1 para kadagiti salaysay). \nNo dimo kayat a ti sinuratmo ket maurnos nga awanan-asi ken maiwaras nga awan sungsungbatan kenka, saanmon nga ited ditoy.<br />\nIkarkarim pay kadakami a bukodmo a sinurat daytoy, wenno kinopia manipud ti publiko a dominio wenno ti kapadpadana a nawaya a nagtaudan.\n<strong>Saan a mangited ti nakarbengan ti kopia nga obra no awan iti pammalubos!</strong>",
+       "copyrightwarning2": "Pangngaasi a laglagipen nga amin a kontribusion iti {{SITENAME}} ket mabalin a maurnos, mabaliwan, wenno ikkaten dagiti sabali a kontributor.\nNo dimo kayat a ti sinuratmo ket maurnos nga awanan-asi ken maiwaras nga awan sungsungbatan kenka, saanmon nga ited ditoy.<br />\nIkarkarim pay kadakami a bukodmo a sinurat daytoy, wenno kinopia manipud ti publiko a dominio wenno ti kapadpadana a nawaya a nagtaudan. (kitaen ti $1 para kadagiti salaysay).\n<strong>Saan a mangited ti nakarbengan ti kopia nga obra no awan iti pammalubos!</strong>",
+       "longpageerror": "<strong>Biddut: Ti testo nga intedmo ket {{PLURAL:$1|maysa a kilobyte|$1 kil-kilobyte}} ti katiddogna, nga at-atiddog ngem ti kangatuan iti  {{PLURAL:$2|maysa a kilobyte|$2 kil-kilobyte}}.</strong>\nSaan a mabalin a maidulin.",
+       "readonlywarning": "<strong>Ballaag: Narikepan ti database tapno mataripato, isu a saanmo a mabalin nga idulin dagita inurnosmo tattan.</strong>\nMabalinmo ti agkopia ken agipegket ti testom iti papeles ti testo ken idulinmo daytoy intono madamdama.\n\nTi administrador a nangrikep ket nangited iti daytoy a palawag: $1",
+       "protectedpagewarning": "<strong>Ballaag: Daytoy a panid ket nasalakniban tapno dagiti laeng agar-aramat nga addaan iti gundaway nga administrador ti makaurnos ditoy.</strong>\nTi naudi a naikabil iti listaan ket naited dita baba para iti reperensia:",
+       "semiprotectedpagewarning": "<strong>Nota:</strong> Nasalakniban daytoy a panid tapno dagiti laeng nakarehistro nga agar-aramat ti makaurnos ditoy.\nTi naudi a naikabil iti listaan ket naited dita baba para iti reperensia:",
+       "cascadeprotectedwarning": "<strong>Ballaag:</strong> Daytoy a panid ket nasalakniban tapno dagiti laeng agar-aramat nga addaan iti gundaway nga administrador ti makaurnos ngamin ket nairaman kadagiti sumaganad a nasalakniban iti sariap\n{{PLURAL:$1|a panid|a pampanid}}:",
+       "titleprotectedwarning": "<strong>Ballaag:  Nasalakniban daytoy a panid tapno [[Special:ListGroupRights|dagiti naisangayan ti karbengan]] ket nasken a makapartuat iti daytoy.</strong>\nTi naudi a naikabil iti listaan ket naited dita baba para iti reperensia:",
        "templatesused": "{{PLURAL:$1|Ti plantilia|Dagiti plantilia}} a naaramat iti daytoy a panid:",
        "templatesusedpreview": "{{PLURAL:$1|Ti plantilia|Dagiti plantilia}} a naaramat iti daytoy a panagpadas:",
        "templatesusedsection": "{{PLURAL:$1|Ti plantilia|Dagiti plantilia}} a naaramat iti daytoy a paset:",
        "template-protected": "(nasalakniban)",
        "template-semiprotected": "(nasalakniban-bassit)",
-       "hiddencategories": "Daytoy a panid ket kameng  {{PLURAL:$1|ti 1 a nailemmeng a kategoria|dagiti $1 a nailemmeng a kategoria}}:",
-       "nocreatetext": "Pinaritan ti {{SITENAME}} ti pannakabael a panagaramid iti kabarbaro a pampanid.\nMabalinmo ti agsubli ken urnosen ti adda a panid, wenno [[Special:UserLogin|sumrek wenno agaramid ti pakabilangan]].",
+       "hiddencategories": "Daytoy a panid ket kameng {{PLURAL:$1|ti 1 a nailemmeng a kategoria|dagiti $1 a nailemmeng a kategoria}}:",
+       "nocreatetext": "Ginawidan ti {{SITENAME}} ti abilidad nga agpartuat kadagiti baro a panid.\nMabalinmo ti agsubli ken agurnos ti adda a panid, wenno [[Special:UserLogin|sumrek wenno agapartuat ti pakabilangan]].",
        "nocreate-loggedin": "Awan ti pammalubosmo nga agpartuat kadagiti baro a panid.",
-       "sectioneditnotsupported-title": "Saan a nasuportaran ti panagurnos ti paset",
+       "sectioneditnotsupported-title": "Saan a nasuportaran ti panag-urnos ti paset",
        "sectioneditnotsupported-text": "Saan a nasuportaran ti panag-urnos ti paset iti daytoy a panid.",
        "permissionserrors": "Biddut ti pammalubos",
        "permissionserrorstext": "Awan ti pammalubosmo nga agaramid iti dayta, gapu ti sumaganad {{PLURAL:$1|a rason|a rasrason}}:",
        "permissionserrorstext-withaction": "Awan ti pammalubosmo nga $2, gapu ti sumaganad a {{PLURAL:$1|rason|rasrason}}:",
-       "recreate-moveddeleted-warn": "'''Ballaag: Agparpartuatka manen ti dati a naikkat a panid'''\n\nNasken a siguraduem no maikanatad nga ituloymo nga urnosen daytoy a panid.\nTi pannakaikkat ken pannakaiyalis a listaan para iti daytoy a panid ket adda ditoy a pakakitaan:",
-       "moveddeleted-notice": "Naikkaten daytoy a panid.\nTi listaan a pannakaikkat ken pannakaiyalis ti panid ket naikabil dita baba tapno usaren a reperensia.",
+       "recreate-moveddeleted-warn": "<strong>Ballaag: Agparpartuatka manen ti dati a naikkat a panid.</strong>\n\nUsigem koma no maitutop ti agtuloy nga agurnos iti daytoy a panid.\nTi listaan ti pannakaikkat ken pannakaiyalis para iti daytoy a panid ket naited ditoy para iti pakainugotan:",
+       "moveddeleted-notice": "Naikkaten daytoy a panid.\nTi listaan ti pannakaikkat ken pannakaiyalis para iti panid ket naited dita baba para iti reperensia.",
        "log-fulllog": "Kitaem ti napno a listaan",
        "edit-hook-aborted": "Ti panag-urnos ket pinasardeng babaen ti kawit.\nAwan ti intedna a palawag.",
        "edit-gone-missing": "Saan a mapabaro daytoy a panid.\nKasla met naikkaten.",
-       "edit-conflict": "Adda kasinnungat ti panag-urnos.",
-       "edit-no-change": "Ti inurnosmo ket saan a naikaskaso, ngamin ket awan ti nasukatan a testo.",
+       "edit-conflict": "Kasinnungat ti panag-urnos.",
+       "edit-no-change": "Ti inurnosmo ket saan a naikaskaso ngamin ket awan ti naaramid a pannakasukat iti testo.",
        "postedit-confirmation-created": "Ti panid ket napartuaten.",
-       "postedit-confirmation-restored": "Ti panid ket naisublin.",
+       "postedit-confirmation-restored": "Ti panid ket naipulangen.",
        "postedit-confirmation-saved": "Ti inurnosmo ket naidulinen.",
        "edit-already-exists": "Saan a makaaramid ti baro a panid.\nAdda met daytoyen.",
        "defaultmessagetext": "Kasisigud a testo ti mensahe",
-       "content-failed-to-parse": "Napaay a nausig ti $2 a linaon para iti $1 a modelo: $3",
+       "content-failed-to-parse": "Napaay a mawaswas ti $2 a linaon para iti $1 a modelo: $3",
        "invalid-content-data": "Imbalido a datos ti linaon",
-       "content-not-allowed-here": "Ti \"$1\" a linaon ket saan a maipalubos idiay panid ti [[$2]]",
-       "editwarning-warning": "Ti ipapanaw iti daytoy a panid ket makapataud ti pannakapukaw kadagiti aniaman a binalbaliwam.\nNo nakastrekka, mabalinmo nga ibaldado daytoy a ballaag idiay \"{{int:prefs-editing}}\" a paset kadagiti kakaykayatam.",
+       "content-not-allowed-here": "Ti \"$1\" a linaon ket saan a maipalubos iti panid ti [[$2]]",
+       "editwarning-warning": "Ti ipapanaw iti daytoy a panid ket makapataud ti pannakapukaw kadagiti aniaman a binalbaliwam.\nNo nakastrekka, mabalinmo nga ibaldado daytoy a ballaag iti \"{{int:prefs-editing}}\" a paset kadagiti kakaykayatam.",
        "editpage-notsupportedcontentformat-title": "Ti pormat ti linaon ket saan a nasuportaran",
        "editpage-notsupportedcontentformat-text": "Ti pormat ti linaon ti $1 ket saan a nasuportaran babaen ti modelo ti linaon ti $2.",
        "content-model-wikitext": "wikitext",
        "content-model-text": "naranas a testo",
        "content-model-javascript": "JavaScript",
        "content-model-css": "CSS",
-       "expensive-parserfunction-warning": "'''Ballaag:''' Daytoy a panid ket adu unay kadagiti nangina a parser a pamay-an  a panagtawtawag.\n\nAdda koman basbasit ngem $2 {{PLURAL:$2|a panagtawtawag|kadagiti panagtawtawag}}, adda {{PLURAL:$1|tattan $1 a panagtawtawag|tattan kadagiti $1 a panagtawtawag}}.",
+       "expensive-parserfunction-warning": "<strong>Ballaag:</strong> Daytoy a panid ket adu unay kadagiti nangina a parser a pamay-an a panagtawtawag.\n\nAdda koman basbasit ngem $2 {{PLURAL:$2|a panagtawtawag|kadagiti panagtawtawag}}, adda {{PLURAL:$1|tattan iti $1 a panagtawtawag|tattan kadagiti $1 a panagtawtawag}}.",
        "expensive-parserfunction-category": "Dagiti panid nga adda ti adu unay a nangina a parser a pamay-an a panagtawtawag",
-       "post-expand-template-inclusion-warning": "'''Ballaag:''' Dakkel unay ti nairaman a kadakkel ti plantilia.\nAdda dagiti plantilia a saanto a mairaman.",
+       "post-expand-template-inclusion-warning": "<strong>Ballaag:</strong> Dakkel unay ti nairaman a kadakkel ti plantilia.\nAdda dagiti plantilia a saanto a mairaman.",
        "post-expand-template-inclusion-category": "Pampanid nga ayan ti plantilia a nagsobra ti kadakkel ti rukod a nairaman",
-       "post-expand-template-argument-warning": "'''Ballaag:''' Daytoy a panid ket aglaon ti saan a basbasit ngem maysa a panangipalawag ti plantilia a dakkel unay ti panagpadakkelna.\nDagitoy a panangipalawag ket naikkaten.",
-       "post-expand-template-argument-category": "Dagiti panid a naglaon ti naikkat a plantilia kadagiti kasinnungat",
-       "parser-template-loop-warning": "Adda nasarakan a silo ti plantilia: [[$1]]",
-       "parser-template-recursion-depth-warning": "Ti kinauneg ti panagdullit ti plantilia ket nagpatingga ti napalabes ($1)",
-       "language-converter-depth-warning": "Ti kauneg ti panagaramid ti pagsasao ket napalabes ti agpatingga a ($1)",
+       "post-expand-template-argument-warning": "<strong>Ballaag:</strong> Daytoy a panid ket aglaon ti saan a basbasit ngem maysa a panangipalawag ti plantilia a dakkel unay ti panagpadakkelna.\nDagitoy nga argumento ket saanen a nairaman.",
+       "post-expand-template-argument-category": "Pampanid a naglaon dagiti saan a nairaman nga argumento ti plantilia",
+       "parser-template-loop-warning": "Nakaduktal ti silo ti plantilia: [[$1]]",
+       "parser-template-recursion-depth-warning": "Nalabsan ti patingga ti panagdullit ti kinauneg ti plantilia ($1)",
+       "language-converter-depth-warning": "Nalabsan ti patingga ti pagbaliwen a kinauneg ti pagsasao ($1)",
        "node-count-exceeded-category": "Dagiti panid a simmurok ti bilang ti nodo",
        "node-count-exceeded-category-desc": "Ti kategoria para kadagiti panid a nalabsan ti bilang ti nodo.",
        "node-count-exceeded-warning": "Ti panid ket nasurokanna ti bilang ti nodo",
        "expansion-depth-exceeded-category": "Dagiti panid a nasurokan ti kauneg ti panagpadakkel",
        "expansion-depth-exceeded-category-desc": "Daytoy ket kategoria para kadagiti panid a nalabsan ti kauneg ti panagpadakkel.",
        "expansion-depth-exceeded-warning": "Ti panid ket nasurokanna ti kauneg ti panagpadakkel",
-       "parser-unstrip-loop-warning": "Adda nakita a di-naukisan a silo",
-       "parser-unstrip-recursion-limit": "Ti di-naukisan a panagsumro manen a patingga ket nasurokan ($1)",
-       "converter-manual-rule-error": "Adda biddut a naduktalan idiay manual nga alagaden ti panagbalbaliw ti pagsasao",
-       "undo-success": "Ti panag-urnos ket saan a maisubli.\nPangngaasi a kitaen ti pagipadaan dita baba tapno maamuan no agpaypayso ti kayatmo nga aramiden, ken idulin dagiti sinukatan dita baba tapno malpas ti panagsubli ti inurnos.",
+       "parser-unstrip-loop-warning": "Nakaduktal ti di-naukisan a silo",
+       "parser-unstrip-recursion-limit": "Nalabsan ti patingga ti panagdullit ti di-naukisan ($1)",
+       "converter-manual-rule-error": "Adda biddut a naduktalan iti manual nga alagaden ti panagbalbaliw ti pagsasao",
+       "undo-success": "Ti panag-urnos ket saan a maisubli.\nPangngaasi a kitaen ti panangipada dita baba tapno maammuan no daytoy ti kayatmo nga aramiden, ken kalpasanna idulin dagiti sinukatan dita baba tapno malpas ti panagsubli ti inurnos.",
        "undo-failure": "Ti inurnos ket saan a maipasubli gaputa adda dagiti nakisinnungat a patingnga a naurnos.",
        "undo-norev": "Saan a maibabawi ti naurnos ngamin ket awan daytoy wenno mabalin a naikkaten.",
        "undo-nochange": "Ti inurnos ket kasla naibabawin.",
        "undo-summary": "Ibabawi ti $1 a binaliwan babaen ni [[Special:Contributions/$2|$2]] ([[User talk:$2|tungtungan]])",
        "undo-summary-username-hidden": "Isubli ti $1 a binaliwan babaen ti nailemmeng nga agar-aramat",
-       "cantcreateaccounttitle": "Saan a makaaramid ti pakabilangan",
-       "cantcreateaccount-text": "Ti panagaramid ti pakabilangan manipud ti daytoy nga IP a pagtaengan ('''$1''') ket sinerraan babaen ni [[User:$3|$3]].\n\nTi inted a rason babaen ni $3 ket ''$2''",
-       "cantcreateaccount-range-text": "Ti pannakapartuat ti pakabilangan manipud kadagiti pagtaengan ti IP iti sakop ti '''$1''', a mairaman ti IP a pagtaengam ('''$4'''), ket sinerraan babaen ni [[User:$3|$3]].\n\nTi inted a rason babaen ni $3 ket ''$2''",
+       "cantcreateaccounttitle": "Saan a makapartuat ti pakabilangan",
+       "cantcreateaccount-text": "Ti panagpartuat ti pakabilangan manipud ti daytoy nga IP a pagtaengan (<strong>$1</strong>) ket sinerraan babaen ni [[User:$3|$3]].\n\nTi inted a rason babaen ni $3 ket <em>$2</em>",
+       "cantcreateaccount-range-text": "Ti panagpartuat ti pakabilangan manipud kadagiti pagtaengan ti IP iti sakop ti '''$1''', a mairaman ti IP a pagtaengam ('''$4'''), ket sinerraan babaen ni [[User:$3|$3]].\n\nTi inted a rason babaen ni $3 ket ''$2''",
        "viewpagelogs": "Kitaen dagiti listaan para iti daytoy a panid",
        "nohistory": "Awan ti pakasaritaan ti panag-urnos iti daytoy a panid.",
-       "currentrev": "Kinaudi a binaliwan",
-       "currentrev-asof": "Kinaudi a panagbalbaliw manipud idi $1",
-       "revisionasof": "Panagbalbaliw manipud idi $1",
-       "revision-info": "Panagbaliw manipud idi $1 babaen ni {{GENDER:$6|$2}}$7",
-       "previousrevision": "←Daan a panagbalbaliw",
-       "nextrevision": "Nabarbaro a panagbalbaliw→",
-       "currentrevisionlink": "Kinaudi a binaliwan",
+       "currentrev": "Kinaudi a rebision",
+       "currentrev-asof": "Kinaudi a rebision manipud idi $1",
+       "revisionasof": "Rebision manipud idi $1",
+       "revision-info": "Rebision manipud idi $1 babaen ni {{GENDER:$6|$2}}$7",
+       "previousrevision": "← Nadadaan a rebision",
+       "nextrevision": "Nabarbaro a rebision →",
+       "currentrevisionlink": "Kinaudi a rebision",
        "cur": "agdama",
        "next": "sumaruno",
        "last": "naudi",
        "page_first": "umuna",
        "page_last": "naudi",
-       "histlegend": "Panagpili ti diperensia: Markaan dagiti kahon ti radio kadagiti panagbaliw tapno maipada ken pinduten ti serrek wenno ti buton dita baba.<br />\nLeyenda: <strong>({{int:cur}})</strong> = naggidiatan ti kinaudi a panagbaliw, <strong>({{int:last}})</strong> = naggidiatan ti sarsarunuen a panagbaliw , <strong>{{int:minoreditletter}}</strong> = bassit a panagbaliw.",
+       "histlegend": "Panagpili ti diperensia: Markaan dagiti kahon ti radio kadagiti rebision tapno maipada ken pinduten ti enter wenno ti buton dita baba.<br />\nLeyenda: <strong>({{int:cur}})</strong> = naggidiatan ti kinaudi a rebision, <strong>({{int:last}})</strong> = naggidiatan ti sarsarunuen a rebision, <strong>{{int:minoreditletter}}</strong> = bassit nga urnos.",
        "history-fieldset-title": "Agbasabasa ti pakasaritaan",
        "history-show-deleted": "Naikkat laeng",
        "histfirst": "kadaanan",
        "histlast": "kabaruan",
        "historysize": "({{PLURAL:$1|1 byte|dagiti $1 a byte}})",
-       "historyempty": "(blanko)",
-       "history-feed-title": "Pakasaritaan ti panagbalbaliw",
-       "history-feed-description": "Pakasaritaan ti panagbalbaliw para iti daytoy a panid ditoy a wiki",
-       "history-feed-item-nocomment": "$1 iti $2",
+       "historyempty": "(awan linaon)",
+       "history-feed-title": "Pakasaritaan ti rebision",
+       "history-feed-description": "Pakasaritaan ti rebision para iti daytoy a panid ditoy a wiki",
+       "history-feed-item-nocomment": "$1 idi $2",
        "history-feed-empty": "Awan ti kiniddaw a panid.\nMabalin a naikkat manipud ti daytoy a wiki, wenno nanaganan manen.\nPadasem ti [[Special:Search|agbiruk ditoy a wiki]] para kadagiti maitutop a baro a panid.",
        "rev-deleted-comment": "(naikkat ti pakabuklan ti inurnos)",
        "rev-deleted-user": "(naikkat ti nagan ti agar-aramat)",
-       "rev-deleted-event": "(naikkat ti aramid a listaan)",
-       "rev-deleted-user-contribs": "[ti nagan ti agar-aramat wenno IP a pagtaengan ket naikkat - ti inurnos ket nailemmeng kadagiti nagparawad]",
-       "rev-deleted-text-permission": "Ti pannakabaliw daytoy a panid ket '''naikkaten'''.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti naikkat].",
-       "rev-deleted-text-unhide": "Ti pannakabaliw daytoy a panid ket '''naikkaten'''.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti naikkat].\nMabalinmo pay a [$1 makita daytoy a panakabaliw] no kayatmo ti agtuloy.",
-       "rev-suppressed-text-unhide": "Ti pannakabaliw daytoy a panid ket '''napasardeng'''.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti napasardeng].\nMabalinmo pay a [$1 makita daytoy a panakabaliw] no kayatmo ti agtuloy.",
-       "rev-deleted-text-view": "Ti pannakabaliw daytoy a panid ket '''naikkaten'''.\nMabalinmo a kitaen; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti naikkat].",
-       "rev-suppressed-text-view": "Ti pannakabaliw daytoy a panid ket '''napasardeng'''.\nMabalinmo a kitaen; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti napasardeng].",
-       "rev-deleted-no-diff": "Saanmo a makita daytoy a paggiddiatan ngamin ket ti maysa a panagbaliw ket '''naikkat''.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti naikkat].",
-       "rev-suppressed-no-diff": "Saanmo a makita daytoy a paggiddiatan ngamin ket maysa a panagbaliwan ket '''naikkat''.",
-       "rev-deleted-unhide-diff": "Maysa a panagbaliw iti daytoy a paggiddiatan ket '''naikkaten'''.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti naikkat].\nMabalinmo pay a [$1 makita daytoy a paggiddiatan] no kayatmo ti agtuloy.",
-       "rev-suppressed-unhide-diff": "Maysa a panagbaliw iti daytoy a paggiddiatan ket '''napasardeng'''.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti napasardeng].\nMabalinmo pay a [$1 makita daytoy a paggiddiatan] no kayatmo ti agtuloy.",
-       "rev-deleted-diff-view": "Maysa a panagbaliw iti daytoy a paggiddiatan ket '''naikkaten'''.\nMabalinmo pay a kitaen daytoy a paggiddiatan; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti naikkat].",
-       "rev-suppressed-diff-view": "Maysa a panagbaliw iti daytoy a paggiddiatan ket '''napasardeng'''.\nMabalinmo pay a kitaen daytoy a paggiddiatan; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti napasardeng].",
-       "rev-delundel": "ipakita/ilemmeng",
+       "rev-deleted-event": "(naikkat ti listaan ti tignay)",
+       "rev-deleted-user-contribs": "[naikkat ti nagan ti agar-aramat wenno IP a pagtaengan - ti inurnos ket nailemmeng manipud kadagiti kontributor]",
+       "rev-deleted-text-permission": "Ti rebision daytoy a panid ket <strong>naikkaten</strong>.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
+       "rev-deleted-text-unhide": "Ti rebision daytoy a panid ket <strong>naikkaten</strong>.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].\nMabalinmo pay a [$1 makita daytoy a rebision] no kayatmo ti agtuloy.",
+       "rev-suppressed-text-unhide": "Ti rebision daytoy a panid ket <strong>napasardeng</strong>.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti panagpasardeng].\nMabalinmo pay a [$1 makita daytoy a rebision] no kayatmo ti agtuloy.",
+       "rev-deleted-text-view": "Ti rebision daytoy a panid ket <strong>naikkaten</strong>.\nMabalinmo a kitaen; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
+       "rev-suppressed-text-view": "Ti rebision daytoy a panid ket <strong>napasardeng</strong>.\nMabalinmo a kitaen; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti panagpasardeng].",
+       "rev-deleted-no-diff": "Saanmo a makita daytoy a paggiddiatan ngamin ket ti maysa a rebision ket <strong>naikkaten</strong>.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
+       "rev-suppressed-no-diff": "Saanmo a makita daytoy a paggiddiatan ngamin ket maysa kadagiti rebision ket <strong>naikkaten</strong>.",
+       "rev-deleted-unhide-diff": "Maysa a rebision iti daytoy a paggiddiatan ket <strong>naikkaten</strong>.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].\nMabalinmo pay a laeng a [$1 makita daytoy a paggiddiatan] no kayatmo ti agtuloy.",
+       "rev-suppressed-unhide-diff": "Maysa a rebision iti daytoy a paggiddiatan ket <strong>napasardeng</strong>.\nDagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti panagpasardeng].\nMabalinmo pay a laeng a [$1 makita daytoy a paggiddiatan] no kayatmo ti agtuloy.",
+       "rev-deleted-diff-view": "Maysa a rebision iti daytoy a paggiddiatan ket <strong>naikkaten</strong>.\nMabalinmo pay a kitaen daytoy a paggiddiatan; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
+       "rev-suppressed-diff-view": "Maysa a rebision iti daytoy a paggiddiatan ket <strong>napasardeng</strong>..\nMabalinmo pay a kitaen daytoy a paggiddiatan; dagiti salaysay ket mabirukan idiay [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} listaan ti panagpasardeng].",
+       "rev-delundel": "baliwan ti pannakakita",
        "rev-showdeleted": "ipakita",
-       "revisiondelete": "Ikkaten/isubli dagiti naikkat a panagbaliw",
-       "revdelete-nooldid-title": "Imbalido ti napuntaan a panagbaliw",
-       "revdelete-nooldid-text": "Mabalin a saanmo nga imbaga ti pagpuntaan ti panagbaliw  (dagiti panagbaliwan) ti panagaramid daytoy,\nawan ti naibaga a panagbaliw, wenno padpadasem nga ilemlemmeng ti agdama a panagbaliw.",
+       "revisiondelete": "Ikkaten/isubli dagiti naikkat a rebision",
+       "revdelete-nooldid-title": "Imbalido ti puntaan a rebision",
+       "revdelete-nooldid-text": "Mabalin a saanmo nga imbaga dagiti puntaan a rebision iti panagaramid daytoy nga annong, awan ti nainaganan a rebision, wenno padpadasem nga ilemlemmeng ti agdama a rebision.",
        "revdelete-no-file": "Awan dayta nainaganan a papeles.",
-       "revdelete-show-file-confirm": "Sigurado kadi a kayatmo ti mangkita ti naikkat a baliwan ti papeles \"<nowiki>$1</nowiki>\" a naggapu idi $2 idi $3?",
+       "revdelete-show-file-confirm": "Siguradoka kadi a kayatmo ti mangkita ti naikkat a rebision ti papeles ti \"<nowiki>$1</nowiki>\" manipud idi $2 idi $3?",
        "revdelete-show-file-submit": "Wen",
-       "revdelete-selected-text": "{{PLURAL:$1|Napili a nabaliwan|Dagiti napili a nabaliwan}} iti [[:$2]]:",
+       "revdelete-selected-text": "{{PLURAL:$1|Napili a rebision|Dagiti napili a rebision}} iti [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Napili a bersion ti papeles|Dagiti napili a bersion ti papeles}} iti [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|Ti napili a listaan ti napasamak|Dagiti napili a listaan ti napasamak}}:",
        "revdelete-text-text": "Dagiti naikkat a rebision ket agparangto pay laeng iti panid ti pakasaritaan, ngem dagiti paset ti linaonda ket saanton a publiko a maserrekan.",
        "revdelete-text-file": "Dagiti naikkat a bersion ti papeles ket agparangto pay laeng iti pakasaritaan ti papeles, ngem dagiti paset ti linaonda ket saanton a publiko a maserrekan.",
        "logdelete-text": "Dagiti naikkat a listaan ti pasamak ket agparangto pay laeng kadagiti listaan, ngem dagiti paset ti linaonda ket saanton a publiko a maserrekan.",
-       "revdelete-text-others": "Dagiti sabali nga administrador iti {{SITENAME}} ket mabalindanto pay laeng a maserrekan ti nailemmeng a linaon ken mabalindanto manen ti mangisubli ti pannakaikkat babaen iti daytoy nga isu met laeng nga interface, malaksid no adda dagiti maipatinayon a maisaad a panangigawid.",
-       "revdelete-confirm": "Pangngaasi a pasingkedam a kayatmo nga aramiden daytoy, a maawatam dagiti pagbanagan, ket araramidem daytoy a segun iti [[{{MediaWiki:Policy-url}}|ti annuroten]].",
-       "revdelete-suppress-text": "Ti panagdepdep ket usaren '''laeng''' kadagiti sumaganad a kaso;\n* Makapataud ti libelo a pakaammo\n* Di maiparbeng a personal a pakaammo\n* : ''dagiti pagtaengan ken numero ti telepono, dagiti numero ti nailian a pakaipakaammuan, ken dadduma pay.''",
-       "revdelete-legend": "Ikabil dagiti panagiparit ti panagkita",
-       "revdelete-hide-text": "Testo ti binaliwan",
+       "revdelete-text-others": "Dagiti sabali nga administrador ket mabalindanto pay laeng a maserrekan ti nailemmeng a linaon ken mangisubli daytoy, malaksid no adda dagiti maipatinayon a maisaad a panangigawid.",
+       "revdelete-confirm": "Pangngaasi a pasingkedam a kayatmo nga aramiden daytoy, a maawatam dagiti pagbanagan, ken araramidem daytoy segun [[{{MediaWiki:Policy-url}}|ti annuroten]].",
+       "revdelete-suppress-text": "Ti panagdepdep ket usaren <strong>laeng</strong> kadagiti sumaganad a kaso;\n* Makapataud ti libelo a pakaammo\n* Di maiparbeng a personal a pakaammo\n* : <em>dagiti adres ti balay ken numero ti telepono, dagiti numero ti nailian a pakaipakaammuan, kdpy.</em>",
+       "revdelete-legend": "Isaad dagiti panangigawid ti panagkita",
+       "revdelete-hide-text": "Testo ti rebision",
        "revdelete-hide-image": "Ilemmeng ti linaon ti papeles",
        "revdelete-hide-name": "Ilemmeng ti aramid ken puntaan",
        "revdelete-hide-comment": "Pakabuklan ti inurnos",
-       "revdelete-hide-user": "Nagan ti agar-amat/ti IP a pagtaengan",
-       "revdelete-hide-restricted": "Depdepen ti datos a naggapu kadagiti administrador ken dagiti sabsabali",
+       "revdelete-hide-user": "Nagan ti agar-amat/IP a pagtaengan ti editor",
+       "revdelete-hide-restricted": "Depdepen ti datos manipud kadagiti administrador ken dagiti pay sabali",
        "revdelete-radio-same": "(saan a sukatan)",
        "revdelete-radio-set": "Nailemmeng",
        "revdelete-radio-unset": "Makita",
-       "revdelete-suppress": "Depdepen ti datos manipud kadagiti administrador ken dagiti sabsabali",
-       "revdelete-unsuppress": "Ikkaten dagiti pannakaiparit kadagiti naisubli a binaliwan",
+       "revdelete-suppress": "Depdepen ti datos manipud kadagiti administrador ken dagiti pay sabali",
+       "revdelete-unsuppress": "Ikkaten dagiti panangigawid kadagiti naipulang a rebision",
        "revdelete-log": "Rason:",
-       "revdelete-submit": "Ipakat {{PLURAL:$1|ti napili a panagbalbaliw|dagiti napili a panagbalbaliw}}",
-       "revdelete-success": "'''Balligi ti panagpabaro ti panagkita ti binalbaliwan.'''",
-       "revdelete-failure": "'''Saan a napabaro ti panagkita ti binalbaliwan.'''\n$1",
-       "logdelete-success": "'''Balligi ti panagikabil ti listaan ti panagkita.'''",
-       "logdelete-failure": "'''Napaay ti panagikabil ti listaan ti panagkita:'''\n$1",
+       "revdelete-submit": "Ipakat {{PLURAL:$1|ti napili a rebision|dagiti napili a rebision}}",
+       "revdelete-success": "<strong>Balligi ti panagpabaro ti panagkita ti rebision.</strong>",
+       "revdelete-failure": "<strong>Saan a napabaro ti panagkita ti rebision.</strong>\n$1",
+       "logdelete-success": "<strong>Balligi ti pannakaisaad ti listaan ti panagkita.</strong>",
+       "logdelete-failure": "<strong>Napaay ti pannakaisaad ti listaan ti panagkita:</strong>\n$1",
        "revdel-restore": "sukatan ti panagkita",
        "pagehist": "Pakasaritaan ti panid",
        "deletedhist": "Naikkat a pakasaritaan",
-       "revdelete-hide-current": "Biddut ti pannakailemmeng ti banag a napetsado a $2, $1: Daytoy ti kinaudi a panagbaliw\nSaan a mabalin a mailemmeng.",
-       "revdelete-show-no-access": "Biddut ti panangipakita ti banag a petsado a $2, $1: Daytoy ket namarkaan a \"nakedngan\".\nSaanmo a mabalin a serrekan.",
-       "revdelete-modify-no-access": "Biddut ti panagpabaro ti banag a petsado a $2, $1: Daytoy ket namarkaan a \"nakedngan\".\nSaanmo a mabalin a serrekan.",
-       "revdelete-modify-missing": "Biddut ti panagpabaro daytoy ID $1: Saan a nasarakan idiay database!",
-       "revdelete-no-change": "'''Ballaag:''' Daytoy a banag a napetsado ti  $2, $1 ket addaan ti kiniddaw kadagiti panagkita a kasasaad.",
-       "revdelete-concurrent-change": "Biddut ti panagpabaro daytoy a banag a napetsado ti  $2, $1: Ti panakaikabilna ket mabalin a nasuktanen ti sabsabli idi pinada mo a pinabaro.\nPangngaasi a kitaen dagiti listaan.",
-       "revdelete-only-restricted": "Biddut ti panagilemmeng daytoy banag a napetsado ti $2, $1: Saanmo a maidepdep dagita iti panagkita dagiti adminitrador no saanmo a pilian ti maysa kadagiti pinagpili ti panagkita.",
-       "revdelete-reason-dropdown": "*Dagiti kadawyan a rason ti panagikkat\n** Panaglabsing ti karbengan ti kopia\n** Di maiparbeng a komentario wenno kabukbukodan a pakaammo\n** Di maiparbeng a nagan ti agar-aramat\n** Adda pannakabalinna a pammadpadakes a pakaammo",
+       "revdelete-hide-current": "Biddut ti pannakailemmeng ti banag a napetsado ti $2, $1: Daytoy ti kinaudi a rebision.\nSaan a mabalin a mailemmeng.",
+       "revdelete-show-no-access": "Biddut ti panangipakita ti banag a petsado ti $2, $1: Daytoy ket namarkaan a \"nagawidan\".\nSaanmo a mabalin a serrekan.",
+       "revdelete-modify-no-access": "Biddut ti panagpabaro ti banag a petsado ti $2, $1: Daytoy ket namarkaan a \"nagawidan\".\nSaanmo a mabalin a serrekan.",
+       "revdelete-modify-missing": "Biddut ti panagpabaro daytoy ID $1: Awan daytoy manipud ti database!",
+       "revdelete-no-change": "<strong>Ballaag:</strong> Daytoy a banag a napetsado ti $2, $1 ken addaan ti kiniddaw a panagkita ti pannakaisaad.",
+       "revdelete-concurrent-change": "Biddut ti panagpabaro daytoy a banag a napetsado ti  $2, $1: Ti kasasaadna ket mabalin a nasukatanen ti sabali idi pinadasmo a pinabaro.\nPangngaasi a kitaen dagiti listaan.",
+       "revdelete-only-restricted": "Biddut ti panagilemmeng daytoy banag a napetsado ti $2, $1: Saanmo a maidepdep dagita iti panagkita dagiti adminitrador no saanmo a pilien ti maysa kadagiti pagpilian ti panagkita.",
+       "revdelete-reason-dropdown": "*Dagiti kadawyan a rason ti panagikkat\n** Panaglabsing ti karbengan ti kopia\n** Di maiparbeng a komentario wenno kabukbukodan a pakaammo\n** Di maiparbeng a nagan ti agar-aramat\n** Mabalin a pammadpadakes a pakaammo",
        "revdelete-otherreason": "Sabali/maipatinayon a rason:",
        "revdelete-reasonotherlist": "Sabali a rason",
        "revdelete-edit-reasonlist": "Urnosen dagiti rason ti panagikkat",
-       "revdelete-offender": "Nangsukat a mannurat:",
+       "revdelete-offender": "Mannurat ti rebision:",
        "suppressionlog": "Listaan ti nadepdepan",
-       "suppressionlogtext": "Dita baba ket addaan dagiti listaan ti pinagikkat ken panagserra a nairaman dagiti linaon a nailemmeng manipud kadagiti administrador.\nKitaen ti [[Special:BlockList|Listaan ti lapden nga IP]] para iti listaan kadagiti agdama nga operasional a panagparit ken panagserra.",
-       "mergehistory": "Pagtiponen dagiti pakasaritaan ti pampanid",
-       "mergehistory-header": "Daytoy a panid ket mabalinmo ti agitipon kadagiti pinagbaliwan ti pakasaritaan iti maysa a taudan idiay barbaro a panid.\nMasapul a sigaraduem a daytoy a panagsukat ket agsustento ti panakaituloy ti pakasaritaan ti panid.",
-       "mergehistory-box": "Pagtiponen dagiti nasukatan iti dua a pampanid:",
+       "suppressionlogtext": "Dita baba ket listaan dagiti panagikkat ken panagserra a nairaman kadagiti linaon a nailemmeng manipud kadagiti administrador.\nKitaen ti [[Special:BlockList|listaan ti serra]] para iti listaan kadagiti agdama nga operasional a panagiparit ken dagiti panagserra.",
+       "mergehistory": "Pagtiponen dagiti pakasaritaan ti panid",
+       "mergehistory-header": "Daytoy a panid ket mangpakabael kenka nga agitipon kadagiti rebision ti pakasaritaan iti maysa a taudan iti barbaro a panid.\nMasapul a siguraduen no daytoy a panagsukat ket agsustento ti pannakaituloy ti pakasaritaan ti panid.",
+       "mergehistory-box": "Pagtiponen dagiti rebision iti dua a pampanid:",
        "mergehistory-from": "Taudan ti panid:",
        "mergehistory-into": "Pangipanan a panid:",
        "mergehistory-list": "Mabalin nga itipon a pakasaritaan ti inurnos",
-       "mergehistory-merge": "Dagiti sumaganad a panagbaliw iti [[:$1]] ket mabalin nga itipon iti [[:$2]].\nUsaren ti radio a buton a tukol ti pinagtipon iti laeng panagbaliw a naaramid idiay ken sakbay ti nainagan nga oras.",
+       "mergehistory-merge": "Dagiti sumaganad a rebision iti [[:$1]] ket mabalin nga itipon iti [[:$2]].\nUsaren ti radio a buton a tukol ti panagtipon iti laeng panagbaliw a napartuat iti ken sakbay ti nainagan nga oras.\nLaglagipen a ti panag-usar kadagiti silpo ti pagdaliasatan ket mangisaad manen iti daytoy a batong.",
        "mergehistory-go": "Ipakita dagiti mabalin a maitipon a panag-urnos",
-       "mergehistory-submit": "Pagtitiponen dagiti binalbaliwan",
-       "mergehistory-empty": "Awan dagiti mabalin nga itipon ti panagbalbaliw.",
-       "mergehistory-success": "$3 {{PLURAL:$3|a binaliwan|dagiti binaliwan}} ti [[:$1]] balligi ti panagitipon idiay [[:$2]].",
-       "mergehistory-fail": "Saan a nakaaramid ti panagtipon ti pakasaritaan, pangngaasi ta kitaen ti panid ken parametro ti oras.",
-       "mergehistory-no-source": "Awan ti taudan ti panid a $1.",
-       "mergehistory-no-destination": "Awan ti papanan ti panid a $1.",
+       "mergehistory-submit": "Pagtitiponen dagiti rebision",
+       "mergehistory-empty": "Awan dagiti rebision ti mabalin nga itipon.",
+       "mergehistory-success": "$3 {{PLURAL:$3|a rebision|dagiti rebision}} iti [[:$1]] ket nagballigi a naitipon iti [[:$2]].",
+       "mergehistory-fail": "Saan a nakaaramid ti panagtipon ti pakasaritaan, pangngaasi a kitaen ti panid ken dagiti parametro ti oras.",
+       "mergehistory-fail-toobig": "Di naaramid ti panagtipon ti pakasaritaan gapu ta ad-adu ti patingga ti $1 {{PLURAL:$1|a rebision|kadagiti rebision}} ti maiyalisto.",
+       "mergehistory-no-source": "Awan ti taudan ti panid ti $1.",
+       "mergehistory-no-destination": "Awan ti papanan ti panid ti $1.",
        "mergehistory-invalid-source": "Masapul nga adda ti umisu a titulo ti taudan ti panid.",
-       "mergehistory-invalid-destination": "Ti pangipanan ti panid ket masapul nga umisu a titulo.",
+       "mergehistory-invalid-destination": "Ti pangipanan a panid ket masapul nga umisu a titulo.",
        "mergehistory-autocomment": "Naitipon ti [[:$1]] iti [[:$2]]",
        "mergehistory-comment": "Naitipon ti [[:$1]] iti [[:$2]]: $3",
        "mergehistory-same-destination": "Ti nagtaudan ken ti pangipanan ti panid ket saan a mabalin nga agpada",
        "mergehistory-reason": "Rason:",
        "mergelog": "Listaan ti panagtipon",
-       "pagemerge-logentry": "itipon ti [[$1]] iti [[$2]] (dagiti binaliwan aginggana iti $3)",
+       "pagemerge-logentry": "itipon ti [[$1]] iti [[$2]] (dagiti rebision aginggana iti $3)",
        "revertmerge": "Pagsinaen",
-       "mergelogpagetext": "Adda dita baba ti listaan dagiti kinaudian a panagtipon ti maysa a panid ti pakasaritaan iti maysa a sabali.",
-       "history-title": "Panagbalbaliw a pakasaritaan iti \"$1\"",
-       "difference-title": "Paggiddiatan a nagbaetan dagiti panagbalbaliw iti \"$1\"",
+       "mergelogpagetext": "Dita baba ket ti listaan dagiti kaudian a panagtipon ti maysa a pakasaritaan ti panid iti sabali.",
+       "history-title": "Pakasaritaan a rebision iti \"$1\"",
+       "difference-title": "Paggiddiatan a nagbaetan dagiti rebision iti \"$1\"",
        "difference-title-multipage": "Paggiddiatan a nagbaetan dagiti panid  \"$1\" ken \"$2\"",
        "difference-multipage": "(Paggiddiatan dagiti panid)",
        "lineno": "Linia $1:",
-       "compareselectedversions": "Ipada dagiti pinili a binaliwan",
-       "showhideselectedversions": "Ipakita/ilemmeng dagiti napili a nabaliwan",
+       "compareselectedversions": "Ipada dagiti pinili a rebision",
+       "showhideselectedversions": "Ipakita/ilemmeng dagiti napili a rebision",
        "editundo": "ibabawi",
-       "diff-empty": "(Awan ti paggiddiatan)",
-       "diff-multi-sameuser": "({{PLURAL:$1|Maysa nga agtengnga a panagbaliw|Dagiti $1 nga agtengnga a panagbaliw}} babaen ti isu met laeng nga agar-aramat a saan a naipakita)",
-       "diff-multi-otherusers": "({{PLURAL:$1|Maysa nga agtengnga a panagbaliw|Dagiti $1 nga agtengnga a panagbaliw}} babaen {{PLURAL:$2|ti maysa a sabali nga agar-aramat|dagiti $2 nga agar-aramat}} a saan a naipakita)",
-       "diff-multi-manyusers": "({{PLURAL:$1|Maysa nga agtengnga a panangbalbaliw|Dagiti $1 nga agtengnga a panangbalbaliw}} babaen ti ad-adu ngem $2 {{PLURAL:$2|nga agar-aramat|kadagiti agar-aramat}} ti saan a naipakita)",
-       "difference-missing-revision": "{{PLURAL:$2|Maysa a panagbalbaliw|$2 kadagiti panagbalbaliw}} iti daytoy a paggiddiatan ($1) {{PLURAL:$2|ket ti|ket dagiti}} saan a naburikan.\n\nDaytoy ket kadawyan a gapuanan babaen ti sumaganad a nabaak a panilpo tipaggiddiatan ti maysa a panid a naikkaten.\nDagiti salaysay ket mabalin a mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
+       "diff-empty": "(Awan paggiddiatan)",
+       "diff-multi-sameuser": "({{PLURAL:$1|Maysa nga agtengnga a rebision|Dagiti $1 nga agtengnga a rebision}} babaen ti isu met laeng nga agar-aramat a saan a naipakita)",
+       "diff-multi-otherusers": "({{PLURAL:$1|Maysa nga agtengnga a rebision|Dagiti $1 nga agtengnga a rebision}} babaen {{PLURAL:$2|ti maysa a sabali nga agar-aramat|dagiti $2 nga agar-aramat}} a saan a naipakita)",
+       "diff-multi-manyusers": "({{PLURAL:$1|Maysa nga agtengnga a rebision|Dagiti $1 nga agtengnga a rebision}} babaen ti ad-adu ngem $2 {{PLURAL:$2|nga agar-aramat|kadagiti agar-aramat}} ti saan a naipakita)",
+       "difference-missing-revision": "{{PLURAL:$2|Maysa a rebision|$2 kadagiti rebision}} iti daytoy a paggiddiatan ($1) {{PLURAL:$2|ket ti|ket dagiti}} saan a naburikan.\n\nDaytoy ket kadawyan a gapuanan babaen ti sumaganad a nabaak a silpo ti paggiddiatan ti maysa a panid a naikkaten.\nDagiti salaysay ket mabalin a mabirukan idiay [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} listaan ti panagikkat].",
        "searchresults": "Dagiti nagbanagan ti panagbiruk",
        "searchresults-title": "Dagiti nabirukan a nagbanagan para iti \"$1\"",
        "titlematches": "Dagiti kapadpada a titulo ti panid",
        "nextn-title": "Sumaruno a $1 {{PLURAL:$1|a nagbanagan|kadagiti nagbanagan}}",
        "shown-title": "Ipakita ti $1 {{PLURAL:$1|a nagbanagan|kadagiti nagbanagan}}  ti tunggal maysa a panid",
        "viewprevnext": "Kitaen ($1 {{int:pipe-separator}} $2) ($3)",
-       "searchmenu-exists": "'''Adda panid a nanaganan ti \"[[:$1]]\" iti daytoy a wiki.'''",
+       "searchmenu-exists": "<strong>Adda panid a nanaganan ti \"[[:$1]]\" iti daytoy a wiki.</strong> {{PLURAL:$2|0=|Kitaen pay ti sabali a nabirukan a nagbanagan ti panagbiruk.}}",
        "searchmenu-new": "<strong>Partuaten ti panid ti \"[[:$1]]\" iti daytoy a wiki!</strong> {{PLURAL:$2|0=|Kitaen pay ti panid a nabirukan ti panagbirukmo.|Kitaen pay dagiti resulta a nabirukan ti panagbiruk.}}",
        "searchprofile-articles": "Dagiti naglaon a panid",
-       "searchprofile-images": "Sabsabali a midia",
+       "searchprofile-images": "Multimidia",
        "searchprofile-everything": "Amin amin",
        "searchprofile-advanced": "Napasayaat",
        "searchprofile-articles-tooltip": "Agbirukka idiay $1",
        "searchprofile-images-tooltip": "Agbirukka para iti papeles",
-       "searchprofile-everything-tooltip": "Birukem amin a linaon (uray dagiti makipatangan a panid)",
-       "searchprofile-advanced-tooltip": "Agbirukka kadagiti naiduma a \"nagan ti espasio\"",
+       "searchprofile-everything-tooltip": "Birukem amin a linaon (uray dagiti tungtungan a panid)",
+       "searchprofile-advanced-tooltip": "Agbirukka kadagiti naiduma a nagan ti espasio",
        "search-result-size": "$1 ({{PLURAL:$2|iti 1 a balikas|kadagiti $2 a balikas}})",
-       "search-result-category-size": "{{PLURAL:$1|1 a kameng| dagiti $1 a kameng}} ({{PLURAL:$2|1 a subkategoria|dagiti $2  a sukategoria}}, {{PLURAL:$3|1 a papeles|dagiti $3 a papeles}})",
+       "search-result-category-size": "{{PLURAL:$1|1 a kameng| dagiti $1 a kameng}} ({{PLURAL:$2|1 a subkategoria|dagiti $2  a subkategoria}}, {{PLURAL:$3|1 a papeles|dagiti $3 a papeles}})",
        "search-result-score": "Kaitutopan: $1%",
-       "search-redirect": "(ibaw-ing ti $1)",
+       "search-redirect": "(baw-ing ti $1)",
        "search-section": "(paset $1)",
        "search-file-match": "(maipada ti linaon a papeles)",
        "search-suggest": "Daytoy kadi: $1",
        "search-relatedarticle": "Mainaig",
        "searchrelated": "mainaig",
        "searchall": "amin",
-       "showingresults": "Maiparang dita baba agingga {{PLURAL:$1|iti '''1''' a nagbanagan|dagiti '''$1''' a nagbanagan}} a mangrugi iti #'''$2'''.",
+       "showingresults": "Maiparang dita baba agingga {{PLURAL:$1|iti <strong>1</strong> a nagbanagan|dagiti <strong>$1</strong> a nagbanagan}} a mangrugi ti #<strong>$2</strong>.",
        "showingresultsinrange": "Mangipakpakita aginggana {{PLURAL:$1|iti <strong>1</strong> a resulta|dagiti <strong>$1</strong> a resulta}} iti sakop ti #<strong>$2</strong> aginggana ti #<strong>$3</strong>.",
-       "showingresultsheader": "{{PLURAL:$5|Nagbanagan a '''$1''' iti '''$3'''|Dagiti Nagbanagan a '''$1 - $2''' iti '''$3'''}} para iti '''$4'''",
-       "search-nonefound": "Awan ti nagbanagan a kapadpada ti sinapul.",
+       "showingresultsheader": "{{PLURAL:$5|Nagbanagan a <strong>$1</strong> iti <strong>$3</strong>|Dagiti Nagbanagan a <strong>$1 - $2</strong> iti <strong>$3</strong>}} para iti <strong>$4</strong>",
+       "search-nonefound": "Awan dagiti nagbanagan a maipada ti usisa.",
        "powersearch-legend": "Napasayat a panagbiruk",
        "powersearch-ns": "Agbirukka kadagiti nagan ti espasio:",
        "powersearch-togglelabel": "Markaan:",
        "powersearch-remember": "Lagipen ti napili para kadagiti masakbayan a panagbiruk",
        "search-external": "Akinruar a panagbiruk",
        "searchdisabled": "Ti panagbiruk iti {{SITENAME}} ket nabaldado.\nMabalinmo ti agbiruk idiay Google tattan.\nLaglagipem laeng a dagiti pagsurotan nagyan ti {{SITENAME}} ket baka baak.",
-       "search-error": "Adda maysa a biddut  napasamak bayat nga agbirbiruk:$1",
+       "search-error": "Adda maysa a biddut a napasamak bayat nga agbirbiruk:$1",
        "preferences": "Kakaykayatan",
        "mypreferences": "Kakaykayatan",
        "prefs-edits": "Bilang dagiti inurnos:",
        "prefs-labs": "Dagiti subokan a langa",
        "prefs-user-pages": "Dagiti panid ti agar-aramat",
        "prefs-personal": "Bariweswes ti agar-aramat",
-       "prefs-rc": "Kinaudi a binalbaliwan",
+       "prefs-rc": "Kaudian a balbaliw",
        "prefs-watchlist": "Listaan ti bambantayan",
-       "prefs-watchlist-days": "Al-aldaw nga iparang idiay listaan ti bambantayan:",
+       "prefs-watchlist-days": "Al-aldaw nga iparang iti listaan ti bambantayan:",
        "prefs-watchlist-days-max": "Kapaut nga $1 {{PLURAL:$1|nga aldaw|nga al-aldaw}}",
-       "prefs-watchlist-edits": "Kaadu a bilang ti ipakita kadagiti sinukatan iti napadakkel a bambantayan:",
+       "prefs-watchlist-edits": "Kaadu a bilang ti ipakita kadagiti sinukatan iti napadakkel a listaan ti bambantayan:",
        "prefs-watchlist-edits-max": "Kaadu a bilang: 1000",
-       "prefs-watchlist-token": "Tandaan ti bambantayan:",
+       "prefs-watchlist-token": "Tandaan ti listaan ti bambantayan:",
        "prefs-misc": "Sabsabali",
        "prefs-resetpass": "Sukatan ti kontrasenias",
        "prefs-changeemail": "Sukatan ti esurat a pagtaengan",
-       "prefs-setemail": "Ikabil ti esurat a pagtaengan",
-       "prefs-email": "Pagpilian ti esurat",
+       "prefs-setemail": "Isaad ti esurat a pagtaengan",
+       "prefs-email": "Dagiti pagpilian ti esurat",
        "prefs-rendering": "Tabas",
        "saveprefs": "Idulin",
-       "restoreprefs": "Isubli amin dagiti kasisigud a pannakaiyasentar (kadagiti amin a paset)",
+       "restoreprefs": "Isubli amin dagiti kasisigud a pannakaisaad (kadagiti amin a paset)",
        "prefs-editing": "Ur-urnosen",
        "rows": "Ar-aray:",
        "columns": "Tuk-tukol:",
        "searchresultshead": "Biruken",
        "stub-threshold": "Pagpatinggaan para iti panagporma ti <a href=\"#\" class=\"stub\">pungol a silpo</a> (dagiti byte):",
        "stub-threshold-disabled": "Nabaldado",
-       "recentchangesdays": "Al-aldaw nga ipakita dagiti kinaudi a binalbaliwan:",
+       "recentchangesdays": "Al-aldaw nga ipakita iti kaudian a balbaliw:",
        "recentchangesdays-max": "Kapaut nga $1 {{PLURAL:$1|nga aldaw|nga al-aldaw}}",
-       "recentchangescount": "Dagiti bilang dagiti naurnos a kinasigud a maiparang:",
-       "prefs-help-recentchangescount": "Nairaman dagiti kinaudian a baliwan, dagiti pakasaritaan ti panid, ken dagiti listaan.",
-       "prefs-help-watchlist-token2": "Daytoy ti sekreto a tulbek iti pakan ti web iti listaan ti banbantayam.\nTi sinoman a makaammo daytoy ket mabalinda a basaen ti listaan ti banbantayam, isunga saanmo nga ipabingay.\n[[Special:ResetTokens|Pindutem ditoy no kayatmo nga iyasentar manen]].",
+       "recentchangescount": "Bilang dagiti inurnos nga ipakita babaen ti kinasigud:",
+       "prefs-help-recentchangescount": "Daytoy ket mangiraman iti kaudian a balbaliw, dagiti pakasaritaan ti panid, ken dagiti listaan.",
+       "prefs-help-watchlist-token2": "Daytoy ti sekreto a tulbek iti pakan ti web iti listaan ti bambantayam.\nTi sinoman a makaammo daytoy ket mabalinda a basaen ti listaan ti bambantayam, isu a saanmo nga ipabingay.\nNo masapulmo, [[Special:ResetTokens|mabalinmo nga isaad manen]].",
        "savedprefs": "Naidulinen dagiti kakaykayatam.",
        "timezonelegend": "Sona ti oras:",
        "localtime": "Lokal nga oras:",
-       "timezoneuseserverdefault": "Usaren ti wiki a kasisigud ($1)",
-       "timezoneuseoffset": "Sabsabali (inaganan ti tangdan)",
+       "timezoneuseserverdefault": "Usaren ti kasisigud ti wiki ($1)",
+       "timezoneuseoffset": "Sabali (inaganan ti timbengan)",
        "servertime": "Oras ti server:",
-       "guesstimezone": "Agikabil manipud idiay pabasabasam",
+       "guesstimezone": "Punuen manipud ti pagbasabasa",
        "timezoneregion-africa": "Aprika",
        "timezoneregion-america": "Amerika",
        "timezoneregion-antarctica": "Antartika",
        "timezoneregion-europe": "Europa",
        "timezoneregion-indian": "Taaw Indiano",
        "timezoneregion-pacific": "Taaw Pasipiko",
-       "allowemail": "Pakabaelam ti esurat a naggapu kadagiti sabali nga agar-aramat",
+       "allowemail": "Pakabaelam ti esurat a naggapo kadagiti sabali nga agar-aramat",
        "prefs-searchoptions": "Biruken",
        "prefs-namespaces": "Dagiti nagan ti espasio",
        "default": "kasisigud",
        "prefs-custom-css": "Naiduma a CSS",
        "prefs-custom-js": "Naiduma a JavaScript",
        "prefs-common-css-js": "Bingay a CSS/JavaScript dagiti amin a kudil:",
-       "prefs-reset-intro": "Mabalinmo nga usaren daytoy a panid tapno maisublim dagita kakaykayatam iti kasisigud ti daytoy a wiki.\nNgem saanto a mabalinen nga ipasubli.",
+       "prefs-reset-intro": "Mabalinmo nga usaren daytoy a panid tapno maisublim dagita kakaykayatam iti kasisigud iti daytoy a wiki.\nNgem saanto a mabalinen nga ipasubli.",
        "prefs-emailconfirm-label": "Pammasingked ti esurat:",
        "youremail": "Esurat:",
        "username": "{{GENDER:$1|Nagan ti agar-aramat}}:",
        "yourrealname": "Pudno a nagan:",
        "yourlanguage": "Pagsasao:",
        "yourvariant": "Linaon ti sabali a pagsasao:",
-       "prefs-help-variant": "Ti kinaykayatmo a kita ti pagsasao wenno sabali a panagsurat a maipakita kadagiti linaon ti panid daytoy a wiki.",
+       "prefs-help-variant": "Ti kinaykayatmo a kita ti pagsasao wenno sabali a panagsurat a maipakita kadagiti linaon ti panid iti daytoy a wiki.",
        "yournick": "Baro a pirma:",
-       "prefs-help-signature": "Dagiti komentario kadagiti tungtungan a panid ket mapirmaan koma iti \"<nowiki>~~~~</nowiki>\" nga agpabalin ti pirmam ken ti petsa.",
-       "badsig": "Saan a pudno a kilaw a pirma.\nIkur-it dagiti HTML nga etiketa.",
-       "badsiglength": "Atiddog unay ti pirmam.\nMasapul a nababbaba ngem $1 {{PLURAL:$1| a karakter|kadagiti karakter}} ti kaatiddogna.",
+       "prefs-help-signature": "Dagiti komentario kadagiti tungtungan a panid ket mapirmaan koma iti \"<nowiki>~~~~</nowiki>\" a pabaliwento iti pirmam ken ti petsa.",
+       "badsig": "Imbalido a naata a pirma.\nKitaen dagiti etiketa ti HTML.",
+       "badsiglength": "Atiddog unay ti pirmam.\nMasapul a saan nga ad-adu ngem $1 {{PLURAL:$1| a karakter|a karkarakter}} ti kaatiddogna.",
        "yourgender": "Kasano kadi ti kayatmo a pannakaibaga?",
        "gender-unknown": "Kaykayatko a saan nga ibaga",
        "gender-male": "Isuna ket lalaki nga agur-urnos ti pampanid ti wiki",
        "gender-female": "Isuna ket babai nga agur-urnos ti pampanid ti wiki",
-       "prefs-help-gender": "Ti panangiyasentar daytoy a kakaykayatan ket saan a nasken.\nTi sopwer ket agus-usar ti pategna daytoy ti panagtawagna kenka ken ti panangibaga ti dadduma ti maitunos gramatika a panangibaga kenka.\nDaytoy a pakaammo ket makita ti publiko.",
+       "prefs-help-gender": "Ti panangisaad daytoy a kakaykayatan ket saan a nasken.\nTi sopwer ket agus-usar iti pategna tapno tawagannaka ken ibaganaka kadagiti sabali nga agus-usar iti maitunos gramatika ti henero.\nDaytoy a pakaammo ket makitanto iti publiko.",
        "email": "Esurat",
-       "prefs-help-realname": "Saan a nasken ti pudno a nagan.\nNgem no kayatmo nga ited, maaramat daytoy a kas pammadayaw ken pangpatalged iti obram.",
-       "prefs-help-email": "Ti esurat a pagtaengan ket saan a masapul, ngem masapul no agsukatka ti kontrasenias, no baka malipatam ti kontraseniasmo.",
-       "prefs-help-email-others": "Mabalinmo nga agpili tapno dagiti sabsabali nga agar-aramat ket ma esuratandaka idiay panagsilpo ti panidmo wenno ti panid ti tungtungam.\nTi esurat a pagtaengam ket saan a maipakita kadagiti agar-aramat nga agkontak kenka.",
-       "prefs-help-email-required": "Masapul ti e-surat a pagtaengan.",
+       "prefs-help-realname": "Saan a nasken ti pudno a nagan.\nNgem no kayatmo nga ited, maaramatto daytoy a kas pammadayaw ken pangpatalged para iti obram.",
+       "prefs-help-email": "Ti esurat a pagtaengan ket saan a masapul, ngem masapul kadagiti panangisaad manen ti kontrasenias, no malipatam ti kontraseniasmo.",
+       "prefs-help-email-others": "Mabalinmo pay ti agpili tapno dagiti sabali nga agar-aramat ket mabalin nga esuratandaka babaen ti silpo ti panidmo wenno ti panid ti tungtungam.\nTi esurat a pagtaengam ket saan a maipakita no agkontak kenka dagiti agar-aramat.",
+       "prefs-help-email-required": "Masapul ti esurat a pagtaengan.",
        "prefs-info": "Kangrunaan a pakaammo",
        "prefs-i18n": "Internasionalisasion",
        "prefs-signature": "Pirma",
-       "prefs-dateformat": "Kita ti petsa",
-       "prefs-timeoffset": "Tangda ti oras",
+       "prefs-dateformat": "Pormat ti petsa",
+       "prefs-timeoffset": "Timbengan ti oras",
        "prefs-advancedediting": "Dagiti sapasap a pagpilian",
        "prefs-editor": "Mannurat",
        "prefs-preview": "Ipadas",
        "prefs-displayrc": "Ipakita dagiti pagpilian",
        "prefs-displaywatchlist": "Ipakita dagiti pagpilian",
        "prefs-tokenwatchlist": "Tandaan",
-       "prefs-diffs": "Sabali",
+       "prefs-diffs": "Paggigiddiatan",
        "prefs-help-prefershttps": "Daytoy a kakaykayatan ket mapakabaelanto iti sumaruno nga iseserrekmo.",
        "prefs-tabs-navigation-hint": "Pakaammo: Mabalinmo nga usaren dagiti kanigid ken kanawan a tekla ti pana tapno madaliasat ti baetan dagiti etiketa iti listaan dagiti etiketa.",
        "email-address-validity-valid": "Ti esurat a pagtaengan ket kasla umiso",
        "email-address-validity-invalid": "Ikabil ti umiso nga esurat a pagtaengan",
        "userrights": "Panagtaripato kadagiti karbengan ti agar-aramat",
        "userrights-lookup-user": "Agtaripato kadagiti grupo ti agar-aramat",
-       "userrights-user-editname": "Mangiserrek iti nagan-agar-aramat:",
+       "userrights-user-editname": "Mangiserrek iti nagan ti agar-aramat:",
        "editusergroup": "Urnosen dagiti grupo ti agar-aramat",
-       "editinguser": "Suksukatan ti karbengan ti agar-aramat ni '''[[User:$1|$1]]''' $2",
+       "editinguser": "Suksukatan ti karbengan ti agar-aramat ni '''[[User:$1|$1]]''' $2",
        "userrights-editusergroup": "Urnosen dagiti grupo ti agar-aramat",
        "saveusergroups": "Idulin dagiti grupo ti agar-aramat",
        "userrights-groupsmember": "Kameng iti:",
        "userrights-groupsmember-auto": "Napudno a kameng iti:",
-       "userrights-groups-help": "Mabaliwam dagiti ayan a grupo ti agar-aramat:\n* Ti nakur-it a kahon ket kayatna a saoen nga adda ti agar-aramat dita a grupo.\n* Ti saan a nakur-it a kahon ket kayatna a saoen nga awan ti agar-aramat dita a grupo.\n* A * ti kunana ket saanmo a maikkat ti grupo no nainayonmon, wenno pagbalittaden.",
+       "userrights-groups-help": "Mabaliwam dagiti ayan a grupo ti agar-aramat:\n* Ti nakur-it a kahon ket kayatna a saoen nga adda ti agar-aramat dita a grupo.\n* Ti saan a nakur-it a kahon ket kayatna a saoen nga awan ti agar-aramat dita a grupo.\n* A * mangipakita a saanmo a maikkat ti grupo no nainayonmon, wenno pagbalittaden.",
        "userrights-reason": "Rason:",
        "userrights-no-interwiki": "Awan ti pammalubosmo nga agurnos ti karbengan ti agar-aramat kadagiti sabali a wiki.",
        "userrights-nodatabase": "Awan ti database a $1 wenno saan a lokal.",
-       "userrights-nologin": "Masapul a [[Special:UserLogin|sumrekka]] nga adda pakabilangan nga administrador ti magted kadagiti karbengan ti agar-aramat.",
+       "userrights-nologin": "Masapul a [[Special:UserLogin|sumrekka]] nga addaan iti pakabilangan ti administrador tapno makaited kadagiti karbengan ti agar-aramat.",
        "userrights-notallowed": "Awan ti pammalubos nga agnayon wenno agikkat kadagiti karbengan ti agar-aramat.",
        "userrights-changeable-col": "Dagiti grupo a mabalinmo a baliwan",
        "userrights-unchangeable-col": "Dagiti grupo a dimo mabalin a baliwan",
        "userrights-conflict": "Suppiat dagiti panagbaliw kadagiti karbengan ti agar-aramat! Pangngaasi nga irepasom ken pasingkedam dagiti sinuksukatam.",
-       "userrights-removed-self": "Nagballigika a nagikkat kadagiti karbengam. Isu a kastoyen ket saanmo a mabalin a pastrekan daytoy a panid.",
+       "userrights-removed-self": "Nagballigika a nagikkat kadagiti bukodmo a karbengan. Iti kastoyen, saankan a mabalin a mangserrek iti daytoy a panid.",
        "group": "Grupo:",
        "group-user": "Dagiti agar-aramat",
        "group-autoconfirmed": "Dagiti automatiko a napasingkedan nga agar-aramat",
        "grouppage-suppress": "{{ns:project}}:Pagpansin",
        "right-read": "Basaen dagiti panid",
        "right-edit": "Agurnos kadagiti panid",
-       "right-createpage": "Agaramid kadagiti panid (saan a pagtutungtongan a pampanid)",
-       "right-createtalk": "Agaramid ti pagtungtungan a pampanid",
-       "right-createaccount": "Agaramid kadagiti baro a pakabilangan ti agar-aramat",
-       "right-minoredit": "Markaan a bassit dagiti inurnos",
-       "right-move": "Iyalis dagiti panid",
-       "right-move-subpages": "Iyalis dagiti panid a kakuyog dagiti subpanidda.",
-       "right-move-rootuserpages": "Iyalis dagiti ramut a panid ti agar-aramat",
-       "right-move-categorypages": "Iyalis ti pampanid ti kategoria",
-       "right-movefile": "Iyalis dagiti papeles",
-       "right-suppressredirect": "Saan nga agaramid ti baw-ing a naggapo iti taudan no iyalis dagiti panid",
-       "right-upload": "Agipan ti papeles",
-       "right-reupload": "Suratam manen dagiti adda a papeles",
-       "right-reupload-own": "Pasuratam manen dagiti addaan ti pinag-ipanmo a papeles",
-       "right-reupload-shared": "Paawanen dagiti papeles idiay pagbingayan ti nakaikabilan ti midia a lokal",
-       "right-upload_by_url": "Pag-ipan ti papeles a naggapu ti URL",
-       "right-purge": "Purgaen ti pagidulinan ti pagsaadan a ti panid nga awan ti panagpasingked",
-       "right-autoconfirmed": "Saanto a mabanagan babaen dagiti patingga ti gatad a naibatay ti IP",
-       "right-bot": "Matrato a kas automatiko a pamay-an",
+       "right-createpage": "Agpartuat kadagiti panid (saan a pagtutungtongan a pampanid)",
+       "right-createtalk": "Agpartuat ti pagtungtungan a pampanid",
+       "right-createaccount": "Agpartuat kadagiti baro a pakabilangan ti agar-aramat",
+       "right-minoredit": "Markaan dagiti inurnos a kas bassit",
+       "right-move": "Agiyalis kadagiti panid",
+       "right-move-subpages": "Agiyalis kadagiti panid a kakuyog dagiti subpanidda",
+       "right-move-rootuserpages": "Agiyalis kadagiti ramut a panid ti agar-aramat",
+       "right-move-categorypages": "Agiyalis ti pampanid ti kategoria",
+       "right-movefile": "Agiyalis kadagiti papeles",
+       "right-suppressredirect": "Saan nga agpartuat kadagiti baw-ing manipud ti taudan ti pampanid no agiyalis kadagiti panid",
+       "right-upload": "Agikarga kadagiti papeles",
+       "right-reupload": "Agisurat manen kadagiti addan a papeles",
+       "right-reupload-own": "Agisurat manen kadagiti addan a papeles a bukod nga inkarga",
+       "right-reupload-shared": "Lokal a mangtuon kadagiti papeles idiay pagbingayan a repsitorio ti midia",
+       "right-upload_by_url": "Agikarga kadagiti papeles manipud ti URL",
+       "right-purge": "Agpurga ti cache ti sitio para iti panid nga awan ti pammasingked",
+       "right-autoconfirmed": "Saan a mabanagan babaen dagiti patingga ti gatad a naibatay ti IP",
+       "right-bot": "Matrato a kas maysa nga automatiko a proseso",
        "right-nominornewtalk": "Nga awanan ti bassit a panagurnos dagiti tungtungan a panid ti mangkalbit dagiti agpakabil ti baro a mensahe",
-       "right-apihighlimits": "Agusar ti nangatngato a patingga kadagiti panagsapul ti API.",
+       "right-apihighlimits": "Agusar kadagiti nangatngato a patingga kadagiti usisa ti API.",
        "right-writeapi": "Panagusar ti panagsurat nga API",
-       "right-delete": "Ikkaten dagiti panid",
-       "right-bigdelete": "Ikkaten dagiti panid nga adda dagiti dakkel a pakasaritaanna",
-       "right-deletelogentry": "Ikkaten ken isubli ti panagikkat dagiti naisangsangayan a naikabil ti listaan",
-       "right-deleterevision": "Ikkaten ken ipasubli dagiti nainagan a panagbaliw ti panid",
-       "right-deletedhistory": "Kitaen dagiti naikabil a pakasaritaan, nga awan kaniada kadagiti nairaman a testo",
-       "right-deletedtext": "Kitaen dagiti naikkat a testo ken dagiti nasukatan a nagbaetan dagiti binaliwan",
-       "right-browsearchive": "Biruken dagiti naikkat a panid",
-       "right-undelete": "Isubli ti naikkat a panid",
-       "right-suppressrevision": "Kitaen ken ipasubli dagiti binaliwan a nailemmeng manipud kadagiti administrador",
-       "right-suppressionlog": "Kitaen dagita pribado a listaan",
-       "right-block": "Serraan dagiti sabali nga agar-aramat manipud iti panag-urnos",
-       "right-blockemail": "Serraan dagiti agar-aramat nga agpatulod manipud ti esurat",
-       "right-hideuser": "Serraan ti maysa a nagan ti agar-aramat, ilemmeng manipud ti publiko",
-       "right-ipblock-exempt": "Labsan dagiti IP a serra, dagiti automatiko a serra ken dagiti nasakup a serra.",
-       "right-proxyunbannable": "Labsan dagiti automatiko a serra dagiti pannakbagi",
-       "right-unblockself": "Ikkaten ti kabukbukodan a pannaka-serra",
-       "right-protect": "Sukatan dagiti agpang ti salaknib ken urnosen dagiti nasalakniban ti sariap a panid",
-       "right-editprotected": "Urnosen dagiti panid a nasalakniban a kas \"{{int:protect-level-sysop}}\"",
-       "right-editsemiprotected": "Urnosen dagiti panid a nasalakniban a kas \"{{int:protect-level-autoconfirmed}}\"",
-       "right-editinterface": "Urnosen ti \"interface\" ti agar-aramat",
-       "right-editusercssjs": "Urnosen dagiti CSS ken JavaScript a papeles dagiti sabsabali nga agar-aramat",
-       "right-editusercss": "Urnosen dagiti CSS a papeles dagiti sabsabali nga agar-aramat",
-       "right-edituserjs": "Urnosen dagiti JavaScript a papeles dagiti sabsabali nga agar-aramat",
-       "right-editmyusercss": "Urnosem dagiti bukodmo a papeles ti CSS ti agar-aramat",
-       "right-editmyuserjs": "Urnosem dagiti bukodmo a papeles ti JavaScript ti agar-aramat",
-       "right-viewmywatchlist": "Kitaem ti bukodmo a listaan ti banbantayan",
-       "right-editmywatchlist": "Urnosem ti bukodmo a listaan ti agar-aramat. Laglagipen nga adda dagiti tignay a mangnayonto pay laeng ti pampanid urayno awan daytoy a karbengan.",
-       "right-viewmyprivateinfo": "Kitaem ti bukodmo a pribado a datos (kasla ti esurat a pagtaengan, pudno a nagan)",
-       "right-editmyprivateinfo": "Urnosem ti bukodmo a pribado a datos (kasla ti esurat a pagtaengan, pudno a nagan)",
-       "right-editmyoptions": "Urnosem dagiti bukodmo a kakaykayatan",
-       "right-rollback": "Pardasan nga ipasubli dagiti inurnos ti naudi nga agar-aramat a nagurnos ti kakasta a panid",
-       "right-markbotedits": "Markaan dagiti napasubli nga urnos a kas inurnos dagiti bot",
-       "right-noratelimit": "Saan a maaringan kadagiti patingga a pagpataray",
-       "right-import": "Agala ti pampanid manipud kadagiti sabsabali a wiki",
-       "right-importupload": "Agala kadagiti panid a naggapu iti papeles ti pinag-ipan",
-       "right-patrol": "Markaan a kas napatruliaan dagiti inurnos ti dadduma",
-       "right-autopatrol": "Dagiti inurnosmo ket mamarkaan nga automatiko a kas napatruliaan",
-       "right-patrolmarks": "Kitaen dagiti kinaudian a binaliwan a  napatruliaan a marka",
-       "right-unwatchedpages": "Kitaen ti listaan dagiti saan a nabambantayan a panid",
-       "right-mergehistory": "Pagtitiponen ti pakasaritaan dagiti panid",
-       "right-userrights": "Urnosen amin dagiti karbengan ti agar-aramat",
-       "right-userrights-interwiki": "Urnosen dagiti karbengan ti agar-aramat kadagiti agar-aramat iti sabsabali a wiki",
-       "right-siteadmin": "Ikandado ken lukatan ti database",
-       "right-override-export-depth": "Ipan dagiti panid ken iraman dagiti nasilpo a panid iti kauneg nga 5",
-       "right-sendemail": "Agpatulod ti esurat kadagiti sabali nga agar-aramat",
-       "right-passwordreset": "Kitaen dagiti esurat a panangiyasentar manen kadagiti kontrasenias",
-       "newuserlogpage": "Listaan dagiti naaramid nga agar-aramat",
-       "newuserlogpagetext": "Daytoy ket listaan ti pannakaramid dagiti agar-aramat.",
+       "right-delete": "Agikkat kadagiti panid",
+       "right-bigdelete": "Agikkat kadagiti panid nga addaan kadagiti dakkel a pakasaritaan",
+       "right-deletelogentry": "Agikkat ken agisubli iti panagikkat kadagiti naisangsangayan a naikabil ti listaan",
+       "right-deleterevision": "Agikkat ken agisubli kadagiti naisangayan a rebision ti panid",
+       "right-deletedhistory": "Agkita kadagiti naikabil a naikkat a pakasaritaan, nga awan kadagiti mainaig a testo",
+       "right-deletedtext": "Agkita kadagiti naikkat a testo ken dagiti nasukatan a nagbaetan dagiti naikkat a rebision",
+       "right-browsearchive": "Agbiruk kadagiti naikkat a panid",
+       "right-undelete": "Agisubli ti pannakaikkat ti panid",
+       "right-suppressrevision": "Agkita, agilemmeng ken agisubli ti pannakakita dagiti naisangayan a rebision dagiti panid manipud ti sinoman nga agar-aramat",
+       "right-viewsuppressed": "Agkita kadagiti rebision a nailemmeng manipud ti sinoman nga agar-aramat",
+       "right-suppressionlog": "Agkita kadagiti pribado a listaan",
+       "right-block": "Agserra kadagiti sabali nga agar-aramat manipud iti panag-urnos",
+       "right-blockemail": "Agserra iti agar-aramat manipud ti panagipatulod ti esurat",
+       "right-hideuser": "Agserra iti nagan ti agar-aramat, ken agilemmeng manipud ti publiko",
+       "right-ipblock-exempt": "Labsanna dagiti serra ti IP, dagiti automatiko a serra ken dagiti sakop a serra.",
+       "right-proxyunbannable": "Labsanna dagiti automatiko a serra dagiti pannakbagi",
+       "right-unblockself": "Bukod nga agikkat it pannaka-serra",
+       "right-protect": "Agsukat kadagiti agpang ti salaknib ken agurnos kadagiti nasalakniban ti sariap a panid",
+       "right-editprotected": "Agurnos kadagiti panid a nasalakniban a kas \"{{int:protect-level-sysop}}\"",
+       "right-editsemiprotected": "Agurnos kadagiti panid a nasalakniban a kas \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editinterface": "Agurnos iti interface ti agar-aramat",
+       "right-editusercssjs": "Agurnos kadagiti papales ti CSS ken JavaScript dagiti sabali nga agar-aramat",
+       "right-editusercss": "Agurnos kadagiti papeles ti CSS dagiti sabali nga agar-aramat",
+       "right-edituserjs": "Agurnos kadagiti papales ti JavaScript dagiti sabali nga agar-aramat",
+       "right-editmyusercss": "Agurnos kadagiti bukodmo a papeles ti CSS ti agar-aramat",
+       "right-editmyuserjs": "Agurnos kadagiti bukodmo a papeles ti JavaScript ti agar-aramat",
+       "right-viewmywatchlist": "Agkita iti bukodmo a listaan ti bambantayan",
+       "right-editmywatchlist": "Agurnos iti bukodmo a listaan ti bambantayan. Laglagipen nga adda dagiti tignay a mangnayonto pay laeng ti pampanid urayno awan daytoy a karbengan.",
+       "right-viewmyprivateinfo": "Agkita iti bukodmo a pribado a datos (kasla ti esurat a pagtaengan, pudno a nagan)",
+       "right-editmyprivateinfo": "Agurnos iti bukodmo a pribado a datos (kasla ti esurat a pagtaengan, pudno a nagan)",
+       "right-editmyoptions": "Agurnos kadagiti bukodmo a kakaykayatan",
+       "right-rollback": "Napardas a mangisubli kadagiti inurnos ti naudi nga agar-aramat a nagurnos iti naisangayan a panid",
+       "right-markbotedits": "Agmarka kadagiti naipasubli nga urnos a kas inurnos dagiti bot",
+       "right-noratelimit": "Saan a maaringan babaen dagiti patingga ti gatad",
+       "right-import": "Agala ti pampanid manipud kadagiti sabali a wiki",
+       "right-importupload": "Agala kadagiti panid manipud ti naikarga a papeles",
+       "right-patrol": "Markaanna dagiti inurnos ti dadduma a kas napatruliaan",
+       "right-autopatrol": "Automatiko a mamarkaanna ti bukod nga inurnos a kas napatruliaan",
+       "right-patrolmarks": "Agkita kadagiti kaudian a binaliwan dagiti marka ti napatruliaan",
+       "right-unwatchedpages": "Agkita ti listaan dagiti saan a nabambantayan a panid",
+       "right-mergehistory": "Mangitipon ti pakasaritaan dagiti panid",
+       "right-userrights": "Agurnos kadagiti amin a karbengan ti agar-aramat",
+       "right-userrights-interwiki": "Agurnos kadagiti karbengan ti agar-aramat kadagiti agar-aramat iti sabsabali a wiki",
+       "right-siteadmin": "Mangikandado ken manglukat iti database",
+       "right-override-export-depth": "Agipan kadagiti panid a mairaman dagiti naisilpo a panid agingana iti kauneg ti 5",
+       "right-sendemail": "Agipatulod ti esurat kadagiti sabali nga agar-aramat",
+       "right-passwordreset": "Agkita kadagiti esurat ti panangisaad manen ti kontrasenias",
+       "newuserlogpage": "Listaan ti panagpartuat ti agar-aramat",
+       "newuserlogpagetext": "Daytoy ket listaan dagiti pannakapartuat iti agar-aramat.",
        "rightslog": "Listaan dagiti karbengan ti agar-aramat",
        "rightslogtext": "Daytoy ket listaan dagiti sinukatan a karbengan ti agar-aramat.",
-       "action-read": "basaen datoy a panid",
-       "action-edit": "agurnos iti datoy a panid",
+       "action-read": "agbasa iti datoy a panid",
+       "action-edit": "agurnos iti daytoy a panid",
        "action-createpage": "agpartuat kadagiti panid",
-       "action-createtalk": "agaramid kadagiti pagtungtungan a panid",
-       "action-createaccount": "agpartuat ti pakabilangan daytoy nga agar-aramat",
-       "action-history": "kitaen ti pakasaritaan daytoy a panid",
-       "action-minoredit": "markaam a bassit nga urnos daytoy",
-       "action-move": "iyalis daytoy a panid",
-       "action-move-subpages": "iyalis daytoy a panid, ken dagiti subpanidna",
-       "action-move-rootuserpages": "iyalis dagiti ramut a panid ti agar-aramat",
-       "action-move-categorypages": "iyalis ti pampanid ti kategoria",
-       "action-movefile": "iyalis daytoy a papeles",
-       "action-upload": "ikarga daytoy a papeles",
-       "action-reupload": "suratam manen dagiti adda a papeles",
-       "action-reupload-shared": "tuonan daytoy a papeles idiay pagbingayan a repositorio",
-       "action-upload_by_url": "ikarga daytoy a papeles manipud ti URL",
-       "action-writeapi": "usaren ti panagsurat ti API",
-       "action-delete": "ikkaten daytoy a panid",
-       "action-deleterevision": "ikkaten daytoy a binaliwan",
-       "action-deletedhistory": "kitaen dagiti naikkat a pakasaritaan daytoy a panid",
-       "action-browsearchive": "birukem dagiti naikkat a panid",
-       "action-undelete": "isublim ti panakaikkat daytoy a panid",
-       "action-suppressrevision": "kitaen ken ipasubli daytoy nailemmeng a panagbaliw",
-       "action-suppressionlog": "kitaen ti listaan a pribado",
-       "action-block": "serraan daytoy nga agar-aramat manipud ti panag-urnos",
-       "action-protect": "sukatan dagiti lessaad ti salaknib iti daytoy a panid",
-       "action-rollback": "pardasan nga ipasubli dagiti inurnos ti kinaudi nga agar-aramat a nagurnos ti naisangsangayan a panid",
+       "action-createtalk": "agpartuat kadagiti pagtungtungan a panid",
+       "action-createaccount": "agpartuat iti pakabilangan daytoy nga agar-aramat",
+       "action-history": "agkita iti pakasaritaan daytoy a panid",
+       "action-minoredit": "agmarka iti daytoy nga inurnos a kas bassit",
+       "action-move": "agiyalis iti daytoy a panid",
+       "action-move-subpages": "agiyalis iti daytoy a panid, ken dagiti subpanidna",
+       "action-move-rootuserpages": "agiyalis kadagiti ramut a panid ti agar-aramat",
+       "action-move-categorypages": "agiyalis iti pampanid ti kategoria",
+       "action-movefile": "agiyalis iti daytoy a papeles",
+       "action-upload": "agikarga iti daytoy a papeles",
+       "action-reupload": "agsurat manen iti daytoy nga adda a papeles",
+       "action-reupload-shared": "mangtuon iti daytoy a papeles idiay pagbingayan a repositorio",
+       "action-upload_by_url": "agikarga iti daytoy a papeles manipud ti URL",
+       "action-writeapi": "agusar iti panagsurat ti API",
+       "action-delete": "agikkat iti daytoy a panid",
+       "action-deleterevision": "agikkat iti daytoy a rebision",
+       "action-deletedhistory": "agkita kadagiti naikkat a pakasaritaan iti daytoy a panid",
+       "action-browsearchive": "agbiruk kadagiti naikkat a panid",
+       "action-undelete": "agisubli iti pannakaikkat iti daytoy a panid",
+       "action-suppressrevision": "agrepaso ken agisubli iti daytoy a nailemmeng a rebision",
+       "action-suppressionlog": "agkita iti daytoy a pribalo a listaan",
+       "action-block": "agserra iti daytoy nga agar-aramat manipud ti panag-urnos",
+       "action-protect": "mangsukat kadagiti lessaad ti salaknib para iti daytoy a panid",
+       "action-rollback": "napardas a mangisubli kadagiti inurnos ti kinaudi nga agar-aramat a nagurnos iti naisangsangayan a panid",
        "action-import": "agala ti pampanid manipud ti sabali a wiki",
-       "action-importupload": "agala ti pampanid manipud ti naipan a papeles",
-       "action-patrol": "markaan a kas napatruliaan dagiti inurnos ti dadduma",
-       "action-autopatrol": "markaam dagiti napatruliam nga inurnos",
-       "action-unwatchedpages": "kitaen ti listaan dagiti saan a nabambantayan a panid",
-       "action-mergehistory": "pagtitiponen ti pakasaritaan daytoy a panid",
-       "action-userrights": "urnosen amin dagiti karbengan ti agar-aramat",
-       "action-userrights-interwiki": "urnosen dagiti karbengan ti agar-aramat iti agar-aramat kadagiti sabsabali a wiki",
-       "action-siteadmin": "kandaduan wenno lukatan daytoy \"database\"",
+       "action-importupload": "agala ti pampanid manipud ti naikarga a papeles",
+       "action-patrol": "agmarka kadagiti inurnos ti dadduma a kas napatruliaan",
+       "action-autopatrol": "agmarka iti bukodmo nga inurnos a kas napatrulian",
+       "action-unwatchedpages": "agkita ti listaan dagiti saan a nabambantayan a panid",
+       "action-mergehistory": "mangitipon ti pakasaritaan iti daytoy a panid",
+       "action-userrights": "agurnos kadagiti amin a karbengan ti agar-aramat",
+       "action-userrights-interwiki": "agurnos kadagiti karbengan ti agar-aramat dagiti agar-aramat kadagiti sabali a wiki",
+       "action-siteadmin": "mangkandado wenno manglukat ti database",
        "action-sendemail": "agipatulod kadagiti esurat",
-       "action-editmywatchlist": "urnosem ti bukodmo a listaan ti banbantayan",
-       "action-viewmywatchlist": "kitaem ti bukodmo a listaan ti banbantayan",
-       "action-viewmyprivateinfo": "kitaem ti bukodmo a pribado a pakaammo",
-       "action-editmyprivateinfo": "urnosem ti bukodmo a pribado a pakaammo",
+       "action-editmywatchlist": "agurnos iti bukodmo a listaan ti bambantayan",
+       "action-viewmywatchlist": "agkita iti bukodmo a listaan ti bambantayan",
+       "action-viewmyprivateinfo": "agkita iti bukodmo a pribado a pakaammo",
+       "action-editmyprivateinfo": "agurnos iti bukodmo a pribado a pakaammo",
        "nchanges": "$1 {{PLURAL:$1|sinukatan|dagiti sinukatan}}",
-       "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|manipud idi naudi a panagsarungkar}}",
+       "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|manipud ti naudi a panagsarungkar}}",
        "enhancedrc-history": "pakasaritaan",
        "recentchanges": "Kaudian a balbaliw",
-       "recentchanges-legend": "Pagpilian kadagiti kaudian a balbaliw",
-       "recentchanges-summary": "Siputen dagiti kinaudi a panagbalbaliw ti wiki iti daytoy a panid.",
+       "recentchanges-legend": "Pagpilian iti kaudian a balbaliw",
+       "recentchanges-summary": "Siputen ti kaudian a balbaliw iti wiki iti daytoy a panid.",
        "recentchanges-noresult": "Awan ti nasuksukatan iti las-ud ti naited a paset ti panawen a kapada dagitoy a kriteria.",
-       "recentchanges-feed-description": "Siputen dagiti kinaudi a panagbalbaliw ti wiki iti daytoy a pakan.",
-       "recentchanges-label-newpage": "Daytoy a panag-urnos ket nakapartuat ti baro a panid",
+       "recentchanges-feed-description": "Siputen ti kaudian a balbaliw iti wiki iti daytoy a pakan.",
+       "recentchanges-label-newpage": "Daytoy a panag-urnos ket nakapartuat iti baro a panid",
        "recentchanges-label-minor": "Daytoy ket bassit a panag-urnos",
-       "recentchanges-label-bot": "Daytoy a panag-urnos ket inaramid babaen ti maysa a bot",
+       "recentchanges-label-bot": "Daytoy a panag-urnos ket inaramid babaen ti bot",
        "recentchanges-label-unpatrolled": "Daytoy a panag-urnos ket saan pay a napatruliaan",
        "recentchanges-label-plusminus": "Ti panagbaliw ti kadakkel ti panid babaen ti bilang dagiti byte",
        "recentchanges-legend-heading": "'''Leyenda:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (kitaen pay ti [[Special:NewPages|listaan ti baro a pampanid]])",
        "rcnotefrom": "Dita baba ket dagiti sinukatan manipud idi strong>$2</strong> (agingga iti <strong>$1</strong> a naipakita).",
-       "rclistfrom": "Ipakita dagiti kabarbaro a sinukatan a mangrugi manipud idi $3 $2",
+       "rclistfrom": "Ipakita dagiti kabarbaro a sinukatan a mangrugi manipud idi $2, $3",
        "rcshowhideminor": "$1 dagiti bassit a panag-urnos",
        "rcshowhideminor-show": "Ipakita",
        "rcshowhideminor-hide": "Ilemmeng",
        "rcshowhideliu": "$1 dagiti nakarehistro nga agar-aramat",
        "rcshowhideliu-show": "Ipakita",
        "rcshowhideliu-hide": "Ilemmeng",
-       "rcshowhideanons": "$1 dagiti di am-ammo nga agar-aramat",
+       "rcshowhideanons": "$1 dagiti di ammo nga agar-aramat",
        "rcshowhideanons-show": "Ipakita",
        "rcshowhideanons-hide": "Ilemmeng",
        "rcshowhidepatr": "$1 dagiti napatrulian a panag-urnos",
        "rcshowhidemine-show": "Ipakita",
        "rcshowhidemine-hide": "Ilemmeng",
        "rclinks": "Ipakita dagiti naudi a $1 a sinukatan iti kallabes a $2 nga al-aldaw<br />$3",
-       "diff": "sabali",
-       "hist": "saritaan",
+       "diff": "dip",
+       "hist": "hist",
        "hide": "Ilemmeng",
        "show": "Ipakita",
        "minoreditletter": "m",
        "newpageletter": "B",
        "boteditletter": "b",
        "number_of_watching_users_pageview": "[$1 nga agbuybuya {{PLURAL:$1|nga agar-aramat|kadagiti agar-aramat}}]",
-       "rc_categories": "Patingga dagiti kategoria (pagsisinaen ti \"|\")",
+       "rc_categories": "Patingga dagiti kategoria (pagsinaen iti \"|\")",
        "rc_categories_any": "Uray ania",
        "rc-change-size-new": "$1 {{PLURAL:$1|a byte|kadagiti byte}} kalpasan ti panag-sukat",
        "newsectionsummary": "/* $1 */ baro a paset",
        "recentchangeslinked-feed": "Mainaig a sinukatan",
        "recentchangeslinked-toolbox": "Mainaig a sinuksukatan",
        "recentchangeslinked-title": "Sinukatan a mainaig iti \"$1\"",
-       "recentchangeslinked-summary": "Listaan daytoy dagiti kaudian a sinukatan kadagiti pampanid a nakasilpo manipud iti maysa a napili a panid (wenno kadagiti kameng ti maysa a nainaganan a kategoria).\nDagiti panid iti [[Special:Watchlist|listaan ti bambantayam]] ket '''napuskol'''.",
+       "recentchangeslinked-summary": "Daytoy ket listaan dagiti kaudian a sinukatan kadagiti pampanid a nakasilpo manipud iti naisangayan a panid (wenno kadagiti kameng ti maysa a nainaganan a kategoria).\nDagiti panid iti [[Special:Watchlist|listaan ti bambantayam]] ket dagiti <strong>napuskol</strong>.",
        "recentchangeslinked-page": "Nagan ti panid:",
-       "recentchangeslinked-to": "Ipakita dagiti sinukatan a panid nga embes a naisilpo iti naited a panid",
-       "upload": "Mangipan iti papeles",
-       "uploadbtn": "Mangipan iti papeles",
-       "reuploaddesc": "Ukasen ti pag-ipan ken agsubli idiay kabuklan ti pag-ipan",
-       "upload-tryagain": "Ited ti napabaro a panagipalawag ti papeles",
+       "recentchangeslinked-to": "Ipakita dagiti sinukatan kadagiti panid nga imbes a naisilpo iti naited a panid",
+       "upload": "Agikarga iti papeles",
+       "uploadbtn": "Agikarga iti papeles",
+       "reuploaddesc": "Ukasen ti panagikarga ken agsubli idiay porma ti panagikarga",
+       "upload-tryagain": "Mangited ti napabaro a deskripsion ti papeles",
        "uploadnologin": "Saan a nakastrek",
-       "uploadnologintext": "Nasken ti $1 tapno makaipanka iti papeles.",
-       "upload_directory_missing": "Ti direktorio ti pag-ipan ($1) ket napukaw ken saan a mabalin nga aramiden iti webserver.",
-       "upload_directory_read_only": "Ti pagipanan a direktoria ($1) ket saan a masuratan ti webserver.",
-       "uploaderror": "Biddut ti panang-ipan",
-       "upload-recreate-warning": "'''Ballag: Ti papeles babaen ti dayta a nagan ket naikkat wenno naiyalis.'''\n\nTi listaan ti panagikkat ken panagiyalis para iti daytoy a panid ket adda ditoy tapno makitam:",
-       "uploadtext": "Usaren ti kabuklan dita baba ti pinag-ipan ti papeles.\nTi panagkita wenno panagbiruk ti napalubos a pinag-ipan ti papeles mapan ka idiay [[Special:FileList|listaan dagiti napag-ipan a papeles]], dagiti pinag-ipan wenno pinag-ipan manen ket nakalista pay idiay [[Special:Log/upload|listaan ti pinag-ipan]], dagiti panagikkat ket idiay [[Special:Log/delete|listaan ti panagikkat]].\n\nTi panagikabil ti papeles iti panid, usaren ti panilpo a kas dagiti sumaganad a kabuklan:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' ti panag-usar ti dakkel a bersion ti papeles\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|alt text]]</nowiki></code>''' ti agusar ti 200 pixel a kaakaba  a panagparang iti kahon idiay kannigid nga adda 'sabali a testo' ti panagipalpalawag\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' ti dagus a panagsilpo idiay papeles nga awan ti panagparang ti papeles",
+       "uploadnologintext": "Pangngaasi a $1 tapno makaikarga kadagiti papeles.",
+       "upload_directory_missing": "Ti pagikargaan a direktorio ($1) ket awan ken saan a mabalin a mapartuat babaen ti webserver.",
+       "upload_directory_read_only": "Ti pagikargaan a direktorio ($1) ket saan a masuratan babaen ti webserver.",
+       "uploaderror": "Biddut ti panagikarga",
+       "upload-recreate-warning": "<strong>Ballag: Ti papeles babaen ti dayta a nagan ket naikkat wenno naiyalis.</strong>\n\nTi listaan ti panagikkat ken panagiyalis para iti daytoy a panid ket naited ditoy para iti pakainugotan:",
+       "uploadtext": "Usaren ti porman dita baba tapno makaikarga iti papeles.\nTi panagkita wenno panagbiruk ti dati a naikarga a papeles mapan idiay [[Special:FileList|listaan dagiti naikarga a papeles]], dagiti naikarga wenno naikarga manen ket nakalista pay idiay [[Special:Log/upload|listaan ti panagikarga]], dagiti panagikkat ket idiay [[Special:Log/delete|listaan ti panagikkat]].\n\nTi panangiraman ti papeles iti panid, usaren ti silpo a kas dagiti sumaganad a porma:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code></strong> tapno mausar ti napno a bersion ti papeles \n* <strong><code><nowiki>[[</nowiki>{{ns:file<nowiki>:File.png|200px|thumb|left|alt text]]</nowiki></code></strong> tapnomausar ti 200 a piksel a kalawa a panagiparang iti kanigid a margin ng aaddaan iti \"alt text\"a kas deskripsion\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code></strong> para iti dagus a panangisilpo itipapeles nga awan ti panangipakita ti papeles",
        "upload-permitted": "Dagiti mapalubosan a kita ti papeles: $1.",
-       "upload-preferred": "Dagiti mabalbalin a kita ti papeles: $1.",
+       "upload-preferred": "Dagiti kaykayat a kita ti papeles: $1.",
        "upload-prohibited": "Dagiti maiparit a kita ti papeles: $1.",
-       "uploadlogpage": "Listaan ti pagipanan",
-       "uploadlogpagetext": "Adda dita baba ti listaan dagiti kaudian a naipan a papeles.\nKitaen dagiti [[Special:NewFiles|galleria ti baro a papeles]] para iti adu pay a pakabuklan apanagkita.",
+       "uploadlogpage": "Listaan ti panagikarga",
+       "uploadlogpagetext": "Dita baba ket ti listaan dagiti kaudian a panangikarga iti papeles.\nKitaen ti [[Special:NewFiles|galeria dagiti baro a papeles]] para iti adu pay a bisual a pakabuklan.",
        "filename": "Nagan ti papeles",
        "filedesc": "Pakabuklan",
        "fileuploadsummary": "Pakabuklan:",
-       "filereuploadsummary": "Dagiti panagsukat ti papeles:",
-       "filestatus": "Kasasaad ti karbengan ti panagipablaak:",
+       "filereuploadsummary": "Dagiti pannakasukat ti papeles:",
+       "filestatus": "Kasasaad ti karbengan ti kopia:",
        "filesource": "Taudan:",
        "ignorewarning": "Di ikaskaso ti ballaag ket idulin latta ti papeles",
-       "ignorewarnings": "Di ikaskaso dagiti ania man a ballaag",
-       "minlength1": "Dagiti nagan ti papeles ket nasken uray a maysa laeng a letra wenno nasursurok.",
-       "illegalfilename": "Ti nagan ti papeles \"$1\" ket adda nagyan na a kababalin a saan a mabalin kadagiti titulo ti panid.\nPangngaasi ta naganan manen ti papeles ken padasen manen nga ipapan.",
-       "filename-toolong": "Dagiti nagan ti papeles ket saan a mabalin nga at-atiddog ngem dagiti 240 a byte.",
-       "badfilename": "Nasukatan ti nagan ti papeles iti \"$1\".",
-       "filetype-mime-mismatch": "Ti pagpa-atiddog ti papeles \".$1\" ket saan a kapada ti nakitaan a kita ti MIME iti papeles ($2).",
-       "filetype-badmime": "Dagiti papeles a kas MIME a kita \"$1\" ket saan a mapalubosan a maipan.",
-       "filetype-bad-ie-mime": "Saan a makapag-ipan ti papeles ngamin ket masarakan ti Internet Explorer a kas \"$1\", a saan a mabalin ken makapataud a dakes a kita ti papeles.",
-       "filetype-unwanted-type": "'''\".$1\"''' ti saan a mapalubusan a kita ti papeles.\nTi mapalubusan  {{PLURAL:$3|a kita ti papeles ket|kadagiti kita ti papeles ket}} $2.",
-       "filetype-banned-type": "Ti '''\".$1\"''' {{PLURAL:$4|ket saan a mapalubusan a kita ti papeles|ket dagiti saan a mapalubusan a kita ti papeles}}.\nTi mapalubusan {{PLURAL:$3|a kita ti papeles ket|kadagiti kita ti papeles ket}} $2.",
-       "filetype-missing": "Daytoy a papeles ket awan ti kita na a (kasla \".jpg\").",
-       "empty-file": "Ti papeles nga intedmo ket awan ti nagyanna.",
+       "ignorewarnings": "Di ikaskaso dagiti aniaman a ballaag",
+       "minlength1": "Dagiti nagan ti papeles ket nasken a saan a basbassit ngem maysa a letra.",
+       "illegalfilename": "Ti nagan ti papeles ti \"$1\" ket aglaon kadagiti karakter a saan a maipalubos kadagiti titulo ti panid.\nPangngaasi a naganan manen ti papeles ken padasen manen nga ikarga.",
+       "filename-toolong": "Dagiti nagan ti papeles ket nasken a saan nga at-atiddog ngem dagiti 240 a byte.",
+       "badfilename": "Nasukatanen ti nagan ti papeles iti \"$1\".",
+       "filetype-mime-mismatch": "Ti pagpa-atiddog ti papeles ti \".$1\" ket saan a maipada iti naduktalan a kita ti MIME iti papeles ($2).",
+       "filetype-badmime": "Dagiti papeles a kita ti MIME ti \"$1\" ket saan a maipalubos a maikarga.",
+       "filetype-bad-ie-mime": "Saan a maikarga daytoy a papeles gapu ta maduktalan ti Internet Explorer a kas \"$1\", a saan a maipalubos ken makapataud ti dakes a kita ti papeles.",
+       "filetype-unwanted-type": "Ti <strong>\".$1\"</strong> ket mays a di kayat a kita ti papeles.\nTi kaykayat {{PLURAL:$3|a kita ti papeles ket|a kita dagiti papeles ket}} $2.",
+       "filetype-banned-type": "Ti <strong>\".$1\"</strong> {{PLURAL:$4|ket saan a maipalubos a kita ti papeles|ket dagiti saan a maipalubos a kita ti papeles}}.\nTi mapalubosan {{PLURAL:$3|a kita ti papeles ket|a kita dagiti papeles ket}} $2.",
+       "filetype-missing": "Daytoy a papeles ket awan ti pagpaatiddogna (kasla ti \".jpg\").",
+       "empty-file": "Ti papeles nga intedmo ket awan linaonna.",
        "file-too-large": "Ti papeles nga intedmo ket dakkel unay.",
        "filename-tooshort": "Ti nagan daytoy a papeles ket bassit unay.",
-       "filetype-banned": "Ti kita daytoy a papeles ket maiparit.",
-       "verification-error": "Daytoy a papeles ket saan a nakapasa ti pagsingkedan.",
-       "hookaborted": "Ti panagbabaro a pinadasmo ket napasardeng babaen ti pangpa-atiddog a kawit.",
-       "illegal-filename": "Ti nagan daytoy a papeles ket saan a maipalubos.",
-       "overwrite": "Saan a mabalin a suratan manen iti papeles nga adda ditan.",
-       "unknown-error": "Adda di amammo a biddut.",
-       "tmp-create-error": "Saan a makaaramid ti saan nga agnayon a papeles.",
-       "tmp-write-error": "Biddut ti pannakaisurat dagiti saan nga agnanayon a papeles.",
-       "large-file": "Ti maipatalked a papeles ket saan koma a dakdakkel ngem $1;\ndaytoy a papeles ket $2.",
-       "largefileserver": "Daytoy a papeles ket dakdakel ngem ti naaramid a mabalin para iti server.",
-       "emptyfile": "Ti papeles nga ipanmo ket kasla awan ti nagyan na.\nBaka daytoy ket gapu ti kamali ti inkabil a nagan ti papeles.\nPangngaasi ta kitaem no kayatmo latta nga ipapan daytoy a papeles.",
-       "windows-nonascii-filename": "Daytoy a wiki ket saanna a suportaran dagiti nagan ti papeles nga addaan kadagiti espesial a karakter.",
-       "fileexists": "Ti papeles nga agnagan ti kastoy ket addan, pangngaasi a kitaem ti <strong>[[:$1]]</strong> no saanka a sigurado no kayatmo a sukatan.\n[[$1|thumb]]",
-       "filepageexists": "Ti panangipalpalawag a panid para iti daytoy a papeles ket naaramiden idiay <strong>[[:$1]]</strong>, ngem awan ti agdama nga agnagan ti kastoy a papeles.\nTi pakabuklan nga inkabilmo ket saan nga agparang idiay deskripsion ti panid.\nTapno agparang ti pakabuklan idiay, masapul a manual a baliwam.\n[[$1|thumb]]",
-       "fileexists-extension": "Adda papeles nga agnagan ti kastoy: [[$2|thumb]]\n* Nagan ti naipapan a papeles: <strong>[[:$1]]</strong>\n* Nagan ti adda a papeles: <strong>[[:$2]]</strong>\nPangngaasi nga agpili ti sabali a nagan.",
-       "fileexists-thumbnail-yes": "Daytoy a papeles ket kasla ladawan a napabassit ''(thumbnail)''.\n[[$1|thumb]]\nPangngaasi a kitaem ti papeles a <strong>[[:$1]]</strong>.\nNo ti nakitam a papeles ket isu ti ladawan iti dati a kadakkel saanen a nasken ti agipan ti maysa a napabassit a ladawan.",
-       "file-thumbnail-no": "Ti nagan ti papeles ket mangrugi iti <strong>$1</strong>.\nKasla ladawan a napabassit ''(thumbnail)''.\nNo addaanka ti napno a resolusion ipanmo daytoy, no saan pangngaasi a sukatam ti nagan ti papeles.",
-       "fileexists-forbidden": "Daytoy a nagan ti papeles ket adda dita, ken saan a mabalin a masuratan manen.\nNo kayatmo pay latta nga ipan ti papeles, pangngaasi nga agsublika ken usarem ti baro a nagan.\n[[File:$1|thumb|center|$1]]",
-       "fileexists-shared-forbidden": "Daytoy a nagan ti papeles ket adda dita pagbingayan a nagikabilan ti papeles.\nNo kayatmo pay latta nga ipan ti papeles, pangngaasi nga agsublika ken usarem ti baro a nagan.\n[[File:$1|thumb|center|$1]]",
+       "filetype-banned": "Daytoy a kita ti papeles ket maiparit.",
+       "verification-error": "Daytoy a papeles ket saan a nakapasa iti pammasingked iti papeles.",
+       "hookaborted": "Ti panagbabaro a pinadasmo ket napasardeng babaen ti pangpaatiddog.",
+       "illegal-filename": "Ti nagan ti papeles ket saan a maipalubos.",
+       "overwrite": "Saan a maipalubos ti mangsurat manen iti addan a papeles.",
+       "unknown-error": "Napasamak ti maysa a di ammo a biddut.",
+       "tmp-create-error": "Saan a makapartuat ti temporario a papeles.",
+       "tmp-write-error": "Biddut ti panagsurat iti temporario a papeles.",
+       "large-file": "Maisingasing a dagiti papeles ket saan a dakdakkel ngem $1;\ndaytoy a papeles ket $2.",
+       "largefileserver": "Daytoy a papeles ket dakdakel ngem ti ipalubos a pannakaaramid ti server.",
+       "emptyfile": "Ti papeles nga inkargam ket kasla awan linaon.\nBaka daytoy ket gapu ti kamali iti nagan ti papeles.\nPangngaasi ta kitaem no kayatmo latta nga ikarga daytoy a papeles.",
+       "windows-nonascii-filename": "Daytoy a wiki ket saan a mangsuporta kadagiti nagan ti papeles nga addaan kadagiti espesial a karakter.",
+       "fileexists": "Ti papeles nga agnagan ti kastoy ket addan, pangngaasi a kitaem ti <strong>[[:$1]]</strong> no {{GENDER:|saanka}} a sigurado a kayatmo a sukatan daytoy.\n[[$1|thumb]]",
+       "filepageexists": "Ti deskripsion a panid para iti daytoy a papeles ket napartuaten idiay <strong>[[:$1]]</strong>, ngem awan ti agdama nga agnagan ti kastoy a papeles.\nTi pakabuklan nga inkabilmo ket saan nga agparang iti deskripsion ti panid.\nTapno agparang ti pakabuklan idiay, masapul a manual nga urnosem.\n[[$1|thumb]]",
+       "fileexists-extension": "Adda papeles nga agnaganen iti kastoy: [[$2|thumb]]\n* Nagan ti naikarga a papeles: <strong>[[:$1]]</strong>\n* Nagan ti adda a papeles: <strong>[[:$2]]</strong>\nKayatmo kadi ti agusar ti naisangsangayan a nagan?",
+       "fileexists-thumbnail-yes": "Daytoy a papeles ket kasla ladawan a napabassit a kadakkel <em>(thumbnail)</em>..\n[[$1|thumb]]\nPangngaasi a kitaem ti papeles ti <strong>[[:$1]]</strong>.\nNo ti nakitam a papeles ket isu ti ladawan iti dati a kadakkel saanen a nasken ti agikarga ti maysa a napabassit unay a ladawan.",
+       "file-thumbnail-no": "Ti nagan ti papeles ket mangrugi iti <strong>$1</strong>.\nKasla ti ladawan a napabassit ti kadakkel <em>(thumbnail)</em>.\nNo addaanka iti daytoy a ladawan iti napno a resolusion ikargam dayta, no saan pangngaasi a sukatam ti nagan ti papeles.",
+       "fileexists-forbidden": "Daytoy a nagan ti papeles ket addan, ken saan a mabalin a masuratan manen.\nNo kayatmo pay latta nga ikarga ti papelesmo, pangngaasi nga agsublika ken agusar iti baro a nagan.\n[[File:$1|thumb|center|$1]]",
+       "fileexists-shared-forbidden": "Ti papeles iti daytoy a nagan ket addan iti pagbingayan a repositorio ti papeles.\nNo kayatmo pay latta nga ikarga ti papeles, pangngaasi nga agsublika ken agusar iti baro a nagan.\n[[File:$1|thumb|center|$1]]",
        "file-exists-duplicate": "Daytoy a papeles ket duplikado kadagiti sumaganad a {{PLURAL:$1|papeles|pappapeles}}:",
-       "file-deleted-duplicate": "Ti papeles a kapadpada ti papeles a ([[:$1]]) ket naikkat idin.\nKitaem koma ti pakasaritaan a panakaikkat ti papeles sakbay a mangirugika ti pinag-ipan.",
-       "file-deleted-duplicate-notitle": "Ti papales a kapada ti daytoy a papeles ket dati a naikkat, ken nalapdan ti titulo.\nNasken nga agdamagka ti addaan ti abilidad a mangkita ti nalapdan a datos ti papeles tapno marepaso ti kasasaad sakbay a mapan nga ikarga manen daytoy.",
-       "uploadwarning": "Ballaag iti pinag-ipan",
-       "uploadwarning-text": "Pangngaasi a baliwam ti deskripsion ti papeles ken padasem manen.",
+       "file-deleted-duplicate": "Ti papeles a kapadpada ti papeles a ([[:$1]]) ket dati a naikkat.\nKitaem koma ti pakasaritaan a pannakaikkat ti papeles sakbay a mangirugika a mangikarga manen.",
+       "file-deleted-duplicate-notitle": "Ti papales a kapada iti daytoy a papeles ket dati a naikkat, ken nalapdan ti titulo.\nNasken nga agdamagka iti sabali nga addaan iti abilidad a mangrepaso ti nalapdan a datos ti papeles tapno marepaso ti kasasaad sakbay a mapan nga agikarga manen iti daytoy.",
+       "uploadwarning": "Ballaag ti panagikarga",
+       "uploadwarning-text": "Pangngaasi a baliwam ti deskripsion ti papeles dita baba ken padasen manen.",
        "savefile": "Idulin ti papeles",
-       "uploadedimage": "naipanen ti \"[[$1]]\"",
-       "overwroteimage": "naipan ti baro a bersion ti \"[[$1]]\"",
-       "uploaddisabled": "Naiddep ti pinag-ipan.",
-       "copyuploaddisabled": "Naiddep ti pinag-ipan iti URL.",
-       "uploaddisabledtext": "Napawilan ti pinag-ipan iti papeles.",
-       "php-uploaddisabledtext": "Ti pinag-ipan ti papeles ket naiddep idiay PHP.\nPanngaasi a kitaem ti pannakaikabil ti pinag-ipan ti papeles.",
-       "uploadscripted": "Daytoy a papeles ket adda nagyanna a HTML wenno panagsurat a kodigo a mabalin nga agpakamali ti panagbasa ti sapot a pagbasabasa.",
+       "uploadedimage": "naikarga ti \"[[$1]]\"",
+       "overwroteimage": "nagikarga ti baro a bersion ti \"[[$1]]\"",
+       "uploaddisabled": "Nabaldado dagiti panagikarga.",
+       "copyuploaddisabled": "Nabaldado ti panagikarga babaen ti URL.",
+       "uploaddisabledtext": "Nabaldado dagiti panagikarga ti papeles.",
+       "php-uploaddisabledtext": "Dagiti panangikarga ti papeles ket nabaldado iti PHP.\nPanngaasi a kitaem ti pannakaisaad ti panagikarga ti papeles.",
+       "uploadscripted": "Daytoy a papeles ket naglaon ti HTML wenno eskritu ti kodigo a mabalin a kamali nga inpatarus babaen ti pagbasabasa ti web.",
        "uploadscriptednamespace": "Daytoy a papeles ti SVG ket aglaon ti maysa a saan a mabalin a nagan ti espasio ti \"$1\"",
        "uploadinvalidxml": "Ti XML iti naikarga a papeles ket saan a maiwaswas.",
-       "uploadvirus": "Addaan ti birus daytoy a papeles! Salaysay: $1",
-       "uploadjava": "Daytoy a papeles ket ZIP a papeles nga adda nagyanna a Java .a kita ti papeles.\nSaan a mabalin ti pinag-ipan ti Java a papeles, ngamin ket palabsanda dagiti seguridad a pangrestrikto.",
+       "uploadvirus": "Ti papeles ket aglaon ti birus! \nDagiti salaysay: $1",
+       "uploadjava": "Daytoy a papeles ket papeles ti ZIP nga aglaon ti Java .a klase ti papeles.\nTi panangikarga ti papales ti Java ket saan a maipalubos gapu ta makapataudda a manglabas kadagiti panangigawid ti seguridad.",
        "upload-source": "Taudan ti papeles",
        "sourcefilename": "Taudan a nagan ti papeles:",
        "sourceurl": "Taudan ti URL:",
        "destfilename": "Pangipanan ti nagan ti papeles:",
-       "upload-maxfilesize": "Kadakkel a rukod ti papeles: $1",
-       "upload-description": "Panagipalpalawag ti papeles",
-       "upload-options": "Pagpilian ti pinag-ipan",
+       "upload-maxfilesize": "Kadakkelan a rukod ti papeles: $1",
+       "upload-description": "Deskripsion ti papeles",
+       "upload-options": "Dagiti pagpilian ti panagikarga",
        "watchthisupload": "Bantayan daytoy a papeles",
-       "filewasdeleted": "Ti papeles a nanaganan ti kastoy ket naipapan idin ken napaikkaten.\nKitaem ti $1 sakbay ka nga agi pag-ipan manen.",
-       "filename-bad-prefix": "Ti nagan ti papeles nga inpanmo ket mangrugi ti '''\"$1\"''', ket saan a maipalpalawag a nagan a kayarigan a naipusgan nga automatiko kadagiti digital a pangretrato.\nPangngaasi ti agpili ti maikapalpalawag a nagan ti papelesmo.",
-       "upload-success-subj": "Balligi ti pinag-ipan",
-       "upload-success-msg": "Ti panag-ipan a naggapu idiay [$2] ket naballigi. Ket adda ditoy: [[:{{ns:file}}:$1]]",
-       "upload-failure-subj": "Parikut ti pinag-ipan",
-       "upload-failure-msg": "Addaan ti parikut ti pinag-ipanmo a naggapu idiay [$2]:\n\n$1",
-       "upload-warning-subj": "Ballaag iti pinag-ipan",
-       "upload-warning-msg": "Addaan a parikut ti panag-ipan a naggapu idiay [$2]. Mabalinmo ti agsubli ti [[Special:Upload/stash/$1|nakabuklan ti pag-ipan]] tapno masimpaan ti parikut.",
+       "filewasdeleted": "Ti papeles iti daytoy a nagan ket dati a naikarga ken kanungpalan a naikkat.\nNasken a kitaem ti $1 sakbay nga agtuloy a mangikarga manen.",
+       "filename-bad-prefix": "Ti nagan ti papeles nga ikarkargam ket mangrugi iti <strong>\"$1\"</strong>,  ken saan a deskriptibo a nagan a kadawyan nga automatiko nga ited babaen dagiti digital a kamera.\nPangngaasi nga agpili ti nasaysayaat a deskriptibo a nagan ti papelesmo.",
+       "upload-success-subj": "Balligi ti panagikarga",
+       "upload-success-msg": "Ti panagikargam manipud ti [$2] ket nagballigi. Daytoy ket magun-od ditoy [[:{{ns:file}}:$1]]",
+       "upload-failure-subj": "Parikut ti panagikarga",
+       "upload-failure-msg": "Adda parikut ti panagikargam manipud ti [$2]:\n\n$1",
+       "upload-warning-subj": "Ballaag ti panagikarga",
+       "upload-warning-msg": "Adda parikut iti panagikargam manipud ti [$2]. Mabalinmo ti agsubli iti [[Special:Upload/stash/$1|porma ti panagikarga]] tapno masimpa daytoy a parikut.",
        "upload-proto-error": "Saan a husto a protokol",
-       "upload-proto-error-text": "Dagiti adayo a pinag-ipan ket makasapul kadagiti URL a mangrugi iti <code>http://</code> wenno <code>ftp://</code>.",
+       "upload-proto-error-text": "Ti adayo a panagikarga ket makasapul kadagiti URL a mangrugi iti <code>http://</code> wenno <code>ftp://</code>.",
        "upload-file-error": "Akin-uneg a biddut",
-       "upload-file-error-text": "Adda biddut a naggapu iti uneg idi padasen ti agaramid ti saan nga agnayon a papeles dita server.\nPangngaasi a kontaken ti [[Special:ListUsers/sysop|administrador]]",
-       "upload-misc-error": "Di ammo a biddut ti panag-ipan",
-       "upload-misc-error-text": "Adda saan nga ammo a biddut ti napasamak idi agdama a nag-ipan.\nPangngaasi a  kitaen ti URL ket umisu  ken maserrekan ken padasem manen.\nNo ti parikut ket agsubli latta, kontaken ti [[Special:ListUsers/sysop|administrador]].",
-       "upload-too-many-redirects": "Adu unay ti baw-ing daytoy nga URL",
-       "upload-http-error": "Naka-adda ti biddut ti HTTP: $1",
-       "upload-copy-upload-invalid-domain": "Ti kopia a panagipan ket saan a magun-od manipud iti daytoy a pagturayan.",
-       "backend-fail-stream": "Saan a maiwaig ti papeles $1.",
-       "backend-fail-backup": "Saan a maidulin ti papeles $1.",
-       "backend-fail-notexists": "Ti papeles a $1 ket awanen.",
-       "backend-fail-hashes": "Saan a maala dagiti papeles a hash tapno maipada.",
-       "backend-fail-notsame": "Addaan ti saan a kapada ti papeles idiay $1.",
-       "backend-fail-invalidpath": "$1 ket imbalido a pagnaan ti pagidulinan.",
-       "backend-fail-delete": "Saan a maikkat ti papeles $1.",
-       "backend-fail-describe": "Saam a mabaliwan ti metadata para iti papeles ti \"$1\".",
-       "backend-fail-alreadyexists": "Ti papeles $1 ket addan.",
-       "backend-fail-store": "Saan a maidulin ti papeles $1 idiay $2.",
-       "backend-fail-copy": "Saan a makopia ti papeles $1 idiay $2.",
-       "backend-fail-move": "Saan a maiyalis ti papeles $1 idiay $2.",
+       "upload-file-error-text": "Adda napasamak nga akin-uneg a biddut idi nagpadpadas nga agpartuat ti temporario a papeles iti server.\nPangngaasi a kontaken ti maysa nga [[Special:ListUsers/sysop|administrador]].",
+       "upload-misc-error": "Di ammo a biddut ti panagikarga",
+       "upload-misc-error-text": "Adda napasamak a di ammo a biddut idi las-ud ti panagikarga.\nPangngaasi a pasingkedan ti URL ket umisu ken maserrekan ken padasem manen.\nNo ti parikut ket agsubli latta, kontaken ti maysa nga [[Special:ListUsers/sysop|administrador]].",
+       "upload-too-many-redirects": "Ti URL ket naglaon kadagiti adu unay a baw-ing",
+       "upload-http-error": "Adda napasamak a biddut ti HTTP: $1",
+       "upload-copy-upload-invalid-domain": "Dagiti kopia a panagikarga ket saan a magun-od manipud ti daytoy a dominio.",
+       "backend-fail-stream": "Saan a maipan ti papeles $1.",
+       "backend-fail-backup": "Saan a makaidulin ti kapada ti papeles ti $1.",
+       "backend-fail-notexists": "Awan ti papeles ti $1.",
+       "backend-fail-hashes": "Saan a makaala kadagiti hash ti papeles para iti panangipada.",
+       "backend-fail-notsame": "Addan ti awan kapada a papeles idiay \"$1\".",
+       "backend-fail-invalidpath": "Ti \"$1\" ket imbalido a dalan ti pagidulinan.",
+       "backend-fail-delete": "Saan a maikkat ti papeles ti \"$1\".",
+       "backend-fail-describe": "Saan a mabaliwan ti metadata para iti papeles ti \"$1\".",
+       "backend-fail-alreadyexists": "Addan ti papeles ti \"$1\".",
+       "backend-fail-store": "Saan a maidulin ti papeles ti \"$1\" iti \"$2\".",
+       "backend-fail-copy": "Saan a makopia ti papeles ti \"$1\" iti \"$2\".",
+       "backend-fail-move": "Saan a maiyalis ti papeles ti \"$1\" iti \"$2\".",
        "backend-fail-opentemp": "Saan a malukatan ti temporario a papeles.",
        "backend-fail-writetemp": "Saan a masuratan ti temporario a papeles.",
        "backend-fail-closetemp": "Saan a marikpan ti temporario a papeles.",
-       "backend-fail-read": "Saan a mabasa ti papeles $1.",
-       "backend-fail-create": "Saan a masuratan ti papeles $1.",
-       "backend-fail-maxsize": "Saan a masuratan ti papeles $1 gaputa dakdakkel ngem {{PLURAL:$2|maysa a byte|dagiti $2 a byte}}.",
-       "backend-fail-readonly": "Ti pagidulinan a kalikudan ti \"$1\" ket agdama a mabasa laeng. Ti rason a naited idi ket: \"$2\"",
-       "backend-fail-synced": "Ti papeles \"$1\" ket bangking ti kasasaadna iti kinauneg a pagidulinan ti kalikudan",
-       "backend-fail-connect": "Saan a makaikapet idiay pagidulinan a kalikudan  \"$1\".",
-       "backend-fail-internal": "Adda di amammo a biddut ti napasamak idiay pagidulinan a kalikudan \"$1\".",
-       "backend-fail-contenttype": "Saan a maammoan ti kita ti linaon ti papeles nga idulin idiay \"$1\".",
-       "backend-fail-batchsize": "Nagited ti nagipenpenan ti bunggoy iti $1 a papeles {{PLURAL:$1|nga aramid|nga ar-aramid}}; ti patingga ket $2 {{PLURAL:$2|nga aramid|nga ar-aramid}}.",
-       "backend-fail-usable": "Saan a mabasa wenno masuratan ti papeles $1 gaputa awan ti makaanay a pammalubos wenno awan dagiti direktorio/pangikabilan.",
-       "filejournal-fail-dbconnect": "Saan a maikapet idiay warnakan a database para iti likudan a pagipenpenan \"$1\".",
-       "filejournal-fail-dbquery": "Saan a makapabaro idiay warnakan a database para iti likudan a pagipenpenan \"$1\".",
+       "backend-fail-read": "Saan a mabasa ti papeles ti \"$1\".",
+       "backend-fail-create": "Saan a masuratan ti papeles ti \"$1\".",
+       "backend-fail-maxsize": "Saan a masuratan ti papeles ti \"$1\" gapu ta daytoy ket dakdakkel ngem {{PLURAL:$2|maysa a byte|dagiti $2 a byte}}.",
+       "backend-fail-readonly": "Ti pagidulinan a kalikudan ti \"$1\" ket agdama a mabasa laeng. Ti rason a naited idi ket: \"<em>$2</em>\"",
+       "backend-fail-synced": "Ti papeles ti \"$1\" ket bangking ti kasasaadna iti kaunegan a pagidulinan dagiti kalikudan",
+       "backend-fail-connect": "Saan a makaikapet idiay pagidulinan a kalikudan ti \"$1\".",
+       "backend-fail-internal": "Adda napasamak a di ammo a biddut idiay pagidulinan a kalikudan ti \"$1\".",
+       "backend-fail-contenttype": "Saan a maikeddeng ti kita ti linaon iti papeles a maidulin iti \"$1\".",
+       "backend-fail-batchsize": "Ti pagidulinan a likudan ket naited a paset ti papeles ti $1 nga {{PLURAL:$1|operasion|op-operasion}}; ti patingga ket $2 nga {{PLURAL:$2|operasion|op-operasion}}.",
+       "backend-fail-usable": "Saan a mabasa wenno masuratan ti papeles ti \"$1\" gapu ta awan ti makaanay a pammalubos wenno awan dagiti direktorio/pagikabilan.",
+       "filejournal-fail-dbconnect": "Saan a maikapet iti database ti warnakan a para iti likudan a pagipenpenan ti \"$1\".",
+       "filejournal-fail-dbquery": "Saan a makapabaro ti database ti warnakan para iti likudan a pagipenpenan ti \"$1\".",
        "lockmanager-notlocked": "Saan a malukatan ti \"$1\"; saan a nakandaduan.",
        "lockmanager-fail-closelock": "Saan a marikepan ti nakandaduan a papeles para iti \"$1\".",
-       "lockmanager-fail-deletelock": "Saan a maikkat ti nakandaduan a papeles para iti \"$1\".",
+       "lockmanager-fail-deletelock": "Saan a maikkat ti kandado ti papeles para iti \"$1\".",
        "lockmanager-fail-acquirelock": "Saan a makaala ti kandado para iti \"$1\".",
        "lockmanager-fail-openlock": "Saan a malukatan ti kandado ti papeles para iti \"$1\".",
        "lockmanager-fail-releaselock": "Saan a maibbatan ti kandado para iti \"$1\".",
-       "lockmanager-fail-db-bucket": "Saan a makasilpo ti umanay a kandado kadagiti database idiay timba $1.",
-       "lockmanager-fail-db-release": "Saan a maibbatan dagiti kandado idiay database $1.",
-       "lockmanager-fail-svr-acquire": "Saan a makaala kadagiti kandado ti server $1.",
-       "lockmanager-fail-svr-release": "Saan a maibbatan dagiti kandado idiay server $1.",
-       "zip-file-open-error": "Adda biddut a nasarakan idi panaglukat ti papeles ti panagkita a ZIP.",
-       "zip-wrong-format": "Ti nainagan a papeles ket saan a ZIP a papeles.",
-       "zip-bad": "Daytoy a papeles ket nadadael wenno saan a mabasa a kas ZIP a papeles.\nSaan a mabalin a nasayaat a makita para iti seguridad.",
-       "zip-unsupported": "Ti papeles ket ZIP a papeles nga agus-usar ti ZIP a langa a saan a sinuportaran babaen ti MediaWiki .\nSaan a mabalin a nasayaat a makita para iti seguridad.",
-       "uploadstash": "Pinag-ipan ti stash",
-       "uploadstash-summary": "Daytoy a panid ket mangted ti panagserrek kadagiti papeles a napag-ipan (wenno nairugi a naipan) ngem saan pay a naipablaak iti wiki. Dagitoy a papeles ket saan a makita ti sabsabali ngem laeng ti agar-aramat a nag-ipan kaniada.",
+       "lockmanager-fail-db-bucket": "Saan a makakontak ti umanay a kandado dagiti database idiay timba ti $1.",
+       "lockmanager-fail-db-release": "Saan a maibbatan dagiti kandado iti database ti $1.",
+       "lockmanager-fail-svr-acquire": "Saan a makaala kadagiti kandado ti server ti $1.",
+       "lockmanager-fail-svr-release": "Saan a maibbatan dagiti kandado iti server ti $1.",
+       "zip-file-open-error": "Adda napasamak a biddut idi lukluktan ti papeles para kadagiti panagkita ti ZIP.",
+       "zip-wrong-format": "Ti nainagan a papeles ket saan a papeles ti ZIP.",
+       "zip-bad": "Daytoy a papeles ket nadadael wenno saan a mabasa a papeles ti ZIP.\nSaan a mabalin a nasayaat a makita para iti seguridad.",
+       "zip-unsupported": "Ti papeles ket papales ti ZIP nga agus-usar ti ZIP a langa a saan a masuportaran babaen ti MediaWiki .\nSaan a mabalin a nasayaat a makita para iti seguridad.",
+       "uploadstash": "Panagikarga ti stash",
+       "uploadstash-summary": "Daytoy a panid ket mangited ti panagserrek kadagiti papeles a naikarga wenno mangrugrugi iti proseso a maikarga, ngem saan pay a naipablaak iti wiki. Dagitoy a papeles ket saan a makita ti sinoman ngem ti laeng agar-aramat a nagikarga kaniada.",
        "uploadstash-clear": "Dalusan dagiti na-stash a papeles",
        "uploadstash-nofiles": "Awan ti na-stash a papelesmo.",
-       "uploadstash-badtoken": "Ti panag-tungpal dayta nga aramid ket napaay, ngamin ta dagiti talekmo ti panag-urnos ket nagpaso. Padasem manen.",
+       "uploadstash-badtoken": "Ti panag-tungpal dayta nga aramid ket napaay, ngamin ta dagiti talekmo ti panag-urnos ket nagpason. Padasen manen.",
        "uploadstash-errclear": "Ti panagdalus kadagiti papeles ket napaay.",
-       "uploadstash-refresh": "Pasadiwaam dagiti listaan ti papeles",
-       "invalid-chunk-offset": "Imbalido ti maysa a tangdan",
-       "img-auth-accessdenied": "naiparit ti iseserrek",
-       "img-auth-nopathinfo": "Ti servermo ket mabalin nga agipasa iti daytoy a pakaammo.\nBaka met laeng naibasta ti CGI ken saan na a tapayaen ti img_auth.\nKitaen ti https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization .",
-       "img-auth-notindir": "Ti kiniddaw a dalan ket saan a ti naaramid a direktorio ti pag-ipan",
-       "img-auth-badtitle": "Saan a makaaramid ti umisu a titulo a naggapu idiay \"$1\".",
+       "uploadstash-refresh": "Pasadiwaen dagiti listaan ti papeles",
+       "invalid-chunk-offset": "Imbalido a pirgis ti timbengan",
+       "img-auth-accessdenied": "Nalibak ti iseserrek",
+       "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 ti \"$1\".",
        "img-auth-nologinnWL": "Saanka a nakastrek ken ti \"$1\" ket awan idiay mabalin a listaan.",
-       "img-auth-nofile": "Ti papeles \"$1\" ket awan dita.",
-       "img-auth-isdir": "Agserserrekka ti direktorio ti papeles \"$1\".\nTi iseserrek ti papeles ti mabalin laeng.",
-       "img-auth-streaming": "Agwaig \"$1\".",
-       "img-auth-public": "Ti pamay-an ti img_auth.php ket mangiruar kadagiti papeles manipud ti pribado a wiki.\nDaytoy a wiki naipabalin a kas publiko a wiki.\nPara iti kangatuan a talinaay, nabaldado ti img_auth.php.",
-       "img-auth-noread": "Ti agar-aramat ket awan ti pammalubosna nga agbasa \"$1\".",
+       "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 ti \"$1\".",
+       "img-auth-public": "Ti annong ti img_auth.php ket ti mangiruar kadagiti papeles manipud ti pribado a wiki.\nDaytoy a wiki naaramid a kas publiko a wiki.\nPara iti kangatuan a seguridad, nabaldado ti img_auth.php.",
+       "img-auth-noread": "Ti agar-aramat ket awan ti pammalubosna nga agbasa ti \"$1\".",
        "http-invalid-url": "Imbalido nga URL: $1",
-       "http-invalid-scheme": "Ti URL nga adda ti \"$1\" a pamuspusan ket saan a masuportaran.",
+       "http-invalid-scheme": "Dagiti URL nga addan iti \"$1\" a pamuspusan ket saan a masuportaran.",
        "http-request-error": "Ti panagkiddaw ti HTTP ket napaay gapu ti di ammo a biddut.",
        "http-read-error": "Biddut ti panagbasa ti HTTP.",
        "http-timed-out": "Nagsardeng ti panagkiddaw ti HTTP.",
        "http-curl-error": "Biddut ti panagala ti URL: $1",
        "http-bad-status": "Adda pakirut idi las-ud ti panagkiddaw ti HTTP: $1 $2",
        "upload-curl-error6": "Di madanon ti URL",
-       "upload-curl-error6-text": "Ti URL a naited ket saan a madanon.\nPangngaasi a kitaem manen no husto ti URL ken adda dayta a pagsaadan.",
-       "upload-curl-error28": "Nagsardeng ti panag-ipan",
-       "upload-curl-error28-text": "Ti pagsaadan ket nabayag unay a simmungbat.\nPangngaasi a kitaen no naipatakder ti pagsaadan, aguray no madamdama ket padasem manen.\nBaka kayatmo a padasen no saan a makumikom nga oras.",
-       "license": "Lisensia:",
-       "license-header": "Lisensia",
+       "upload-curl-error6-text": "Ti URL a naited ket saan a madanon.\nPangngaasi a kitaem manen no husto ti URL ken adda dayta a sitio.",
+       "upload-curl-error28": "Nagsardeng ti panagikarga",
+       "upload-curl-error28-text": "Ti sitio ket nabayag unay a simmungbat.\nPangngaasi a kitaen no naipatakder ti sito, aguray no madamdama ket padasen manen.\nBaka kayatmo a padasen iti saan a makumikom nga oras.",
+       "license": "Panaglisensia:",
+       "license-header": "Panaglisensia",
        "nolicense": "Awan ti napili",
-       "license-nopreview": "(Saan a mabalin nga ipadas)",
-       "upload_source_url": " (maysa nga umisu, ken maserrekan ti publiko nga URL)",
-       "upload_source_file": "(papeles iti kompiutermo)",
-       "listfiles-summary": "Daytoy nga espesial a panid ket agiparang kadagiti amin a naipan a papeles.",
-       "listfiles_search_for": "Agsapul para iti nagan ti midia:",
+       "licenses-edit": "Urnosen dagiti pagpilian ti lisensia",
+       "license-nopreview": "(Saan a magun-od ti panagipadas)",
+       "upload_source_url": "(maysa nga umisu, ken publiko a maserrekan nga URL)",
+       "upload_source_file": "(ti papeles iti kompiutermo)",
+       "listfiles-delete": "ikkaten",
+       "listfiles-summary": "Daytoy nga espesial a panid ket agiparang kadagiti amin a naikarga a papeles.",
+       "listfiles_search_for": "Agbiruk para iti nagan ti midia:",
        "imgfile": "papeles",
        "listfiles": "Listaan ti papeles",
        "listfiles_thumb": "Bassit a ladawan",
        "listfiles_name": "Nagan",
        "listfiles_user": "Agar-aramat",
        "listfiles_size": "Kadakkel",
-       "listfiles_description": "Panagipalpalawag",
+       "listfiles_description": "Deskripsion",
        "listfiles_count": "Dagiti bersion",
        "listfiles-show-all": "Iraman dagiti daan a bersion dagiti ladawan",
        "listfiles-latestversion": "Agdama a bersion",
        "listfiles-latestversion-no": "Saan",
        "file-anchor-link": "Papeles",
        "filehist": "Pakasaritaan ti papeles",
-       "filehist-help": "Ipindut ti maysa a petsa/oras tapno makitam ti papeles iti kasisigud a langana iti dayta nga oras.",
+       "filehist-help": "Pinduten iti petsa/oras tapno makita ti papeles a kas naiparang iti dayta a panawen.",
        "filehist-deleteall": "ikkaten amin",
        "filehist-deleteone": "ikkaten",
        "filehist-revert": "isubli",
        "filehist-datetime": "Petsa/Oras",
        "filehist-thumb": "Bassit a ladawan",
        "filehist-thumbtext": "Bassit a ladawan para iti bersion manipud idi $1",
-       "filehist-nothumb": "Awan ti napabassit a ladawan",
+       "filehist-nothumb": "Awan ti bassit a ladawan",
        "filehist-user": "Agar-aramat",
        "filehist-dimensions": "Dagiti rukod",
        "filehist-filesize": "Kadakkel ti papeles",
        "filehist-comment": "Komentario",
-       "imagelinks": "Panagusar ti papeles",
-       "linkstoimage": "Ti sumaganad {{PLURAL:$1|a silpo ti panid|kadagiti $1 a silpo ti panid}} ditoy a papeles:",
-       "linkstoimage-more": "Ad-adu ngem $1 {{PLURAL:$1|a silsilpo ti panid|silpo ti pampanid}} iti daytoy a papeles.\nTi sumaganad a listaan ket agipakita {{PLURAL:$1|ti umona a silpo ti panid|kadagiti umuna a $1 a silpo ti panid}} iti daytoy laeng a papeles.\nMagun-od ti [[Special:WhatLinksHere/$2|kompleto a listaan]].",
+       "imagelinks": "Panag-usar ti papeles",
+       "linkstoimage": "Ti sumaganad {{PLURAL:$1|a silsilpo ti panid|kadagiti $1 a silpo ti pampanid}} iti daytoy a papeles:",
+       "linkstoimage-more": "Ad-adu ngem $1 {{PLURAL:$1|a silsilpo ti panid|a silpo ti pampanid}} iti daytoy a papeles.\nTi sumaganad a listaan ket mangipakita {{PLURAL:$1|ti umona a silpo ti panid|kadagiti umuna a $1 a silsilpo ti panid}} iti daytoy laeng a papeles.\nMagun-od ti [[Special:WhatLinksHere/$2|kompleto a listaan]].",
        "nolinkstoimage": "Awan ti pampanid a nakasilpo iti daytoy a papeles.",
-       "morelinkstoimage": "Kitaen ti [[Special:WhatLinksHere/$1|ad-adu pay a silpo]] iti daytoy a papeles.",
+       "morelinkstoimage": "Kitaen ti [[Special:WhatLinksHere/$1|adu pay a silsilpo]] iti daytoy a papeles.",
        "linkstoimage-redirect": "$1 (baw-ing ti papeles) $2",
-       "duplicatesoffile": "Ti sumaganad a {{PLURAL:$1|papeles ket duplikado|a $1 a pappapeles ket duplikado}} iti daytoy a papeles ([[Special:FileDuplicateSearch/$2|adu pay a salaysay]]):",
-       "sharedupload": "Daytoy a papeles ket naggapu idiay $1 ken mabalin a mausar kadagiti sabsabali a gandat.",
-       "sharedupload-desc-there": "Daytoy a papeles ket naggapu idiay $1 ken mabalin a mausar kadagiti sabsabali a gandat.\nPangngaasi a kitaem ti [$2 pagipalpalawag ti panid] para iti adu pay a pakaammo.",
-       "sharedupload-desc-here": "Daytoy a papeles ket naggapu idiay $1 ken mabalin a mausar kadagiti sabsabali a gandat.\nTi pagipalpalawagna idiay [$2 pagipalpalawag a panid ti papeles ] ket naipakita dita baba.",
-       "sharedupload-desc-edit": "Daytoy a papeles ket naggapu manipud idiay $1 ken mabalin a mausar babaen dagiti sabali a gandat.\nBaka kayatmo nga urnosen ti bukodna a deskripsion idiay [$2 deskripsion ti papeles a panid].",
-       "sharedupload-desc-create": "Daytoy a papeles ket naggapu manipud idiay $1 ken mabalin a mausar babaen dagiti sabali a gandat.\nBaka kayatmo nga urnosen ti bukodna a deskripsion idiay [$2 deskripsion ti papeles a panid].",
+       "duplicatesoffile": "Ti sumaganad a {{PLURAL:$1|papeles ket duplikado|a $1 a pappapeles ket duplikado}} iti daytoy a papeles ([[Special:FileDuplicateSearch/$2|adu pay a salaysay]]):",
+       "sharedupload": "Daytoy a papeles ket manipud ti $1 ken mabalin a mausar babaen dagiti sabali a gandat.",
+       "sharedupload-desc-there": "Daytoy a papeles ket manipud ti $1 ken mabalin a mausar babaen dagiti sabali a gandat.\nPangngaasi a kitaem ti [$2 panid ti deskripsion ti papeles] para iti adu pay a pakaammo.",
+       "sharedupload-desc-here": "Daytoy a papeles ket manipud ti $1 ken mabalin a mausar babaen dagiti sabali a gandat.\nTi deskripsion iti [$2 panid ti deskripsion ti papelesna] idiay ket naipakita dita baba.",
+       "sharedupload-desc-edit": "Daytoy a papeles ket manipud ti $1 ken mabalin a mausar babaen dagiti sabali a gandat.\nMabalin a kayatmo nga urnosen ti bukodna a deskripsion idiay [$2 panid ti deskripsion ti papeles].",
+       "sharedupload-desc-create": "Daytoy a papeles ket manipud ti $1 ken mabalin a mausar babaen dagiti sabali a gandat.\nMabalin a kayatmo nga urnosen ti bukodna a deskripsion idiay [$2 panid ti deskripsion ti papeles].",
        "filepage-nofile": "Awan ti agnagan ti kasta a papeles.",
-       "filepage-nofile-link": "Awan ti agnagan ti kastoy a papeles, ngem mabalinmo ti [$1 mangipan].",
-       "uploadnewversion-linktext": "Mangipan ti kabarbaro a bersion iti daytoy a papeles",
-       "shared-repo-from": "Naggapo iti $1",
-       "shared-repo": "iti pagbingbingayan a nagikabilan",
-       "upload-disallowed-here": "Saanmo a masuratan manen daytoy a ladawan.",
+       "filepage-nofile-link": "Awan ti agnagan ti kastoy a papeles, ngem mabalinmo ti [$1 agikarga].",
+       "uploadnewversion-linktext": "Agikarga ti baro a bersion iti daytoy a papeles",
+       "shared-repo-from": "manipud ti $1",
+       "shared-repo": "ti pagbingbingayan a repositorio",
+       "upload-disallowed-here": "Saanmo a masuratan manen daytoy a papeles.",
        "filerevert": "Isubli ti $1",
        "filerevert-legend": "Isubli ti papeles",
-       "filerevert-intro": "Mangrugrugika nga agipasubli ti papeles '''[[Media:$1|$1]]''' iti [$4 bersion ti oras ket petsa nga $3, $2].",
+       "filerevert-intro": "Mangrugrugika nga agipasubli ti papeles ti <strong>[[Media:$1|$1]]</strong> iti [$4 bersion manipud idi $3, $2].",
        "filerevert-comment": "Rason:",
-       "filerevert-defaultcomment": "Naisubli ti bersion manipud idi $2, $1",
+       "filerevert-defaultcomment": "Naisubli iti bersion manipud idi $2, $1",
        "filerevert-submit": "Isubli",
-       "filerevert-success": "Ti '''[[Media:$1|$1]]''' ket naipasubli idiay [$4 bersion ti oras ken petsa $3, $2].",
-       "filerevert-badversion": "Awan ti dati a lokal a bersion daytoy a papeles a naited ti dayta nga oras ken petsa.",
+       "filerevert-success": "Ti <strong>[[Media:$1|$1]]</strong> ket naipasubli iti [$4 bersion manipud idi $3, $2].",
+       "filerevert-badversion": "Awan ti dati a lokal a bersion iti daytoy a papeles a naited ti dayta nga oras ken petsa.",
        "filedelete": "Ikkaten ti $1",
        "filedelete-legend": "Ikkaten ti papeles",
-       "filedelete-intro": "Mangrugrugika nga agikkat ti '''[[Media:$1|$1]]''' ken mairaman amin a pakasaritaanna.",
-       "filedelete-intro-old": "Ikikkatem ti bersion iti '''[[Media:$1|$1]]''' manipud idi [$4 $3, $2].",
+       "filedelete-intro": "Mangrugrugika nga agikkat ti <strong>[[Media:$1|$1]]</strong> ken mairaman amin a pakasaritaanna.",
+       "filedelete-intro-old": "Ikikkatem ti bersion iti <strong>[[Media:$1|$1]]</strong> manipud idi [$4 $3, $2].",
        "filedelete-comment": "Rason:",
        "filedelete-submit": "Ikkaten",
-       "filedelete-success": "Naikkaten ti '''$1'''.",
-       "filedelete-success-old": "Ti bersion iti '''[[Media:$1|$1]]''' manipud idi $3, $2 ket naikkaten.",
-       "filedelete-nofile": "awan ti '''$1''' .",
-       "filedelete-nofile-old": "Awan ti naidulin a bersion ti '''$1''' nga addaan ti naited a kakitkitana.",
+       "filedelete-success": "Naikkaten ti <strong>$1</strong>.",
+       "filedelete-success-old": "Ti bersion iti <strong>[[Media:$1|$1]]</strong> manipud idi $3, $2 ket naikkaten.",
+       "filedelete-nofile": "awan ti <strong>$1</strong> .",
+       "filedelete-nofile-old": "Awan ti naidulin a bersion ti <strong>$1</strong> nga addaan kadagiti naited a gupit.",
        "filedelete-otherreason": "Sabali/maipatinayon a rason:",
        "filedelete-reason-otherlist": "Sabali a rason",
-       "filedelete-reason-dropdown": "*Kadawyan a rasrason ti pannakaikkat\n** Panagsalungasing iti karbengan ti panagkopia\n** Nadoble a papeles",
+       "filedelete-reason-dropdown": "*Kadawyan a rasrason ti pannakaikkat\n** Panagsalungasing iti karbengan ti kopia\n** Duplikado a papeles",
        "filedelete-edit-reasonlist": "Urnosen dagiti rason ti panagikkat",
        "filedelete-maintenance": "Ti panagikkat ken panagisubli kadagiti papaeles ket nabaldado iti las-ud ti panagtartaripato.",
-       "filedelete-maintenance-title": "Saan a maikkat daytoy a papeles",
+       "filedelete-maintenance-title": "Saan a maikkat ti papeles",
        "mimesearch": "Pagbiruk ti MIME",
-       "mimesearch-summary": "Daytoy a panid ket pakabaelanna ti panagsagat ti papeles iti MIME a kitada.\nIkabil: kita ti nagyan/subtipo, a kas ti <code>image/jpeg</code>.",
+       "mimesearch-summary": "Daytoy a panid ket pakabaelanna ti panagsagat kadagiti papeles iti MIME a kitada.\nIkabil: kita ti linaon/subtipo wenno kita ti linaon/*, a kas ti <code>image/jpeg</code>.",
        "mimetype": "Kita ti MIME:",
        "download": "ikarga",
        "unwatchedpages": "Di mabambantayan a pampanid",
        "listduplicatedfiles-summary": "Daytoy ket listaan dagiti papeles a ti kaudian unay a bersion ti papeles ket duplikado ti kaudian unay a bersion iti sabali a papeles. Dagiti laeng lokal a papeles ti maikeddeng.",
        "listduplicatedfiles-entry": "Ti [[:File:$1|$1]] ket addaan [[$3|{{PLURAL:$2|iti duplikado|kadagiti $2 a duplikado}}]].",
        "unusedtemplates": "Dagiti saan a nausar a plantilia",
-       "unusedtemplatestext": "Daytoy a panid ket ilistana dagiti panid idiay {{ns:template}} a nagan ti espasio a saan a nairaman iti sabali a panid.\nLaglagipem ti agkita kadagiti sabsabali a silpo ti plantilia sakbay nga ikkatem ida.",
-       "unusedtemplateswlh": "dagiti sabali a silpo",
+       "unusedtemplatestext": "Daytoy a panid ket ilistana dagiti panid iti nagan ti espasio ti {{ns:template}} a saan a nairaman iti sabali a panid.\nLaglagipem a kitaen dagiti sabali a silpo dagiti plantilia sakbay nga ikkaten ida.",
+       "unusedtemplateswlh": "sabali a silsilpo",
        "randompage": "Pugto a panid",
        "randompage-nopages": "Awan ti pampanid iti sumaganad a {{PLURAL:$2|nagan ti espasio|nagnagan ti espasio}}: $1.",
        "randomincategory": "Pugto a panid iti kategoria",
        "randomincategory-invalidcategory": "Ti \"$1\" ket saan nga umisu a nagan ti kategoria.",
-       "randomincategory-nopages": "Awan ti pampanid iti [[:Category:$1]].",
+       "randomincategory-nopages": "Awan ti pampanid iti kategoria ti [[:Category:$1]].",
        "randomincategory-selectcategory": "Agala ti pugto a panid manipud ti kategoria: $1 $2.",
        "randomincategory-selectcategory-submit": "Inkan",
        "randomredirect": "Pugto a baw-ing",
        "randomredirect-nopages": "Awan dagiti baw-ing iti daytoy a nagan ti espasio ti \"$1\".",
        "statistics": "Estadistika",
        "statistics-header-pages": "Estadistika ti panid",
-       "statistics-header-edits": "Estadistika ti inurnos",
+       "statistics-header-edits": "Estadistika ti panag-urnos",
        "statistics-header-views": "Estadistika ti panagkita",
        "statistics-header-users": "Estadistika ti agar-aramat",
-       "statistics-header-hooks": "Estadistika a sabsabali",
+       "statistics-header-hooks": "Sabali nga estadistika",
        "statistics-articles": "Dagiti naglaon a panid",
        "statistics-pages": "Pampanid",
-       "statistics-pages-desc": "Dagiti amin a panid ti wiki, a mairaman dagiti tungtungan a panid, dagiti baw-ing, ken dadduma pay",
-       "statistics-files": "Ti naipapan a papeles",
+       "statistics-pages-desc": "Amin a pampanid iti wiki, a mairaman dagiti tungtungan a panid, dagiti baw-ing, kdpy.",
+       "statistics-files": "Dagiti naikarga a papeles",
        "statistics-edits": "Dagiti naurnos a panid manipud idi nairugi ti {{SITENAME}}",
-       "statistics-edits-average": "Pagtengngaan nga urnos ti tunggal maysa a panid",
+       "statistics-edits-average": "Dagiti pagtengngaan nga inurnos iti tunggal maysa a panid",
        "statistics-views-total": "Dagiti dagup ti panagkita",
-       "statistics-views-total-desc": "Saan a naikabil ti panagkita dagiti awan a panid ken dagiti espesial a panid",
-       "statistics-views-peredit": "Panagkita ti tunggal maysa nga urnos",
+       "statistics-views-total-desc": "Dagiti panagkita ti awan a pampanid ken saan a mairaman dagiti espesial a panid",
+       "statistics-views-peredit": "Panagkita iti tunggal maysa a panag-urnos",
        "statistics-users": "Dagiti nakarehistro nga [[Special:ListUsers|agar-aramat]]",
-       "statistics-users-active": "Dagiti nasiglat nga agar-aramat",
-       "statistics-users-active-desc": "Dagiti agar-aramat a nagtungpal ti aramid ti napalabas nga {{PLURAL:$1|aldaw|$1 nga al-aldaw}}",
+       "statistics-users-active": "Dagiti aktibo nga agar-aramat",
+       "statistics-users-active-desc": "Dagiti agar-aramat a nagtungpal ti aramid iti napalabas nga {{PLURAL:$1|aldaw|$1 nga al-aldaw}}",
        "statistics-mostpopular": "Kaaduan a nabuya a pampanid",
-       "pageswithprop": "Pampanid nga adda maysa a tagikua ti panid",
-       "pageswithprop-legend": "Pampanid nga adda maysa a tagikua ti panid",
+       "pageswithprop": "Pampanid nga adda tagikua ti panid",
+       "pageswithprop-legend": "Pampanid nga adda tagikua ti panid",
        "pageswithprop-text": "Daytoy a panid ket ilistana ti pampanid nga agus-usar ti naisangayan a tagikua ti panid.",
        "pageswithprop-prop": "Nagan ti tagikua:",
        "pageswithprop-submit": "Inkan",
-       "pageswithprop-prophidden-long": "atiddog a testo ti tagikua a nailemmeng ($1)",
+       "pageswithprop-prophidden-long": "atiddog a testo ti pateg ti tagikua a nailemmeng ($1)",
        "pageswithprop-prophidden-binary": "binario a pateg ti tagikua a nailemmeng ($1)",
        "doubleredirects": "Dagiti namindua a naibaw-ing",
-       "doubleredirectstext": "Daytoy a panid ket ilistana dagiti panid nga agbaw-ing kadagiti sabsabali a baw-ing a pampanid.\nIti tunggal maysa nga aray ket adda nagyanna kadagiti silpo iti umuna ken maikadua a baw-ing, ken iti puntaan iti maikadua a baw-ing, nga isu ti \"pudno\" a puntaan ti panid, nga ti umuna a baw-ing ket isu ti ipatudona.\n<del>Nakurosan</del> dagita naikabil ket napadtuan.",
-       "double-redirect-fixed-move": "Naiyalisen ti [[$1]].\nAutomatiko idi a napabaro ken naibaw-ing tattan idiay [[$2]].",
-       "double-redirect-fixed-maintenance": "Automatiko a simsimpaen ti doble a baw-ing manipud ti [[$1]] idiay [[$2]] iti panagtaripato nga obra.",
+       "doubleredirectstext": "Daytoy a panid ket ilistana dagiti panid nga agbaw-ing kadagiti sabali a baw-ing a pampanid.\nIti tunggal maysa nga aray ket aglaon kadagiti silpo iti umuna ken maikadua a baw-ing, ken ti pay puntaan ti maikadua a baw-ing, nga isu ti \"pudno\" a puntaan ti panid, nga ti umuna a baw-ing ket isu koma ti pakaituduanna.\nNasolbaren dagiti <del>nakurosan</del> a naikabil.",
+       "double-redirect-fixed-move": "Naiyalisen ti [[$1]].\nAutomatiko idi a napabaro ken naibaw-ing tattan iti [[$2]].",
+       "double-redirect-fixed-maintenance": "Automatiko nga agsimsimpa ti doble a baw-ing manipud ti [[$1]] iti [[$2]] iti panagtaripato nga obra.",
        "double-redirect-fixer": "Panagsimpa ti baw-ing",
        "brokenredirects": "Dagiti naputed a baw-ing",
-       "brokenredirectstext": "Dagitoy sumaganad a baw-ing ket nakasilpo kadagiti awan a panid:",
+       "brokenredirectstext": "Dagiti sumaganad a baw-ing ket nakasilpo kadagiti awan a panid:",
        "brokenredirects-edit": "urnosen",
        "brokenredirects-delete": "ikkaten",
-       "withoutinterwiki": "Dagiti panid nga awan ti silpona ti pagsasao",
-       "withoutinterwiki-summary": "Dagitoy a pampanid ket saan a nakasilpo ti sabali a bersion ti pagsasao.",
+       "withoutinterwiki": "Pampanid nga awan kadagiti silpo ti pagsasao",
+       "withoutinterwiki-summary": "Dagiti sumaganad a pampanid ket saan a nakasilpo kadagiti sabali a bersion ti pagsasao.",
        "withoutinterwiki-legend": "Pagpasaruno",
        "withoutinterwiki-submit": "Ipakita",
-       "fewestrevisions": "Dagiti panid nga adda kadagiti kabassitan a panangbalbaliw",
+       "fewestrevisions": "Dagiti panid nga adda kadagiti kabassitan a rebision",
        "nbytes": "$1 {{PLURAL:$1|a byte|dagiti byte}}",
        "ncategories": "$1 {{PLURAL:$1|a kategoria|a katkategoria}}",
        "ninterwikis": "$1 {{PLURAL:$1|nga interwiki|dagiti interwiki}}",
        "nlinks": "$1 {{PLURAL:$1|a silpo|kadagiti silpo}}",
        "nmembers": "$1 {{PLURAL:$1|a kameng|kamkameng}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|kameng|kamkameng}}",
-       "nrevisions": "$1 {{PLURAL:$1|a panagbalbaliw|kadagiti panagbalbaliw}}",
+       "nrevisions": "$1 {{PLURAL:$1|a rebison|kadagiti rebision}}",
        "nviews": "$1 {{PLURAL:$1|a panangkita|kadagiti panangkita}}",
-       "nimagelinks": "Inusar idiay $1 {{PLURAL:$1|a panid|a pampanid}}",
-       "ntransclusions": "inusar idiay $1 {{PLURAL:$1|a panid|a pampanid}}",
-       "specialpage-empty": "Awan dagiti nagbanaganna daytoy a padamag.",
+       "nimagelinks": "Inusar iti $1 {{PLURAL:$1|a panid|a pampanid}}",
+       "ntransclusions": "inusar iti $1 {{PLURAL:$1|a panid|a pampanid}}",
+       "specialpage-empty": "Awan dagiti nagbanagan daytoy a reporta.",
        "lonelypages": "Dagiti naulila a panid",
-       "lonelypagestext": "Dagiti sumaganad a panid ket saan a nakasilpo idiay wenno naipakita kadagiti sabali a panid idiay {{SITENAME}}.",
+       "lonelypagestext": "Dagiti sumaganad a panid ket saan a nakasilpo wenno nailak-am kadagiti sabali a panid iti {{SITENAME}}.",
        "uncategorizedpages": "Dagiti saan a nakategoria a panid",
        "uncategorizedcategories": "Dagiti saan a nakategoria a kategoria",
        "uncategorizedimages": "Dagiti saan a nakategoria a papeles",
        "popularpages": "Dagiti nadayeg a panid",
        "wantedcategories": "Dagiti makiddaw a kategoria",
        "wantedpages": "Dagiti makiddaw a panid",
-       "wantedpages-badtitle": "Saan nga umisu a titulo idiay naikabil a pagbanagan: $1",
+       "wantedpages-badtitle": "Imbalido a titulo iti agasmang ti nagbanagan: $1",
        "wantedfiles": "Dagiti makiddaw a papeles",
-       "wantedfiletext-cat": "Dagiti sumaganad a papeles ket maus-usar ngem awanda met. Dagiti papeles a naggapu kadagiti ganganaet a repositorio ket mailista uray pay no addaan da. No adda dagiti kasla adda dagitoy ket <del>maikkat</del> to. A maipanayon pay, dagiti pampanid nga agisengngat kadagiti papeles nga awan ket nailista idiay [[:$1]].",
-       "wantedfiletext-nocat": "Dagiti sumaganad a papeles ket maus-usar ngem awanda met. Dagiti papeles a naggapu kadagiti ganganaet a repositorio ket mailista uray pay no addaan da. No adda dagiti kasla adda dagitoy ket <del>maikkat</del> to.",
+       "wantedfiletext-cat": "Dagiti sumaganad a papeles ket maus-usar ngem awanda met. Dagiti papeles manipud kadagiti ganganaet a repositorio ket mabalin a mailista urayno adda. Ti kasta man a saan nga umno a positibo ket <del>maikkatto</del>. Iti maipatinayon, dagiti panid nga agisengngat kadagiti papeles nga awan ket nailista iti [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Dagiti sumaganad a papeles ket naus-usar ngem awanda met. Iti maipatinayon, dagiti panid a mangipenpen kadagiti papeles ket nailista iti [[:$1]].",
+       "wantedfiletext-nocat": "Dagiti sumaganad a papeles ket maus-usar ngem awanda met. Dagiti papeles manipud ti ganganaet a repositorio ket mabalin a mailista urayno adda. No adda dagiti kasta a saan nga umno a positibo ket <del>maikkatto</del>.",
+       "wantedfiletext-nocat-noforeign": "Dagiti sumaganad a papeles ket naus-usar ngem awanda met.",
        "wantedtemplates": "Dagiti makiddaw a plantilia",
        "mostlinked": "Dagiti panid a kaaduan iti nakasilpo",
        "mostlinkedcategories": "Dagiti kategoria a kaaduan iti nakasilpo",
-       "mostlinkedtemplates": "Dagiti plantilia a kaaduan iti nakasilpo",
+       "mostlinkedtemplates": "Kaaduan a nailak-am a pampanid",
        "mostcategories": "Dagiti panid a kaaduan kadagiti kategoria",
        "mostimages": "Dagiti papeles a kaaduan iti nakasilpo",
        "mostinterwikis": "Dagiti panid a kaaduan kadagiti interwiki",
-       "mostrevisions": "Dagiti artikulo a kaaduan ti pannakabalbaliwna",
+       "mostrevisions": "Dagiti artikulo a kaaduan kadagiti rebision",
        "prefixindex": "Dagiti amin a panid nga addaan iti pasaruno",
-       "prefixindex-namespace": "Amin a panid nga addaan ti pasaruno ($1 a nagan ti espasio)",
+       "prefixindex-namespace": "Amin a pampanid nga addaan iti pasaruno (nagan ti espasio ti $1)",
        "prefixindex-strip": "Ikkaten ti pasaruno iti listaan",
        "shortpages": "Dagiti ababa a panid",
        "longpages": "Dagiti atiddog a panid",
        "deadendpages": "Dagiti ngudo a panid",
-       "deadendpagestext": "Dagitoy a pampanid ket saan a nakasilpo ti sabali a pampanid ditoy {{SITENAME}} .",
+       "deadendpagestext": "Dagiti sumaganad a panid ket saan a nakasilpo kadagiti sabali a panid iti {{SITENAME}}.",
        "protectedpages": "Dagiti nasalakniban a panid",
-       "protectedpages-indef": "Inggat ingana a salakniban laeng",
+       "protectedpages-indef": "Dagiti inggat ingana a salaknib laeng",
        "protectedpages-summary": "Daytoy a panid ket ilistana dagiti panid nga agdama a nasalakniban. Para iti listaan dagiti titulo a nasalakniban manipud ti pannakapartuat, kitaen ti [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
        "protectedpages-cascade": "Dagiti sariap a salaknib laeng",
        "protectedpages-noredirect": "Ilemmeng dagiti baw-ing",
        "protectedpages-unknown-performer": "Di ammo nga agar-aramat",
        "protectedtitles": "Dagiti nasalakniban a titulo",
        "protectedtitles-summary": "Daytoy a panid ket ilistana dagiti titulo nga agdama a nasalakniban manipud ti pannakapartuat. Para iti listaan dagiti adda a panid a nasalakniban, kitaen ti  [[{{#special:ProtectedPages}}|{{int:protectedpages}}]]..",
-       "protectedtitlesempty": "Awan dagiti titulo nga agdama a nasalakniban iti dagitoy a parametro.",
-       "listusers": "Listaan dagiti agar-aramat",
-       "listusers-editsonly": "Ipakita laeng dagiti agar-aramat nga adda inurnosda",
-       "listusers-creationsort": "Ilasin no ania a petsa ti pannakaaramid",
-       "listusers-desc": "Paglalasinen iti agpababa nga urnos",
+       "protectedtitlesempty": "Awan dagiti titulo nga agdama a nasalakniban kadagitoy a parametro.",
+       "listusers": "Listaan ti agar-aramat",
+       "listusers-editsonly": "Ipakita laeng dagiti agar-aramat nga addaan kadagiti inurnos",
+       "listusers-creationsort": "Ilasin babaen ti petsa a pannakapartuat",
+       "listusers-desc": "Ilasin iti agpababa nga urnos",
        "usereditcount": "$1 {{PLURAL:$1|nga inurnos|kadagiti inurnos}}",
-       "usercreated": "{{GENDER:$3|Inaramid}} idi $1 idi $2",
+       "usercreated": "{{GENDER:$3|Pinartuat}} idi $1, $2",
        "newpages": "Baro a pampanid",
        "newpages-username": "Nagan ti agar-aramat:",
        "ancientpages": "Dagiti kadaanan a panid",
        "move": "Iyalis",
        "movethispage": "Iyalis daytoy a panid",
-       "unusedimagestext": "Adda dagiti sumaganad a papeles ngem saanda a naikabil iti ania man a panid.\nPangngaasi a laglagipen a dagiti sabali a sapot ti pagsaadan  ket makasilpoda ti papeles iti dagus a URL, ken isu pay a nailista da ditoy urayno saanda a naus-usar iti agdama.",
-       "unusedcategoriestext": "Adda dagiti sumaganad a kategoria a panid, ngem awan ti sabali a panid wenno kategoria ti agus-usar kaniada.",
-       "notargettitle": "Awan ti napuntaan",
-       "notargettext": "Saanmo a nainagan ti puntaan a panid wenno agar-aramat ti mangtungpal daytoy nga opisio.",
+       "unusedimagestext": "Adda dagiti sumaganad a papeles ngem saanda a naikabil iti aniaman a panid.\nPangngaasi a laglagipen a dagiti sabali a sitio ti web ket mabalin a nakasilpoda iti papeles iti dagus a URL, ken mabalin pay a nailista ditoy urayno saanda nga aktibo a maus-usar.",
+       "unusedcategoriestext": "Ti sumaganad a kategoria ti pampanid ket adda,urayno awan ti sabali a panid wenno kategoria ti agus-usar kaniada.",
+       "notargettitle": "Awan ti puntaan",
+       "notargettext": "Saanmo a nainagan ti puntaan a panid wenno agar-aramat ti mangtungpal iti daytoy nga annong.",
        "nopagetitle": "Awan ti kasta a puntaan a panid",
        "nopagetext": "Awan ti puntaan a panid a nainaganam.",
        "pager-newer-n": "{{PLURAL:$1|nabarbaro 1|dagiti nabarbaro $1}}",
        "pager-older-n": "{{PLURAL:$1|nadadaan 1|nadadaan $1}}",
        "suppress": "Pakapansin",
-       "querypage-disabled": "Daytoy a nangruna a panid ket nabaldado gapu kadagiti rason a panagtungpal.",
+       "querypage-disabled": "Daytoy nga espesial a panid ket nabaldado gapu kadagiti rason ti kasayaat ti panagpataray.",
        "booksources": "Dagiti taudan ti libro",
-       "booksources-search-legend": "Agsapul para kadagiti taudan ti libro",
+       "booksources-search-legend": "Agbiruk para kadagiti taudan ti libro",
        "booksources-go": "Inkan",
-       "booksources-text": "Dita baba ket listaan dagiti silpo ti sabsali a lugar nga aglaklako ti liblibro, ken baka adda pay adu a pakaammoda kadagiti liblibro a kitkitaem:",
-       "booksources-invalid-isbn": "Ti naited nga ISBN ket kasla saan nga umisu; kitaen dagiti biddut ti panagtulad kadagiti naggappuanna a taudan.",
-       "specialloguserlabel": "Ti nagtungpal:",
+       "booksources-text": "Dita baba ket listaan dagiti silpo ti sabali a sitio nga aglaklako ti baro ken saan a nausar a liblibro, ken mabalin nga addaan pay iti adu a pakaammo a maipanggep kadagiti libro a birbirukem:",
+       "booksources-invalid-isbn": "Ti naited nga ISBN ket kasla saan nga umisu; kitaen dagiti biddut ti panagtulad manipud ti kasisigud a taudan.",
+       "specialloguserlabel": "Perpormer:",
        "speciallogtitlelabel": "Puntaan (titulo wenno agar-aramat):",
        "log": "Dagiti listaan",
        "all-logs-page": "Amin a listaan a publiko",
-       "alllogstext": "Naipagtipon a pinagpakita kadagiti amin nga adda a listaan ti {{SITENAME}}.\nMapabassitmo ti pinagpakita no piliam ti kita ti listaan, ti nagan ti agar-aramat (sensitibo ti kadakkel ti letra), wenno ti naapektaran a panid (ket sensitibo met ti kadakkel ti letra).",
-       "logempty": "Awan ti agpada a bagay dita listaan.",
-       "log-title-wildcard": "Agsapul kadagiti titulo nga agrugi iti daytoy a testo",
-       "showhideselectedlogentries": "Ipakita/ilemmeng dagiti napili a naikabil ti listaan",
+       "alllogstext": "Naipagtipon a panagiparang kadagiti amin a magun-od a listaan iti {{SITENAME}}.\nMapabassitmo ti panagkita babaen ti panagpili ti kita ti listaan, ti nagan ti agar-aramat (sensitibo ti kadakkel ti letra), wenno ti naapektaran a panid (ket sensitibo pay ti kadakkel ti letra).",
+       "logempty": "Awan dagiti maipada a banag iti listaan.",
+       "log-title-wildcard": "Agbiruk kadagiti titulo a mangrugi iti daytoy a testo",
+       "showhideselectedlogentries": "Baliwan ti panagkita kadagiti napili a naikabil iti listaan",
        "allpages": "Amin a pampanid",
        "nextpage": "sumaruno a panid ($1)",
        "prevpage": "Napalabas a panid ($1)",
        "allpagesfrom": "Ipakita dagiti panid a mangrugi iti:",
        "allpagesto": "Ipakita dagiti panid nga agpatingga iti:",
        "allarticles": "Amin a pampanid",
-       "allinnamespace": "Amin a pampanid ($1 a nagan ti espasio)",
+       "allinnamespace": "Amin a pampanid (nagan ti espasio ti $1)",
        "allpagessubmit": "Inkan",
        "allpagesprefix": "Iparang dagiti pampanid nga adda pasarunona:",
-       "allpagesbadtitle": "Ti naited a titulo ti panid ket imbalido wenno adda idi ti sabali a pagsasao wenno interwiki a pasarunona.",
-       "allpages-bad-ns": "Awan ti {{SITENAME}} iti nagan ti espasio a \"$1\".",
+       "allpagesbadtitle": "Ti naited a titulo ti panid ket imbalido wenno adda idi ti sabali a pagsasao wenno interwiki a pasarunona.\nDaytoy ket mabalin nga aglaon iti maysa wenno ad-adu a karkarakter a saan a mausar kadagiti titulo.",
+       "allpages-bad-ns": "Ti {{SITENAME}} ket awan iti nagan ti espasio iti \"$1\".",
        "allpages-hide-redirects": "Ilemmeng dagiti baw-ing",
-       "cachedspecial-viewing-cached-ttl": "Kitkitaem ti naidulin a bersion iti daytoy a panid, nga addan ti kadaanan a $1.",
-       "cachedspecial-viewing-cached-ts": "Kitkitaem ti maysa a naidulin a bersion iti daytoy a panid, a baka daytoy ket saan a kompleto nga agpayso.",
+       "cachedspecial-viewing-cached-ttl": "Kitkitaem ti naidulin a bersion iti daytoy a panid, a mabalin nga agduog iti $1.",
+       "cachedspecial-viewing-cached-ts": "Kitkitaem ti maysa a naidulin a bersion iti daytoy a panid, a mabalin daytoy a saan a kompleto nga agpayso.",
        "cachedspecial-refresh-now": "Kitaen ti kinaudian.",
        "categories": "Katkategoria",
        "categoriespagetext": "Ti sumaganad a {{PLURAL:$1|kategoria ket aglaon|katkategoria ket aglaon}} kadagiti panid wenno midia.\n[[Special:UnusedCategories|Dagiti saan a nausar a kategoria]] ket saan a maiparang ditoy.\nKitaen met [[Special:WantedCategories|dagiti makiddaw a kategoria]].",
        "categoriesfrom": "Ipakita dagiti kategoria a mangrugi iti:",
-       "special-categories-sort-count": "paglalasinen babaen ti bilang",
-       "special-categories-sort-abc": "paglalasinen nga alpabetiko",
-       "deletedcontributions": "Dagiti naikkat nga inararamid ti agar-aramat",
-       "deletedcontributions-title": "Dagiti naikkat nga inararamid ti agar-aramat",
-       "sp-deletedcontributions-contribs": "naar-aramid",
+       "special-categories-sort-count": "ilasin babaen ti bilang",
+       "special-categories-sort-abc": "ilasin nga alpabetiko",
+       "deletedcontributions": "Dagiti naikkat a kontribusion ti agar-aramat",
+       "deletedcontributions-title": "Dagiti naikkat a kontribusion ti agar-aramat",
+       "sp-deletedcontributions-contribs": "dagiti kontribusion",
        "linksearch": "Dagiti panagbiruk ti ruar a silpo",
        "linksearch-pat": "Tabas ti panagbiruk:",
        "linksearch-ns": "Nagan ti espasio:",
        "linksearch-ok": "Biruken",
-       "linksearch-text": "Ti naataap a tarheta a kas ti \"*.wikipedia.org\" ket mabalin nga usaren.\nMasapul ti kangatuan a pagturayan, a kaspagarigan \"*.org\".<br />\n{{PLURAL:$2|Ti protokol|Dagiti protokol}} a nasuportaran: <code>$1</code> (naipakasigud ti http:// no awan ti protokol a nainaganan).",
-       "linksearch-line": "Ti $1 ket nakasilpo idiay $2",
-       "linksearch-error": "Ti naatap a tarheta ket agparang laeng iti panagrugi ti nagan ti agsangaili.",
+       "linksearch-text": "Ti naataap a tarheta a kas ti \"*.wikipedia.org\" ket mabalin nga usaren.\nMasapul ti saan a basbassit ngem kangatuan a dominio, kas pagarigan \"*.org\".<br />\n{{PLURAL:$2|Ti protokol|Dagiti protokol}} a nasuportaran: <code>$1</code> (kasisigud iti http:// no awan ti nainaganan a protokol).",
+       "linksearch-line": "Ti $1 ket naisilpo manipud ti $2",
+       "linksearch-error": "Ti naatap a tarheta ket mabalin nga agparang laeng iti rugi ti nagan ti agsangaili.",
        "listusersfrom": "Iparang dagiti agar-aramat a mangrugi iti:",
        "listusers-submit": "Ipakita",
        "listusers-noresult": "Awan ti nasarakan nga agar-aramat.",
        "listusers-blocked": "(naserraan)",
-       "activeusers": "Listaan dagiti nasiglat nga agar-aramat",
+       "activeusers": "Listaan dagiti aktibo nga agar-aramat",
        "activeusers-intro": "Daytoy ti listaan dagiti agar-aramat nga adda inararamidda kadagiti napalabas a $1 {{PLURAL:$1|nga aldaw|nga al-aldaw}}.",
-       "activeusers-count": "$1 {{PLURAL:$1|a tignay|tigtignay}} idi kalpasan ti {{PLURAL:$3|nga aldaw|$3 nga al-aldaw}}",
+       "activeusers-count": "$1 {{PLURAL:$1|a tignay|tigtignay}} iti napalabas {{PLURAL:$3|nga aldaw|$3 nga al-aldaw}}",
        "activeusers-from": "Iparang dagiti agar-aramat a mangrugi iti:",
        "activeusers-hidebots": "Ilemmeng dagiti bot",
        "activeusers-hidesysops": "Ilemmeng dagiti administrador",
        "activeusers-noresult": "Awan ti nasarakan nga agar-aramat.",
        "listgrouprights": "Dagiti karbengan ti grupo ti agar-aramat",
-       "listgrouprights-summary": "Dagiti sumaganad a listaan ti grupo ti agar-aramat a naipalawag iti daytoy a wiki, a nairaman dagiti karbengan ti panagserrekda.\nAdda pay mabalin nga [[{{MediaWiki:Listgrouprights-helppage}}|adu a pakaammo]] a maipapan kadagiti bukbukod a karbengan.",
-       "listgrouprights-key": "Sarita: \n* <span class=\"listgrouprights-granted\">Naited a karbengan</span> \n* <span class=\"listgrouprights-revoked\">Naukas a karbengan</span>",
+       "listgrouprights-summary": "Dagiti sumaganad a listaan ti grupo ti agar-aramat a naipalawag iti daytoy a wiki, a nairaman dagiti mainaig a karbengan ti panagserrekda.\nAdda pay mabalin nga [[{{MediaWiki:Listgrouprights-helppage}}|adu a pakaammo]] a maipanggep kadagiti kabukbuodan a karbengan.",
+       "listgrouprights-key": "Leyenda: \n* <span class=\"listgrouprights-granted\">Naited a karbengan</span> \n* <span class=\"listgrouprights-revoked\">Naukas a karbengan</span>",
        "listgrouprights-group": "Grupo",
        "listgrouprights-rights": "Dagiti karbengan",
        "listgrouprights-helppage": "Help:Dagiti karbengan ti grupo",
        "listgrouprights-members": "(listaan ti kamkameng)",
-       "listgrouprights-addgroup": "Agnayon ti {{PLURAL:$2|a grupo|kadagiti grupo}} : $1",
-       "listgrouprights-removegroup": "Aggikkat ti {{PLURAL:$2|a grupo|kadagiti grupo}}: $1",
+       "listgrouprights-addgroup": "Agnayon {{PLURAL:$2|iti grupo|kadagiti grupo}} : $1",
+       "listgrouprights-removegroup": "Aggikkat {{PLURAL:$2|iti grupo|kadagiti grupo}}: $1",
        "listgrouprights-addgroup-all": "Inayon amin dagiti grupo",
        "listgrouprights-removegroup-all": "Ikkatem amin dagiti grupo",
-       "listgrouprights-addgroup-self": "Agnayon ti {{PLURAL:$2|a grupo|kadagiti grupo}} iti bukod a pakabilangan: $1",
-       "listgrouprights-removegroup-self": "Agikkat ti {{PLURAL:$2|a grupo|kadagiti grupo}} manipud ti bukod a pakabilangan: $1",
+       "listgrouprights-addgroup-self": "Agnayon {{PLURAL:$2|iti grupo|kadagiti grupo}} iti bukod a pakabilangan: $1",
+       "listgrouprights-removegroup-self": "Agikkat {{PLURAL:$2|iti grupo|kadagiti grupo}} manipud ti bukod a pakabilangan: $1",
        "listgrouprights-addgroup-self-all": "Inayon amin dagiti grupo iti bukod a pakabilangan",
        "listgrouprights-removegroup-self-all": "Ikkatem amin dagiti grupo manipud ti bukod a pakabilangan",
        "listgrouprights-namespaceprotection-header": "Dagiti panangigawid ti nagan ti espasio",
        "post-expand-template-argument-category-desc": "Kalpasan ti panagpadakkel ti argumento ti plantilia (dagiti addaan iti tallo a pangrikep, kasla ti <code>{{{Foo}}}</code>), ti panid ket dakdakkel ngem ti <code>$wgMaxArticleSize</code>.",
        "expensive-parserfunction-category-desc": "Adu unay dagiti nangina nga annong ti parser (kasla ti <code>#ifexist</code>) a nairaman iti panid. Kitaen ti[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit].",
        "broken-file-category-desc": "Kategoria a nainayon no ti panid ket aglaon ti nadadael a silpo ti papeles (ti silpo a panangisengngat ti papeles no awan ti papeles).",
-       "hidden-category-category-desc": "Daytoy ket kategoria nga addaan iti <code><nowiki>__HIDDENCAT__</nowiki></code> , a mangpawil daytoy nga agparang kadagiti silpo ti kahon ti kategoria kadagiti panid, bbabaen ti kasisigud.",
+       "hidden-category-category-desc": "Daytoy ket kategoria nga addaan iti <code><nowiki>__HIDDENCAT__</nowiki></code> , a mangpawil daytoy nga agparang kadagiti silpo ti kahon ti kategoria kadagiti panid, babaen ti kasisigud.",
        "trackingcategories-nodesc": "Awan ti magun-od a deskripsion.",
        "trackingcategories-disabled": "Nabaldado ti kategoria",
        "mailnologin": "Awan ti pagipatulodan a pagtaengan",
-       "mailnologintext": "Masapul a [[Special:UserLogin|nakastrekka]] ken adda umisu nga esurat a pagtaengan idiay [[Special:Preferences|kaykayatmo]] ti agipatulod ti esurat kadagiti sabsabali nga agar-aramat.",
+       "mailnologintext": "Masapul a [[Special:UserLogin|nakastrekka]] ken adda umisu nga esurat a pagtaengan idiay [[Special:Preferences|kaykayatam]] tapno makaipatulod iti esurat kadagiti sabali nga agar-aramat.",
        "emailuser": "Esuratan daytoy nga agar-aramat",
        "emailuser-title-target": "Esuratam daytoy nga {{GENDER:$1|agar-aramat}}",
        "emailuser-title-notarget": "Esuratan ti agar-aramat",
        "emailpage": "Esuratan ti agar-aramat",
-       "emailpagetext": "Mabalinmo nga usaren ti kinabuklan dita baba nga agipatulod ti e-surat a mensahe ti daytoy nga {{GENDER:$1|agar-aramat}}.\nTi e-surat nga inkabilmo idiay  [[Special:Preferences|kakaykayatam]] ket agparang a kas \"Naggapu\" a pagtaengan ti e-surat, tapno ti nagipatulodam ket makasungbat kenka.",
+       "emailpagetext": "Mabalinmo nga usaren ti porma dita baba tapno makaipatulod ti esurat a mensahe iti daytoy nga {{GENDER:$1|agar-aramat}}.\nTi esurat nga inkabilmo iti [[Special:Preferences|kakaykayatam]] ket agparang a kas \"Naggapu\" a pagtaengan ti esurat, tapno ti nagipatulodam ket makasungbat kenka.",
        "defemailsubject": "Esurat ti {{SITENAME}} a naggapo kenni \"$1\"",
        "usermaildisabled": "Saanmo a mabalin ti agipatulod ti esurat",
-       "usermaildisabledtext": "Saanmo a mabalin ti agipatulod ti esurat kadagiti sabali nga agar-aramat ditoy a wiki",
+       "usermaildisabledtext": "Saanmo a mabalin ti agipatulod ti esurat kadagiti sabali nga agar-aramat iti daytoy a wiki",
        "noemailtitle": "Awan ti esurat a pagtaengan",
        "noemailtext": "Ti agar-aramat ket saan a nanginagan ti umisu nga esurat a pagtaengan.",
        "nowikiemailtext": "Ti agar-aramat ket mabalinna ti agpili a saan nga umawat iti esurat kadagiti sabali nga agar-aramat.",
        "emailccsubject": "Kopia ti mensahem kenni $1: $2",
        "emailsent": "Naipatuloden ti esurat",
        "emailsenttext": "Naipatuloden ti esurat a mensahem.",
-       "emailuserfooter": "Daytoy nga esurat ket impatulod ni $1 kenni $2 iti \"Esurat\" a panagararamid idiay {{SITENAME}}",
-       "usermessage-summary": "Agibatbati ti mesahe iti sistema.",
-       "usermessage-editor": "Mensahero iti sistema",
+       "emailuserfooter": "Daytoy nga esurat ket impatulod babaen ni $1 kenni $2 iti \"Esurat\" nga annong iti {{SITENAME}}",
+       "usermessage-summary": "Pumanpanaw iti mesahe ti sistema.",
+       "usermessage-editor": "Mensahero ti sistema",
        "watchlist": "Bambantayan",
        "mywatchlist": "Bambantayan",
        "watchlistfor2": "Para iti $1 $2",
        "nowatchlist": "Awan ti banag iti listaan dagiti bambantayam.",
        "watchlistanontext": "Pangngaasim ti $1 tapno makitam dagiti inurnosmo dita bambantayam.",
        "watchnologin": "Saan a nakastrek",
-       "addwatch": "Inayon iti bambantayan",
+       "addwatch": "Inayon iti listaan ti bambantayan",
        "addedwatchtext": "Ti panid iti \"[[:$1]]\" ket nainayonen idiay [[Special:Watchlist|listaan ti bambantayam]].\nDagiti masakbayan a panagsukat iti daytoy a panid ken dagiti mainaig a tungtunganna a panid ket mailistanto idiay.",
        "addedwatchtext-short": "Ti panid ti \"$1\" ket nainayonen iti listaan ti bambantayam.",
-       "removewatch": "Ikkaten dita bambantayan",
+       "removewatch": "Ikkaten manipud ti listaan ti bambantayan",
        "removedwatchtext": "Daytoy a panid  \"[[:$1]]\" ket naikkat idiay [[Special:Watchlist|bambantayam]].",
        "removedwatchtext-short": "Ti panid ti \"$1\" ket naikkaten manipud ti listaan ti bambantayam.",
-       "watch": "bantayan",
+       "watch": "Bantayan",
        "watchthispage": "Bantayan daytoy a panid",
        "unwatch": "Saanen a bantayan",
        "unwatchthispage": "Isardeng a bantayan daytoy a panid",
        "notanarticle": "Saan a naglaon a panid",
-       "notvisiblerev": "Ti panagbalbaliw ti sabali nga agar-aramat ket naikkaten",
-       "watchlist-details": "{{PLURAL:$1|$1 panid|$1 dagiti panid}} a bambantayam, saan a naisina a mairaman dagiti panid ti tungtungan.",
+       "notvisiblerev": "Ti naudi a rebision babaen ti sabali nga agar-aramat ket naikkaten",
+       "watchlist-details": "{{PLURAL:$1|$1 a panid|$1 a pampanid}} iti listaan ti bambantayam, a saan a naisina a mairaman dagiti panid ti tungtungan.",
        "wlheader-enotif": "Napakabaelan ti panangipakaammo ti esurat.",
-       "wlheader-showupdated": "Dagiti panid a nasukatanen manipud ti kinaudi a panagsarungkarmo ket naipakita iti '''napuskol'''",
+       "wlheader-showupdated": "Dagiti panid a nasukatanen manipud ti kinaudi a panagsarungkarmo ket naipakita iti <strong>napuskol</strong>.",
        "wlnote2": "Dita baba ket dagiti binalbaliwan {{PLURAL:$1|iti napalabas nga oras|kadagiti napalabas a <strong>$1</strong> nga oras}}, manipud idi $2, $3.",
        "wlshowlast": "Ipakita dagiti naudi a $1 nga or-oras $2 nga al-aldaw $3",
        "watchlist-options": "Dagiti pagpilian ti listaan a bambantayan",
        "watching": "Bambantayan...",
        "unwatching": "Saanen a bantayan...",
-       "watcherrortext": "Adda nagkabiddut idi suksukatam ti kita ti bambantayam \"$1\".",
+       "watcherrortext": "Adda napasamak a biddut bayat a suksukatam dagiti pannakaisaad ti listaan ti bambantayam para iti \"$1\".",
        "enotif_reset": "Markaan amin a pampanid a kas nasarungkaran",
        "enotif_impersonal_salutation": "Agar-aramat ti {{SITENAME}}",
        "enotif_subject_deleted": "Ti {{SITENAME}} a panid ti $1 ket inikkat idin babaen ni {{gender:$2|$2}}",
-       "enotif_subject_created": "Ti {{SITENAME}} a panid ti $1 ket napartuat idin babaen ni {{gender:$2|$2}}",
-       "enotif_subject_moved": "Ti {{SITENAME}} panid ti $1 ket naiyalis idin babaen ni {{gender:$2|$2}}",
-       "enotif_subject_restored": "Ti {{SITENAME}} a panid ti $1 ket naipasubli idin babaen ni {{gender:$2|$2}}",
-       "enotif_subject_changed": "Ti {{SITENAME}} a panid ti $1 ket nasukatan idin babaen ni {{gender:$2|$2}}",
-       "enotif_body_intro_deleted": "Ti {{SITENAME}} a panid ti $1 ket {{GENDER:$2|naikkaten}} idiay $PAGEEDITDATE babaen ni $2, kitaen ti $3.",
-       "enotif_body_intro_created": "Ti {{SITENAME}} a panid ti $1 ket napartuat idin idiay $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
-       "enotif_body_intro_moved": "Ti {{SITENAME}} a panid ti $1 ket naiyalis idin idiay $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
-       "enotif_body_intro_restored": "Ti {{SITENAME}} a panid ti $1 ket naipasubli idi idiay $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
-       "enotif_body_intro_changed": "Ti {{SITENAME}} a panid ti $1 ket nasukatan idin idiay $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
+       "enotif_subject_created": "Ti {{SITENAME}} a panid ti $1 ket pinartuat idin babaen ni {{gender:$2|$2}}",
+       "enotif_subject_moved": "Ti {{SITENAME}} panid ti $1 ket inyalis idin babaen ni {{gender:$2|$2}}",
+       "enotif_subject_restored": "Ti {{SITENAME}} a panid ti $1 ket inpulang idin babaen ni {{gender:$2|$2}}",
+       "enotif_subject_changed": "Ti {{SITENAME}} a panid ti $1 ket sinukatan idin babaen ni {{gender:$2|$2}}",
+       "enotif_body_intro_deleted": "Ti {{SITENAME}} a panid ti $1 ket {{GENDER:$2|naikkat}} idi $PAGEEDITDATE babaen ni $2, kitaen ti $3.",
+       "enotif_body_intro_created": "Ti {{SITENAME}} a panid ti $1 ket napartuaten idi $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
+       "enotif_body_intro_moved": "Ti {{SITENAME}} a panid ti $1 ket naiyalisen idi $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
+       "enotif_body_intro_restored": "Ti {{SITENAME}} a panid ti $1 ket naipulangen idi $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
+       "enotif_body_intro_changed": "Ti {{SITENAME}} a panid ti $1 ket nasukatanen idi $PAGEEDITDATE babaen ni {{gender:$2|$2}}, kitaen ti $3 para iti agdama panagbaliw.",
        "enotif_lastvisited": "Kitaen ti $1 para iti am-amin a panagsukat sipud ti naudi nga isasarungkarmo.",
        "enotif_lastdiff": "Kitaen ti $1 tapno mabuya daytoy a panagsukat.",
        "enotif_anon_editor": "di am-ammo nga agar-aramat $1",
-       "enotif_body": "Nadungngo a $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nPakabuklan ti mannurat: $PAGESUMMARY $PAGEMINOREDIT\n\nKontaken ti mannurat:\nsurat: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nAwanton dagiti sabali a pakaammo iti kaso ti adu pay a panagtigtignay malaksid no sarungkaram datoy a panid bayat a nakastrekka. Mabalinmo pay nga iyasentar manen dagiti wagayway ti pakaammo para kadagiti amin a bambantayam a panid idiay listaan ti bambantayam.\n\nTi mannakigayyem a sistema ti panagpaammo ti {{SITENAME}} \n\n--\nTi panagsukat ti kasasaad ti esurat a pagpa-ammom, sarungkaram ti\n{{canonicalurl:{{#special:Preferences}}}}\n\nTi panagsukat kadagiti kasasaad ti bambantayam, sarungkaram ti\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nTi panag-ikkat ti panid kadagiti bambantayam, sarungkaram ti\n$UNWATCHURL\n\nTi makunkunam ken no masapulmo pay ti tulong:\n$HELPPAGE",
+       "enotif_body": "Nadungngo a $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nPakabuklan ti mannurat: $PAGESUMMARY $PAGEMINOREDIT\n\nKontaken ti mannurat:\nsurat: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nAwanton dagiti sabali a pakaammo iti kaso ti adu pay a panagtigtignay malaksid no sarungkaram datoy a panid bayat a nakastrekka. Mabalinmo pay nga isaad manen dagiti wagayway ti pakaammo para kadagiti amin a bambantayam a panid idiay listaan ti bambantayam.\n\nTi mannakigayyem a sistema ti panagpaammo ti {{SITENAME}} \n\n--\nTi panagsukat ti kasasaad ti esurat a pagpa-ammom, sarungkaram ti\n{{canonicalurl:{{#special:Preferences}}}}\n\nTi panagsukat kadagiti kasasaad ti listaan ti bambantayam, sarungkaram ti\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nTi panagikkat ti panid kadagiti listaan ti bambantayam, sarungkaram ti\n$UNWATCHURL\n\nTi makunkunam ken no masapulmo pay ti tulong:\n$HELPPAGE",
        "created": "naaramid",
        "changed": "nasukatan",
        "deletepage": "Ikkaten ti panid",
        "confirm": "Pasingkedan",
        "excontent": "ti linaon idi ket: '$1'",
-       "excontentauthor": "ti linaonna idi ket: \"$1\" (ken ti laeng nakaaramid idi ket ni \"[[Special:Contributions/$2|$2]]\")",
+       "excontentauthor": "ti linaonna idi ket: \"$1\" (ken ti laeng kontributor idi ket ni \"[[Special:Contributions/$2|$2]]\")",
        "exbeforeblank": "ti linaon sakbay idi nablanko ket: \"$1\"",
        "delete-confirm": "Ikkaten ti \"$1\"",
        "delete-legend": "Ikkaten",
-       "historywarning": "'''Ballaag: ''' Ti panid a kayatmo nga ikkaten ket adda pakasaritaanna ti agarup a $1 {{PLURAL:$1|a binaliwan|kadagiti binaliwan}}:",
-       "confirmdeletetext": "Ikkatemon ti maysa a panid agraman am-amin a pakasaritaanna.\nPangngaasim ta pasingkedam a talaga a kayatmo nga aramiden daytoy, a maawatam ti bunga ti panangikkatmo, ken aramidem daytoy kas maiyannugot iti [[{{MediaWiki:Policy-url}}|annuroten]].",
-       "actioncomplete": "Nalpasen a naaramid",
+       "historywarning": "<strong>Ballaag:</strong> Ti panid a kayatmo nga ikkaten ket adda pakasaritaanna ti agarup a $1 {{PLURAL:$1|a rebision|kadagiti rebision}}:",
+       "confirmdeletetext": "Mangrugrugika a mangikkat ti maysa a panid a kakuyogna amin ti pakasaritaanna.\nPangngaasi a pasingkedam a talaga a kayatmo nga aramiden daytoy, a maawatam ti bunga ti panangikkatmo, ken aramidem daytoy kas maiyannugot iti [[{{MediaWiki:Policy-url}}|annuroten]].",
+       "actioncomplete": "Nalpasen ti aramid",
        "actionfailed": "Napaay ti aramid",
-       "deletedtext": "Naikkaten ti \"$1\".\nKitaen ti $2 para iti pannakrehistro dagiti naudi a naikkat.",
+       "deletedtext": "Naikkaten ti \"$1\".\nKitaen ti $2 para iti pannakairehistro dagiti naudi a pangikkat.",
        "dellogpage": "Listaan ti panagikkat",
        "dellogpagetext": "Adda dita baba ti listaan dagiti kaudian a panangikkat.",
        "deletionlog": "listaan ti panagikkat",
-       "reverted": "Naisubli iti immuna a panagbalbaliw",
+       "reverted": "Naisubli iti nasapsapa a rebision",
        "deletecomment": "Rason:",
        "deleteotherreason": "Sabali/maipatinayon a rason:",
        "deletereasonotherlist": "Sabali a rason",
-       "deletereason-dropdown": "* Kadawyan a rasrason ti panagikkat\n** Spam\n** Bandalismo\n** Panaglabsing iti karbengan ti panagipablaak\n** Kiddaw ti mannurat\n** Naputed a baw-ing",
+       "deletereason-dropdown": "* Kadawyan a rasrason ti panagikkat\n** Spam\n** Bandalismo\n** Panaglabsing iti karbengan ti kopia\n** Kiddaw ti mannurat\n** Naputed a baw-ing",
        "delete-edit-reasonlist": "Urnosen dagiti rason ti panagikkat",
        "delete-toobig": "Daytoy a panid ket dakkel ti pakasaritaanna, sumurok a  $1 {{PLURAL:a panagbaliwan|dagiti panagbaliwan}}.\nTi panagikkat ti kastoy a pammpanid ket naparitan tapno mapawilan ti saan nga inkarkaro a pannakadadael ti {{SITENAME}}.",
        "delete-warning-toobig": "Daytoy a panid ket adda ti dakkel unay a pakasaritaan ti panag-urnos, ti kaadu nga $1 {{PLURAL:$1|panagbaliw|dagiti panagbaliw}}.\nTi panagikkat ket madisturbo ti panagpataray ti database ti {{SITNAME}};\nagal-aluadka a mangrugi.",
        "rollback": "Isubli dagiti panag-urnos",
        "rollback_short": "Isubli",
        "rollbacklink": "isubli",
-       "rollbacklinkcount": "agisubli ti $1 {{PLURAL:$1|nga inurnos|nga inururnos}}",
-       "rollbacklinkcount-morethan": "agisubli ti ad-adu ngem $1 {{PLURAL:$1|nga inurnos|nga inururnos}}",
+       "rollbacklinkcount": "agisubli ti $1 {{PLURAL:$1|nga inurnos|nga inur-urnos}}",
+       "rollbacklinkcount-morethan": "agisubli ti ad-adu ngem $1 {{PLURAL:$1|nga inurnos|nga inur-urnos}}",
        "rollbackfailed": "Napaay ti panangisubli",
-       "cantrollback": "Saan a maisubli ti panagurnos;\nti naudi a nakaaramid ket iti laeng nagsurat daytoy a panid..",
+       "cantrollback": "Saan a maisubli ti panagurnos;\nti naudi a nakaaramid ket iti laeng nagsurat iti daytoy a panid.",
        "alreadyrolled": "Saan a maipasubli ti kinaudi a panagurnos iti [[:$1]] babaen ni [[User:$2|$2]] ([[User talk:$2|tungtungan]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nadda sabali a naurnos wenno nagipasubli ti panid.\n\nTi kinaudi a panagurnos ti daytoy a panid ket babaen ni [[User:$3|$3]] ([[User talk:$3|tungtungan]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
-       "editcomment": "Ti panagurnos a pakabuklan idi ket: \"''$1''\".",
-       "revertpage": "Insubli ti panagurnos babaen ni [[Special:Contributions/$2|$2]] ([[User talk:$2|tungtungan]]), naisubli ti kinaudi a panagbaliw babaen ni [[User:$1|$1]]",
-       "revertpage-nouser": "Naisubli dagiti inurnos babaen ti nailemmeng nga agar-aramat iti kinaudi a panagbalbaliw babaen ni {{GENDER:$1|[[User:$1|$1]]}}",
-       "rollback-success": "Naibabawi dagiti panag-urnos babaen ni $1;\nnaisubli manen ti naudi a panagbaliw babaen ni $2.",
-       "sessionfailure-title": "Napaay ti gimong",
-       "sessionfailure": "Adda parikut ti gimong ti panagserrekmo;\ndaytoy nga aramid ket naibabawi a kas pagpawilan ti panaghijack ti gimong.\nAgsubli ka ti naggapuam a panid, ikargam ti panid ken padasem manen.",
+       "editcomment": "Ti pakabuklan ti panag-urnos idi ket: \"''$1''\".",
+       "revertpage": "Insubli ti panag-urnos babaen ni [[Special:Contributions/$2|$2]] ([[User talk:$2|tungtungan]]), naisubli ti kinaudi 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 panag-urnos babaen ni $1;\nnaisubli manen ti naudi a rebision babaen ni $2.",
+       "sessionfailure-title": "Napaay ti sesion",
+       "sessionfailure": "Adda parikut ti sesion ti panagserrekmo;\ndaytoy nga aramid ket naibabawi a kas pagpawilan ti panaghijack ti sesion.\nAgsublika iti naggapuam a panid, ikargam manen ti panid ken padasen manen.",
        "protectlogpage": "Listaan ti panagsalaknib",
        "protectlogtext": "Dita baba ket adda listaan dagiti sinukatan a salaknib ti panid.\nKitaen ti [[Special:ProtectedPages|listaan kadagiti nasalakniban a panid]] ti listaan kadagiti agdama a panagpataray a panagsalaknib ti panid.",
        "protectedarticle": "nasalakniban ti \"[[$1]]\"",
        "modifiedarticleprotection": "nasukatan ti agpang ti salaknib para iti \"[[$1]]\"",
-       "unprotectedarticle": "naikkat ti salaknib ti \"[[$1]]\"",
-       "movedarticleprotection": "iyalis ti kasasaad ti salaknib manipud iti \"[[$2]]\" idiay \"[[$1]]\"",
+       "unprotectedarticle": "naikkat ti salaknib manipud ti \"[[$1]]\"",
+       "movedarticleprotection": "iyalis ti kasasaad ti salaknib manipud ti \"[[$2]]\" iti \"[[$1]]\"",
        "protect-title": "Sukatan ti agpang ti salaknib para iti \"$1\"",
        "protect-title-notallowed": "Kitaen ti agpang ti salaknib ti \"$1\"",
        "prot_1movedto2": "[[$1]] naiyalis iti [[$2]]",
        "protect-badnamespace-title": "Saan a mabalin a salakniban a nagan ti espasio",
-       "protect-badnamespace-text": "Dagiti panid ditoy a nagan ti espasio ket saan a mabalin a masalakniban.",
-       "protect-norestrictiontypes-text": "Daytoy a panid ket saan a mabalin a masalakniban gaputa awan dagiti maiparit a kita a magun-od.",
+       "protect-badnamespace-text": "Dagiti panid iti daytoy a nagan ti espasio ket saan a mabalin a masalakniban.",
+       "protect-norestrictiontypes-text": "Daytoy a panid ket saan a mabalin a masalakniban gapu ta awan dagiti magun-od a kita ti panangigawid.",
        "protect-norestrictiontypes-title": "Di masalakniban a panid",
        "protect-legend": "Pasingkedan ti panagsalaknib",
        "protectcomment": "Rason:",
        "protect_expiry_invalid": "Imbalido ti oras a panagpaso.",
        "protect_expiry_old": "Napalabasen ti oras ti panagpaso.",
        "protect-unchain-permissions": "Lukatan dagiti pagpilian ti salaknib",
-       "protect-text": "Mabalinmo a kitaen ken sukatan ti agpang ti salaknib para iti panid ti '''$1'''.",
-       "protect-locked-blocked": "Saanmo a mabalin a sukatan dagiti kita ti salaknib no naserraanka.\nAdda ditoy kadagiti agdama a kasasaad ti panid '''$1''':",
-       "protect-locked-dblock": "Ti kita ti salaknib ket saan a masukatan gapu ti agdama a kandado ti database.\nAdda ditoy kadagiti agdama a kasasaad ti panid '''$1''':",
-       "protect-locked-access": "Awan ti pammalubos ti pakabilangam a mangsukat kadagiti lessaad ti salaknib ti panid.\nDagitoy dagiti agdama a kasasaad ti panid a '''$1''':",
-       "protect-cascadeon": "Daytoy a panid ket agdama a nasalakniban gapu ta nairaman kadagiti sumaganad a {{PLURAL:$1|panid, nga addaan|pampanid, nga addaan}} iti sipapakat a salaknib a sariap.\nDagiti panagbaliw iti agpang ti salaknib iti daytoy a panid ket saan a mabanagan ti salaknib a sariap.",
+       "protect-text": "Mabalinmo a kitaen ken sukatan ti agpang ti salaknib para iti panid ti <strong>$1</strong>.",
+       "protect-locked-blocked": "Saanmo a mabalin a sukatan dagiti kita ti salaknib no naserraanka.\nAdda ditoy kadagiti agdama a kasasaad ti panid ti <strong>$1</strong>:",
+       "protect-locked-dblock": "Ti kita ti salaknib ket saan a masukatan gapu ti agdama a kandado ti database.\nAdda ditoy kadagiti agdama a kasasaad ti panid ti <strong>$1</strong>:",
+       "protect-locked-access": "Ti pakabilangam ket awan pammalubosna a mangsukat kadagiti agpang ti salaknib ti panid.\nDagitoy ti agdama a pannakaisaad para iti panid ti <strong>$1</strong>:",
+       "protect-cascadeon": "Daytoy a panid ket agdama a nasalakniban gapu ta nairaman kadagiti sumaganad a {{PLURAL:$1|panid, nga addaan|pampanid, nga addaan}} iti nalukatan a salaknib ti sariap.\nDagiti panagbaliw iti agpang ti salaknib iti daytoy a panid ket saan a mabanagan ti salaknib ti sariap.",
        "protect-default": "Palubosan amin nga agar-aramat",
        "protect-fallback": "Palubosan laeng dagiti agar-aramat nga adda iti \"$1\" a pammalubos",
        "protect-level-autoconfirmed": "Palubosan laeng dagiti automatiko a napasingkedan nga agar-aramat",
        "protect-existing-expiry": "Ti adda a panagpaso ti oras: $3, $2",
        "protect-otherreason": "Sabali/maipatinayon a rason:",
        "protect-otherreason-op": "Sabali a rason",
-       "protect-dropdown": "*Kadawyan a rasrason ti panagsalaknib\n** Adu unay a bandalismo\n** Adu unay a panagspam\n** Saan a produktibo ti kasinnungat a panag-urnos\n** Adu unay nga agbuybuya ti panid",
+       "protect-dropdown": "*Kadawyan a rasrason ti panagsalaknib\n** Adu unay a bandalismo\n** Adu unay a panagspam\n** Saan a produktibo ti agsinnungat a panag-urnos\n** Adu unay nga agbuybuya iti panid",
        "protect-edit-reasonlist": "Urnosen dagiti rason ti salaknib",
        "protect-expiry-options": "1 nga oras:1 hour,1 nga aldaw:1 day,1 a lawas:1 week,2 a lawas:2 weeks,1 a bulan:1 month,3 a bulan:3 months,6 a bulan:6 months,1 a tawen:1 year,awan inggana:infinite",
        "restriction-type": "Pammalubos:",
-       "restriction-level": "Agpang ti pannakaiparit:",
-       "minimum-size": "Kinababa a kadakkel:",
-       "maximum-size": "Kinangato a kadakkel:",
+       "restriction-level": "Agpang ti panangigawid:",
+       "minimum-size": "Kababaan a kadakkel:",
+       "maximum-size": "Kangatuan a kadakkel:",
        "pagesize": "(dagiti byte)",
        "restriction-edit": "Urnosen",
        "restriction-move": "Iyalis",
-       "restriction-create": "Aramiden",
-       "restriction-upload": "Pang-ipan",
+       "restriction-create": "Agpartuat",
+       "restriction-upload": "Agikarga",
        "restriction-level-sysop": "napno a nasalakniban",
        "restriction-level-autoconfirmed": "nasalakniban bassit",
        "restriction-level-all": "aniaman nga agpang",
        "undelete": "Kitaen dagiti naikkat a panid",
        "undeletepage": "Kitaen ken isubli dagiti naikkat a panid",
-       "undeletepagetitle": "'''Ti sumaganad ket buklen dagiti naikkat a panagbaliw ni [[:$1|$1]]'''.",
+       "undeletepagetitle": "<strong>Ti sumaganad ket buklen dagiti naikkat a rebision ni [[:$1|$1]]</strong>.",
        "viewdeletedpage": "Kitaen dagiti naikkat a panid",
        "undeletepagetext": "Ti sumaganad a {{PLURAL:$1|panid ket naikkaten ngem|$1 pampanid ket naikkaten ngem}} adda pay naarkibo ken mabalin pay a maipasubli .\nTi arkibo ket mabalin a sagpaminsan a madalusan.",
-       "undelete-fieldset-title": "Ipasubli dagiti binaliwan",
-       "undeleteextrahelp": "Tapno maipasubli ti intero a pakasaritaan ti panid, ibatim a saan nga nakur-itan dagita kahon ken ipindut ti '''''{{int:undeletebtn}}'''''.\nTi agaramid ti napilian a panagisubli, ikur-it dagita napilim kadagiti kahon ti kayatmo nga ipasubli, ken ipindut ti '''''{{int:undeletebtn}}'''''.",
-       "undeleterevisions": "$1 {{PLURAL:$1|a binalbaliwan|kadagiti binalbaliwan}} ti nailebben",
-       "undeletehistory": "No ipasublim daytoy a panid, amin dagiti pinagbaliwan ket maipasubli idiay pakasaritaan.\nKet no adda baro a panid a kanagnagan na a naaramid ti napalabas a pinagikkat, dagiti naipasubli a pinagbaliwan ket agparang idiay napalabas a pakasaritaan.",
-       "undeleterevdel": "Ti panagikkat ket saan a maaramid no agbanag iti rabaw ti panid, wenno ti pinagbaliwan ti papeles ket maikkatan ti bassit.\nIti kastoy a kaso, masapul nga ikkatem ti kur-it wenno ikkatem ti lemmeng dagiti kabarbaro a naikkat a binalbaliwan.",
-       "undeletehistorynoadmin": "Daytoy a panid ket naikkaten.\nTi rason ti panagikkat ket naipakita ti pakabuklan dita baba, ken dagita dsalaysay ti agar-aramat a nagpabaliw ditoy a panid sakbay a naikkat.\nTi husto a testo ti nabaliwan a panagbaliw ket adda kadagiti administrador laeng.",
-       "undelete-revision": "Naikkat ti binaliwan a $1 (manipud idi $4, idi $5) babaen ni $3:",
-       "undeleterevision-missing": "Imbalido wenno napukaw a panagbaliw.\nAddaanka ngata ti madi a silpo, wenno ti panagbaliw ket naipasubli wenno naikkat manipud idiay nailebbeng.",
-       "undelete-nodiff": "Awan ti nasarakan kadagiti dati a nabalbaliwan.",
+       "undelete-fieldset-title": "Ipasubli dagiti rebision",
+       "undeleteextrahelp": "Tapno maipasubli ti intero a pakasaritaan ti panid, ibatim a saan nga nakur-itan dagita kahon ken pinduten ti '''''{{int:undeletebtn}}'''''.\nTi agaramid ti napilian a panagisubli, ikur-it dagita napilim kadagiti kahon ti kayatmo nga ipasubli, ken pinduten ti '''''{{int:undeletebtn}}'''''.",
+       "undeleterevisions": "$1 {{PLURAL:$1|a rebision|kadagiti rebision}} ti naarkibo",
+       "undeletehistory": "No ipasublim daytoy a panid, amin dagiti rebision ket maipasubli iti pakasaritaan.\nKet no adda baro a panid a kanagnaganna a naaramid ti napalabas a panagikkat, dagiti naipasubli a rebision ket agparang iti napalabas a pakasaritaan.",
+       "undeleterevdel": "Ti panagikkat ket saan a maaramid no agbanag iti rabaw ti panid, wenno ti rebision ti papeles ket maikkatan ti bassit.\nIti kastoy a kaso, masapul nga ikkatem ti kur-it wenno ikkatem ti lemmeng dagiti kabarbaro a naikkat a rebision.",
+       "undeletehistorynoadmin": "Daytoy a panid ket naikkaten.\nTi rason ti panagikkat ket naipakita iti pakabuklan dita baba, ken dagita a salaysay ti agar-aramat a nagurnos iti daytoy a panid sakbay a naikkat.\nTi husto a testo dagitoy a naikat a rebision ket magun-od laeng dagiti administrador.",
+       "undelete-revision": "Naikkat ti rebision ti $1 (manipud idi $4, $5) babaen ni $3:",
+       "undeleterevision-missing": "Imbalido wenno napukaw a rebision.\nAddaanka ngata ti madi a silpo, wenno ti rebision ket mabalin a naipasubli wenno naikkat manipud ti arkibo.",
+       "undelete-nodiff": "Awan ti nasarakan kadagiti dati a rebision.",
        "undeletebtn": "Isubli",
        "undeletelink": "kitaen/isubli",
        "undeleteviewlink": "kitaen",
        "undeleteinvert": "Baliktaden ti napili",
        "undeletecomment": "Rason:",
-       "undeletedrevisions": "{{PLURAL:$1|1 a  binaliwan|dagiti $1 a binaliwan}} ti naisubli",
-       "undeletedrevisions-files": "{{PLURAL:$1|1 a binaliwan|dagiti $1 a binaliwan}} ken {{PLURAL:$2|1 a papeles|dagiti $2 a papeles}} ti naisubli",
+       "undeletedrevisions": "{{PLURAL:$1|1 a rebision|dagiti $1 a rebision}} ti naisubli",
+       "undeletedrevisions-files": "{{PLURAL:$1|1 a rebision|dagiti $1 a rebision}} ken {{PLURAL:$2|1 a papeles|dagiti $2 a papeles}} ti naisubli",
        "undeletedfiles": "{{PLURAL:$1|1 a papeles|dagiti $1 a papeles}} ti naisubli",
-       "cannotundelete": "Napaay ti panagikkat:\n$1",
-       "undeletedpage": "'''Naisublin ti $1'''\n\nBinsiren ti [[Special:Log/delete|listaan ti naik-ikkat]] para iti listaan dagiti naudi a naik-ikkat ken naisubsubli.",
-       "undelete-header": "Kitaen [[Special:Log/delete|ti listaan ti pinagikkat]] kadagiti kinaudian a naikkat a panid.",
+       "cannotundelete": "Napaay ti panagisubli iti panagikkat:\n$1",
+       "undeletedpage": "<strong>Naisublin ti $1</strong>\n\nBinsiren ti [[Special:Log/delete|listaan ti panagikkat]] para iti rehistro dagiti kaudian panagikkat ken naisubsubli.",
+       "undelete-header": "Kitaen [[Special:Log/delete|ti listaan ti panagikkat]] kadagiti kaudian a naikkat a panid.",
        "undelete-search-title": "Biruken dagiti naikkat a panid",
        "undelete-search-box": "Biruken dagiti naikkat a panid",
        "undelete-search-prefix": "Ipakita dagiti panid a mangrugi iti:",
        "undelete-search-submit": "Biruken",
-       "undelete-no-results": "Awan dagiti kapada ti panid a nasarakan idiay lebben ti panagikkat.",
-       "undelete-filename-mismatch": "Saan maisubli ti panagikkat ti pinagbaliwan ti papeles nga adda oras ket petsana a $1: Saan nga agpada ti nagan ti papeles.",
-       "undelete-bad-store-key": "Saan a maisubli ti pinagikkat ti pinagbaliwan ti papeles nga adda oras ket petsana a $1: Ti papeles ket napukaw sakbay a naikkat.",
-       "undelete-cleanup-error": "Biddut ti panagikkat ti saan a naus-usar a naidulin a papeles \"$1\".",
-       "undelete-missing-filearchive": "Saan a naipabalin ti panagisubli ti ID ti papeles a nailebben $1 ngamin ket awan idiay database.\nMabalin daytoy a naikkaten.",
-       "undelete-error": "Ballaag ti panagisubli ti panagikkat ti panid",
-       "undelete-error-short": "Biddut ti pannakaikkat ti papeles: $1",
-       "undelete-error-long": "Adda nasarakan a biddut idi panagisubli ti panagikkat ti papeles:\n\n$1",
-       "undelete-show-file-confirm": "Sigurado a kayatmo ti mangkita ti naikkat a panagbaliw ti papeles \"<nowiki>$1</nowiki>\" manipud idi $2 idi $3?",
+       "undelete-no-results": "Awan dagiti kapada ti panid a nasarakan idiay arkibo ti panagikkat.",
+       "undelete-filename-mismatch": "Saan maisubli ti panagikkat ti rebision ti papeles nga adda oras ket petsana a $1: Saan nga agpada ti nagan ti papeles.",
+       "undelete-bad-store-key": "Saan a maisubli ti pinagikkat ti rebision ti papeles nga adda oras ket petsana a $1: Ti papeles ket napukaw sakbay a naikkat.",
+       "undelete-cleanup-error": "Biddut ti panagikkat ti saan a naus-usar a naarkibo a papeles ti \"$1\".",
+       "undelete-missing-filearchive": "Saan a naipasubli ti ID ti arkibo ti papeles ti $1 ngamin ket awan idiay database.\nMabalin naikkaten daytoy.",
+       "undelete-error": "Biddut ti panagisubli ti panagikkat ti panid",
+       "undelete-error-short": "Biddut ti panagisubli ti pannakaikkat ti papeles: $1",
+       "undelete-error-long": "Adda dagiti nasarakan a biddut bayat ti panagisubli ti panagikkat ti papeles:\n\n$1",
+       "undelete-show-file-confirm": "Sigurado a kayatmo ti mangkita ti naikkat a rebision ti papeles \"<nowiki>$1</nowiki>\" manipud idi $2, $3?",
        "undelete-show-file-submit": "Wen",
        "namespace": "Nagan ti espasio:",
        "invert": "Baliktaden ti napili",
        "tooltip-invert": "Ikur-it daytoy a kahon ti panagilemmeng kadagiti sinukatan a panid iti uneg ti napili a nagan ti espasio (ken ti nairaman a nagan ti espasio no naikur-it)",
-       "namespace_association": "Nairaman a nagan ti espasio",
-       "tooltip-namespace_association": "Ikur-it daytoy a kahon ti panagiraman ti kapatangan wenno suheto ti nagan ti espasio a nairaman kadagiti napili a nagan ti espasio.",
+       "namespace_association": "Mainaig a nagan ti espasio",
+       "tooltip-namespace_association": "Ikur-it daytoy a kahon ti panagiraman ti tungtungan wenno suheto ti nagan ti espasio a nairaman kadagiti napili a nagan ti espasio",
        "blanknamespace": "(Umuna)",
-       "contributions": "Naar-aramid ti {{GENDER:$1|Agar-aramat}}",
-       "contributions-title": "Inar-aramid ti agar-aramat para kenni $1",
-       "mycontris": "Naar-aramid",
+       "contributions": "Dagiti kontribusion ti {{GENDER:$1|agar-aramat}}",
+       "contributions-title": "Kontribusion ti agar-aramat para kenni $1",
+       "mycontris": "Dagiti kontribusion",
        "contribsub2": "Para kenni {{GENDER:$3|$1}} ($2)",
-       "contributions-userdoesnotexist": "Ti pakabilangan ti agar-aramat \"$1\" ket saan a nakarehistro.",
-       "nocontribs": "Awan ti nasarakan a nasukatan a kapada daytoy a kita.",
+       "contributions-userdoesnotexist": "Ti pakabilangan ti agar-aramat ni \"$1\" ket saan a nakarehistro.",
+       "nocontribs": "Awan ti nasarakan a nasukatan a kapada dagitoy a kriteria.",
        "uctop": "(agdama)",
-       "month": "Manipud iti bulan ti (ken nasapsapa pay):",
-       "year": "Manipud iti tawen (ken nasapsapa pay):",
-       "sp-contributions-newbies": "Iparang dagiti inar-aramid dagiti kabarbaro a pakabilangan laeng",
+       "month": "Manipud ti bulan (ken nasapsapa):",
+       "year": "Manipud ti tawen (ken nasapsapa):",
+       "sp-contributions-newbies": "Iparang dagiti kontribusion dagiti kabarbaro a pakabilangan laeng",
        "sp-contributions-newbies-sub": "Para kadagiti kabarbaro a pakabilangan",
-       "sp-contributions-newbies-title": "Dagiti inar-aramid ti agar-aramat iti baro a pakabilangan",
-       "sp-contributions-blocklog": "listaan ti naserraan",
+       "sp-contributions-newbies-title": "Dagiti kontribusion para kadagiti baro a pakabilangan",
+       "sp-contributions-blocklog": "listaan ti serra",
        "sp-contributions-suppresslog": "pasardengen dagiti kontribusion ti agar-aramat",
-       "sp-contributions-deleted": "dagiti naikkat nga inar-aramid ti agar-aramat",
-       "sp-contributions-uploads": "dagiti pang-ipan",
-       "sp-contributions-logs": "listaan",
+       "sp-contributions-deleted": "dagiti naikkat a kontribusion ti agar-aramat",
+       "sp-contributions-uploads": "dagiti naikarga",
+       "sp-contributions-logs": "dagiti listaan",
        "sp-contributions-talk": "tungtungan",
        "sp-contributions-userrights": "panagtaripato kadagiti karbengan ti agar-aramat",
-       "sp-contributions-blocked-notice": "Naserraan tatta daytoy nga agar-aramat.\nTi naudi a listaan ti pannakaserra ket adda dita baba tapno mausar a reperensia:",
-       "sp-contributions-blocked-notice-anon": "Daytoy nga IP a pagtaengan ket naserraan.\nTi naudi a listaan ti pannakaserra ket adda dita baba tapno mausar a reperensia:",
-       "sp-contributions-search": "Agsapul para kadagiti naar-aramid",
+       "sp-contributions-blocked-notice": "Adama a naserraan daytoy nga agar-aramat.\nTi naudi a naikabil iti listaan ti pannakaserra ket naited dita baba para iti reperensia:",
+       "sp-contributions-blocked-notice-anon": "Daytoy nga IP a pagtaengan ket agdama a naserraan.\nTi naudi a naikabil iti listaan ti pannakaserra ket adda dita baba para iti reperensia:",
+       "sp-contributions-search": "Agbiruk para kadagiti kontribusion",
        "sp-contributions-username": "IP a pagtaengan wenno nagan ti agar-aramat:",
-       "sp-contributions-toponly": "Ipakita laeng dagiti inurnos a kinaudian a panagbaliw",
+       "sp-contributions-toponly": "Ipakita laeng dagiti inurnos dagiti kaudian a rebision",
        "sp-contributions-newonly": "Ipakita laeng dagiti inurnos a pannakapartuat ti pampanid",
        "sp-contributions-submit": "Biruken",
        "whatlinkshere": "Dagiti nakasilpo ditoy",
        "whatlinkshere-title": "Pampanid a nakasilpo iti \"$1\"",
        "whatlinkshere-page": "Panid:",
-       "linkshere": "Dagiti sumaganad a panid ket nakasilpo iti '''[[:$1]]''':",
-       "nolinkshere": "Awan ti pampanid a nakasilpo iti '''[[:$1]]'''.",
-       "nolinkshere-ns": "Awan ti pampanid a nakasilpo idiay '''[[:$1]]''' iti napili a nagan ti espasio.",
+       "linkshere": "Dagiti sumaganad a panid ket nakasilpo iti <strong>[[:$1]]</strong>:",
+       "nolinkshere": "Awan ti pampanid a nakasilpo iti <strong>[[:$1]]</strong>.",
+       "nolinkshere-ns": "Awan ti pampanid a nakasilpo iti <strong>[[:$1]]</strong> iti napili a nagan ti espasio.",
        "isredirect": "baw-ing a panid",
        "istemplate": "mailak-am",
        "isimage": "silpo ti papeles",
        "whatlinkshere-next": "{{PLURAL:$1|sumaruno|sumaruno a $1}}",
        "whatlinkshere-links": "← silsilpo",
        "whatlinkshere-hideredirs": "$1 dagiti baw-ing",
-       "whatlinkshere-hidetrans": "$1 dagiti mailaklak-am",
+       "whatlinkshere-hidetrans": "$1 dagiti mailak-am",
        "whatlinkshere-hidelinks": "$1 dagiti silpo",
-       "whatlinkshere-hideimages": "$1 a silsilpo ti papeles",
+       "whatlinkshere-hideimages": "$1 dagiti silpo ti papeles",
        "whatlinkshere-filters": "Dagiti sagat",
        "autoblockid": "Auto a panagserra #$1",
        "block": "Seraan ti agar-aramat",
        "unblock": "Ikkaten ti serra ti agar-aramat",
        "blockip": "Serraan ti agar-aramat",
        "blockip-legend": "Serraan ti agar-aramat",
-       "blockiptext": "Usaren ti kinabuklan dita baba tapno maserraan ti panagsurat manipud iti naisangayan nga IP a pagtaengan wenno nagan ti agar-aramat.\nUsaren laeng daytoy tapno pawilan ti bandalismo, ken panagtunos iti [[{{MediaWiki:Policy-url}}|annuroten]].\nIkkan ti naisangayan a rason dita baba (kas pagarigan, dakamaten ti maysa a panid a na-bandalismo) .",
+       "blockiptext": "Usaren ti porma dita baba tapno maserraan ti panagsurat manipud iti naisangayan nga IP a pagtaengan wenno nagan ti agar-aramat.\nUsaren laeng daytoy tapno pawilan ti bandalismo, ken panagtunos iti [[{{MediaWiki:Policy-url}}|annuroten]].\nIkkan ti naisangayan a rason dita baba (kas pagarigan, dakamaten ti maysa a panid a na-bandalismo) .",
        "ipaddressorusername": "IP a pagtaengan wenno nagan ti agar-aramat:",
        "ipbexpiry": "Agpaso:",
        "ipbreason": "Rason:",
-       "ipbreason-dropdown": "*Dagiti kadawyan a rason ti panagserra\n** Agikabil kadagiti  madi a pakaammo\n** Agikkat kadagiti linaon ti pampanid\n** Agikabil ti spam a silpo iti ruar\n** Agikabil ti minamaag/saan a maawatan a pampanid\n** Nabutbuteng a panagkukua /agriribok\n** Agab-abuso kadagiti sabsabali a pakabilangan\n** Saan a maawat a nagan ti agar-aramat",
-       "ipb-hardblock": "Iparit kadagiti nakastrek nga agar-aramat manipud ti panagurnos manipud ti naggapo ditoy nga IP a pagtaengan",
+       "ipbreason-dropdown": "*Dagiti kadawyan a rason ti panagserra\n** Agikabil kadagiti  madi a pakaammo\n** Agikkat kadagiti linaon ti pampanid\n** Agikabil ti spam a silpo iti ruar\n** Agikabil ti minamaag/saan a maawatan a pampanid\n** Mangbutbuteng a panagkukua /mangriribok\n** Agab-abuso kadagiti nadumaduma a pakabilangan\n** Saan a maawat a nagan ti agar-aramat",
+       "ipb-hardblock": "Iparit dagiti nakastrek nga agar-aramat manipud ti panagurnos manipud ti daytoy nga IP a pagtaengan",
        "ipbcreateaccount": "Pawilan ti panagpartuat iti pakabilangan",
        "ipbemailban": "Pawilan ti agar-aramat nga agipatulod ti esurat",
-       "ipbenableautoblock": "Automatiko ti serra ti naudi nga IP a pagtaengan nga inusar daytoy nga agar-aramat, ken dagiti sumaruno nga IP a pagtaengan a padasenda nga agpabaliw",
+       "ipbenableautoblock": "Automatiko a mangserra ti naudi nga IP a pagtaengan nga inusar daytoy nga agar-aramat, ken dagiti sumaruno nga IP a pagtaengan nga ayan ti pangipadasanda nga agurnos",
        "ipbsubmit": "Serraan daytoy nga agar-aramat",
        "ipbother": "Sabali nga oras:",
        "ipboptions": "2 nga oras:2 hours,1 nga aldaw:1 day,3 nga aldaw:3 days,1 a lawas:1 week,2 a lawas:2 weeks,1 a bulan:1 month,3 a bulan:3 months,6 a bulan:6 months,1 a tawen:1 year,awan inggana:infinite",
        "ipbhidename": "Ilemmeng ti nagan ti agar-aramat kadagiti listaan ken inurnos",
        "ipbwatchuser": "Bantayan ti panid ti agar-ramat ken panid ti tungtungan daytoy nga agar-aramat",
-       "ipb-disableusertalk": "Pawilan daytoy nga agar-aramat nga agurnos kadagiti bukodda a tungtungan a panid no naserraan",
-       "ipb-change-block": "Serraan manen ti agar-aramat kadagitoy a disso",
+       "ipb-disableusertalk": "Pawilan daytoy nga agar-aramat nga agurnos kadagiti bukodda a tungtungan a panid bayat a naserraan",
+       "ipb-change-block": "Serraan manen ti agar-aramat kadagitoy a pannakaisaad",
        "ipb-confirm": "Pasingkedan ti serra",
        "badipaddress": "Imbalido nga IP a pagtaengan",
        "blockipsuccesssub": "Balligi ti panangserra",
-       "blockipsuccesstext": "[[Special:Contributions/$1|$1]] ket naserraanen.<br />\nKitaen ti [[Special:BlockList|listaan ti lapden nga IP ]] tapno marepaso dagiti serra.",
+       "blockipsuccesstext": "Ni [[Special:Contributions/$1|$1]] ket naserraanen.<br />\nKitaen ti [[Special:BlockList|listaan ti serra]] tapno marepaso dagiti serra.",
        "ipb-blockingself": "Mangrugrugika nga agserra kenka! Sigurado a kayatmo nga aramiden daytoy?",
-       "ipb-confirmhideuser": "Mangrugrugika ti mangserra ti agar-aramat nga adda ti napabalinna nga \"ilemmeng ti agar-aramat\". Iddeppenna ti nagan daytoy nga agar-aramat kadagiti amin a listaan ken dagiti naikabkabil ti listaan. Siguradoka a kasta ti kayatmo?",
-       "ipb-confirmaction": "No segurado a kayatmo nga aramiden daytoy, pangngaasi a kitaen ti \"{{int:ipb-confirm}}\" a pagikabilan dita baba.",
+       "ipb-confirmhideuser": "Mangrugrugika ti mangserra iti agar-aramat a napakabaelan iti \"ilemmeng ti agar-aramat\". Iddeppenna ti nagan daytoy nga agar-aramat kadagiti amin a listaan ken dagiti naikabkabil ti listaan. Siguradoka a kasta ti kayatmo?",
+       "ipb-confirmaction": "No sigurado a kayatmo nga aramiden daytoy, pangngaasi a kitaen ti \"{{int:ipb-confirm}}\" a pagikabilan dita baba.",
        "ipb-edit-dropdown": "Urnosen dagiti rason ti panagserra",
        "ipb-unblock-addr": "Lukatan ti serra ni $1",
        "ipb-unblock": "Lukatan ti serra ti nagan ti agar-aramat wenno IP a pagtaengan",
        "ipb-blocklist": "Kitaen dagiti adda a serra",
-       "ipb-blocklist-contribs": "Dagiti inaramid ni $1",
+       "ipb-blocklist-contribs": "Dagiti kontribusion para kenni $1",
        "unblockip": "Lukatan ti serra ti agar-aramat",
-       "unblockiptext": "Usaren ti porma dita baba ti panangisubli ti panagserrek nga agsurat ti napalabas a naserran nga IP a pagtaengan wenno nagan ti agar-aramat.",
+       "unblockiptext": "Usaren ti porma dita baba tapno maisubli ti panagserrek ti panagsurat ti dati a naserran nga IP a pagtaengan wenno nagan ti agar-aramat.",
        "ipusubmit": "Ikkaten daytoy a serra",
        "unblocked": "Naikkat ti pannakaserra ni [[User:$1|$1]].",
-       "unblocked-range": "Naikkat ti serra ti $1.",
+       "unblocked-range": "Naikkaten ti serra ti $1.",
        "unblocked-id": "Naikkaten ti serra ti $1.",
        "blocklist": "Dagiti naserraan nga agar-aramat",
        "ipblocklist": "Dagiti naserraan nga agar-aramat",
        "blocklist-userblocks": "Ilemmeng dagiti serra ti pakabilangan",
        "blocklist-tempblocks": "Ilemmeng dagiti temporario a serra",
        "blocklist-addressblocks": "Ilemmeng ti maysa a serra dagiti IP",
-       "blocklist-rangeblocks": "Ilemmeng dagiti nasakup a serra",
+       "blocklist-rangeblocks": "Ilemmeng dagiti nasakop a serra",
        "blocklist-timestamp": "Petsa ken oras",
        "blocklist-target": "Puntaan",
        "blocklist-expiry": "Agpaso",
        "blocklist-by": "Ti nagserra nga admin",
-       "blocklist-params": "Parametro ti serra",
+       "blocklist-params": "Dagiti parametro ti serra",
        "blocklist-reason": "Rason",
        "ipblocklist-submit": "Biruken",
        "ipblocklist-localblock": "Lokal a serra",
        "ipblocklist-otherblocks": "Sabali {{PLURAL:$1|a serra|kadagiti serra}}",
        "infiniteblock": "inggana't inggana",
-       "expiringblock": "agpaso intono $1 ti oras nga $2",
-       "anononlyblock": "di am-ammo laeng",
-       "noautoblockblock": "nabaldado ti auto a serra",
+       "expiringblock": "agpaso intono $1, $2",
+       "anononlyblock": "di ammo laeng",
+       "noautoblockblock": "nabaldado ti automatiko a serra",
        "createaccountblock": "naserraan ti pannakapartuat ti pakabilangan",
-       "emailblock": "naserraan ti esurat",
+       "emailblock": "nabaldado ti esurat",
        "blocklist-nousertalk": "saan a mabalin nga agurnos ti bukod a tungtungan a panid",
-       "ipblocklist-empty": "Awan nagyan ti listaan ti serra.",
-       "ipblocklist-no-results": "Ti kiniddaw nga IP a pagtaengan wenno nagan ti agar-aramat ket saan a naserraan",
+       "ipblocklist-empty": "Awan linaon ti listaan ti serra.",
+       "ipblocklist-no-results": "Ti kiniddaw nga IP a pagtaengan wenno nagan ti agar-aramat ket saan a naserraan.",
        "blocklink": "serraan",
-       "unblocklink": "saanen a naserraan",
-       "change-blocklink": "baliwan  ti serra",
+       "unblocklink": "ikkaten ti serra",
+       "change-blocklink": "baliwan ti serra",
        "contribslink": "aramid",
        "emaillink": "ipatulod ti esurat",
        "autoblocker": "Automatiko a naserraan ngamin ket ti IP a pagtaengam ket naudi nga inusar babaen ni \"[[User:$1|$1]]\".\nTi inted a rason para iti serra ni $1 ket: \"$2\"",
-       "blocklogpage": "Listaan ti naserraan",
-       "blocklog-showlog": "Daytoy nga agar-aramat ket dati a naserraan.\nTi listaan ti serra ket naikabil dita baba tapno mausar a reperensia:",
-       "blocklog-showsuppresslog": "Daytoy nga agar-aramat ket dati a naserraan ken nailemmeng.\nTi listaan ti napasardeng ket naikabil dita baba tapno mausar a reperensia:",
+       "blocklogpage": "Listaan ti serra",
+       "blocklog-showlog": "Daytoy nga agar-aramat ket dati a naserraan.\nTi listaan ti serra ket naikabil dita baba para iti reperensia:",
+       "blocklog-showsuppresslog": "Daytoy nga agar-aramat ket dati a naserraan ken nailemmeng.\nTi listaan ti panagpasardeng ket naikabil dita baba para iti reperensia:",
        "blocklogentry": "naserraan ni [[$1]] nga adda ti oras a panagpaso iti $2 $3",
-       "reblock-logentry": "sinukatan ti pannakaserra para kenni [[$1]] nga adda ti oras a panagpaso iti  $2 $3",
-       "blocklogtext": "Daytoy ket listaan ti agar-aramat kadagiti panagserra ken panaglukat ti serra\nDagiti na-atomatiko a panakaserra ti IP a pagtaengan ket saan a nailista.\nKitaen ti [[Special:BlockList|Listaan ti lapden nga IP]] para iti listaan kadagiti agdama a naiparit a pagpataray ken dagiti serra.",
+       "reblock-logentry": "sinukatan ti pannakaserra para kenni [[$1]] nga adda ti oras a panagpaso iti $2 $3",
+       "blocklogtext": "Daytoy ket listaan ti agar-aramat kadagiti panagserra ken panaglukat ti serra\nDagiti automatiko a panakaserra ti IP a pagtaengan ket saan a nailista.\nKitaen ti [[Special:BlockList|listaan ti serra]] para iti listaan kadagiti agdama a naiparit a pagpataray ken dagiti serra.",
        "unblocklogentry": "lukatan ti serra ni $1",
-       "block-log-flags-anononly": "dagiti di am-ammo nga agar-aramat laeng",
+       "block-log-flags-anononly": "dagiti di ammo nga agar-aramat laeng",
        "block-log-flags-nocreate": "nabaldado ti panagpartuat ti pakabilangan",
-       "block-log-flags-noautoblock": "naiddep ti auto-serra",
-       "block-log-flags-noemail": "naserraan ti esurat",
+       "block-log-flags-noautoblock": "nabaldado ti automatiko a serra",
+       "block-log-flags-noemail": "nabaldado ti esurat",
        "block-log-flags-nousertalk": "saan a mabalin nga agurnos ti bukodna a tungtungan a panid",
-       "block-log-flags-angry-autoblock": "napabalin ti napasayaat nga auto-serra",
+       "block-log-flags-angry-autoblock": "napakabaelan ti napasayaat nga automatiko a serra",
        "block-log-flags-hiddenname": "nailemmeng ti nagan ti agar-aramat",
-       "range_block_disabled": "Ti abilidad ti administrador nga agaramid ti nasakupan a serra ket naiddep.",
+       "range_block_disabled": "Ti abilidad ti administrador nga agpartuat ti nasakupan a serra ket nabaldado.",
        "ipb_expiry_invalid": "Imbalido ti oras a panagpaso.",
        "ipb_expiry_temp": "Ti serra ti nagan ti agar-aramat ket masapul a permanente.",
-       "ipb_hide_invalid": "Saan a mapasardeng daytoy a pakabilangan; daytoy ket addaan ti ad-adu ngem {{PLURAL:$1|maysa nga inurnos|dagiti $1 nga inurnos}}.",
-       "ipb_already_blocked": " \"$1\" ket naserraan",
-       "ipb-needreblock": "$1 ket naseraan. Kayatmo a sukatan ti serrana?",
+       "ipb_hide_invalid": "Saan a mapasardeng daytoy a pakabilangan; daytoy ket addaan iti ad-adu ngem {{PLURAL:$1|maysa nga inurnos|dagiti $1 nga inurnos}}.",
+       "ipb_already_blocked": "Ni \"$1\" ket naserraanen.",
+       "ipb-needreblock": "Ni $1 ket naseraanen. Kayatmo a sukatan ti serrana?",
        "ipb-otherblocks-header": "Sabali {{PLURAL:$1|a naserraan|kadagiti naserraan}}",
        "unblock-hideuser": "Saanmo a maisubli ti serra daytoy nga agar-aramat, nailemmengen ti nagan daytoy nga agar-aramat.",
-       "ipb_cant_unblock": "Biddut: ID $1 ti serra a nabirukan. Baka nalukatan ti serranan.",
-       "ipb_blocked_as_range": "Ballag: Ti IP a pagtaengan $1 ket saan a dagus a naserraan ken saan a malukatan ti serrana.\nNgem, nupay kasta, naserran a kas paset ti sakup ti $2, a mabalin a malukatan ti serrana.",
-       "ip_range_invalid": "Imbalido a sakup ti IP.",
-       "ip_range_toolarge": "Dagiti serra a nasakup a dakdakkel ngem /$1 ket saan a maipalubos.",
+       "ipb_cant_unblock": "Biddut: San a nabirukan ti ID $1 ti serra. Mabalin a nalukatanen ti serrana.",
+       "ipb_blocked_as_range": "Biddut: Ti IP a pagtaengan ti $1 ket saan a dagus a naserraan ken saan a malukatan ti serrana.\nNgem, nupay kasta, naserran a kas paset ti sakop ti $2, a mabalin a malukatan ti serrana.",
+       "ip_range_invalid": "Imbalido a sakop ti IP.",
+       "ip_range_toolarge": "Dagiti serra a nasakop a dakdakkel ngem /$1 ket saan a maipalubos.",
        "proxyblocker": "Pannakbagi a panagserra",
-       "proxyblockreason": "Ti IP a pagtaengam ket naserraan ngamin ket daytoy ket nakalukat a panakbagi.\nPangngaasi ta kontakem ti agit-ited ti serbisio ti Internetmo wenno teknikal a suporta ti kaurnusam ken ibagam kaniada ti nakaro a parikut ti seguridad.",
-       "sorbsreason": "Ti IP a pagtaengam ket nakalista a kasla \"nalukatan a pannakbagi\" idiay DNSBL nga inusar ti {{SITNAME}}.",
-       "sorbs_create_account_reason": "Ti IP a pagtaengam ket nakalista a kasla \"nalukatan a pannakbagi\" idiay DNSBL nga inusar ti {{SITNAME}}.\nSaanka a makaaramid ti pakabilangan",
+       "proxyblockreason": "Ti IP a pagtaengam ket naserraan ngamin ket daytoy ket nakalukat a panakbagi.\nPangngaasi a kontakem ti agit-ited ti serbisio ti Internetmo wenno teknikal a suporta ti gunglom ken ibagam kaniada ti nakaro a parikut ti seguridad.",
+       "sorbsreason": "Ti IP a pagtaengam ket nailista a kasla \"nalukatan a pannakbagi\" iti DNSBL nga inusar babaen ti {{SITNAME}}.",
+       "sorbs_create_account_reason": "Ti IP a pagtaengam ket nailista a kasla \"nalukatan a pannakbagi\" iti DNSBL nga inusar babaen ti {{SITNAME}}.\nSaanka a makapartuat ti pakabilangan.",
        "xffblockreason": "Ti maysa nga IP a pagtaengan nga adda iti X-Forwarded-For header, mabalin a kukuam wenno ti pannakbagi a server nga us-usarem, ket naserraan. Ti kasisigud a rason ti pannakaserra idi ket: $1",
-       "cant-see-hidden-user": "Ti agar-aramat a kayatmo a serraan ket naserraan ken nailemmeng.\nKet awan met ti karbengam nga agilemming ti agar-aramat, saan mo a makita wenno mabaliwan ti serra ti agar-aramat.",
-       "ipbblocked": "Saanmo a mabalin ti agserra wenno agikkat ti serra ti sabali nga agar-aramat, ngamin ket naserraan ka met.",
-       "ipbnounblockself": "Saanmo a mabalin a lukatan ti serram",
+       "cant-see-hidden-user": "Ti agar-aramat a kayatmo a serraan ket naserraanen ken nailemmeng.\nGapu ta awan met ti karbengam nga agilemming ti agar-aramat, saanmo a makita wenno maurnos ti serra ti agar-aramat.",
+       "ipbblocked": "Saanmo a mabalin ti agserra wenno agikkat ti serra ti sabali nga agar-aramat, ngamin ket naserraanka met.",
+       "ipbnounblockself": "Saanmo a mabalin a lukatan ti serram.",
        "lockdb": "Balunetan ti database",
        "unlockdb": "Lukatan ti database",
-       "lockdbtext": "Ti panagserra ti database ket makaikkat ti abilidad kadagiti amin nga agar-aramat ti agurnos kadagiti panid, ti panagsukat dagiti kaykayatda, ti panagurnos dagiti bambantayanda, ken dagiti sabsabali pay a masapul ti panagsukat idiay database.\nPangngaasi a pasingkedam daytoy no kayatmo nga aramiden, ken luktam dayta database no malpas kan nga agsimpa.",
-       "unlockdbtext": "Ti panaglukat ti database ket mangipasubli ti abilidad dagiti amin nga agar-aramat ti panagurnos kadagiti panid, ti panagsukat dagiti kaykayatda, ti panagurnos dagiti bambantayanda, ken dagiti amin a makasapul ti panagsukat idiay database.\nPangngaasi a pasingkedam a daytoy no kayatmo nga aramiden.",
+       "lockdbtext": "Ti panagserra ti database ket makaikkat ti abilidad kadagiti amin nga agar-aramat ti agurnos kadagiti panid, ti panagsukat dagiti kakaykaytanda, ti panagurnos dagiti listaan ti bambantayanda, ken dagiti sabali pay a masapul ti panagsukat iti database.\nPangngaasi a pasingkedam daytoy no kayatmo nga aramiden, ken luktam dayta database no malpaskan nga agsimpa.",
+       "unlockdbtext": "Ti panaglukat ti database ket mangipasubli ti abilidad dagiti amin nga agar-aramat ti panagurnos kadagiti panid, ti panagsukat kadagiti kakaykayatanda, ti panagurnos dagiti listaan bambantayanda, ken dagiti amin a makasapul ti panagsukat iti database.\nPangngaasi a pasingkedam a daytoy no kayatmo nga aramiden.",
        "lockconfirm": "Wen, talaga a kayatko a balunetan ti database.",
        "unlockconfirm": "Wen, talaga a kayatko a balunetan ti database.",
        "lockbtn": "Balunetan ti database",
        "unlockdbsuccesssub": "Naikkaten ti balunet ti database",
        "lockdbsuccesstext": "Nabalunetan ti database.<br />\nLaglagipem nga [[Special:UnlockDB|ikkaten ti balunetna]] kalpasan a malpaska nga agsimpa.",
        "unlockdbsuccesstext": "Nalukatanen ti database.",
-       "lockfilenotwritable": "Ti serra a papeles ti database ket saan a masuratan.\nTi agserra ken aglukat iti database, masapul a masuratan ti web server.",
+       "lockfilenotwritable": "Ti papeles ti balunet ti database ket saan a masuratan.\nTapno mabalunetan ken malukatan ti database, nasken daytoy a masuratan babaen ti web server.",
        "databasenotlocked": "Saan a nabalunetan ti database.",
-       "lockedbyandtime": "(ni {{GENDER:$1|$1}} idi $2 ti oras $3)",
+       "lockedbyandtime": "(ni {{GENDER:$1|$1}} idi $2, $3)",
        "move-page": "Iyalis ti $1",
        "move-page-legend": "Iyalis ti panid",
-       "movepagetext": "Ti panagusar ti kinabuklan dita baba, ket mangnagan manen ti panid, a mangiyalis amin ti pakasaritaanna idiay baro a nagan.\nTi daan a titulo ket agbalin a baw-ing a panid idiay baro a titulo.\nMapabarom a kas automatiko dagiti baw-ing a nakatudo dita kasisigud a titulo.\nNo agpilika a saanmo a kayat, pasaraduam a kitaen ti [[Special:DoubleRedirects|doble]] wenno [[Special:BrokenRedirects|nadadael a baw-ing]].\nRenbbengmo ti mangpatalged nga amin a silpo ket agtultuloy a nakatudo iti nasken a papananda.\n\nLaglagipen a ti panid ket '''saan''' a maiyalis no addan sigud a panid iti baro a titulo, malaksid no ti kinaudi ket maysa a baw-ing ken awan ti napalabas a pakasaritaan ti panag-urnos. \nKayat a sawen daytoy a mabalinmo a suktan ti nagan ti maysa a panid manipud iti punto ti pannakasukat ti nagan no nagbiddutka, ken saan mo a mabalin a suratan manen ti addaan a panid.\n\n'''Ballaag!'''\nMabalin a maysa daytoy a nakaro ken saan a bigla a panagbaliw iti maysa a nasikat a panid;\npangngaasim a pasingkedam a maawatam ti ibunga daytoy sakbay nga agtuloyka a mangbaliw.",
-       "movepagetext-noredirectfixer": "Ti panagusar ti kinabuklan dita baba, ket panaganan ti panid, iyalis na amin ti pakasaritaan na idiay baro a nagan.\nTi daan a titulo ket agbalin baw-ing a panid idiay baro a titulo.\nPasaruduam a kitaen ti [[Special:DoubleRedirects|doble]] wenno [[Special:BrokenRedirects|nadadael a baw-ing]].\nRebbengem ti mangpatalged nga amin a panilpo ket agtultuloy a nakatudo iti nasken a papananda.\n\nLaglagipen a ti panid ket '''saan''' a maiyalis no addan sigud a panid iti baro a titulo, malaksid no awan linaonna wenno no maysa a baw-ing a panid ken awan ti panagbaliw iti pakasaritaan ti napalabas. \nKayat a sawen daytoy a mabalinmo a suktan ti nagan ti maysa a panid manipud iti punto ti pannakasukat ti nagan no nagbiddutka, ken saan mo a mabalin a suratan manen ti addaan a panid.\n\n'''Ballaag!'''\nMabalin a maysa daytoy a nakaro ken saan a bigla a panagbaliw iti maysa a nasikat a panid;\npangngaasim ta pasingkedam a maawatam ti ibunga daytoy sakbay nga agtuloyka a mangbaliw.",
-       "movepagetalktext": "Ti mainaig a tungtungan ti panid ket giddato a maiyalis a karamanna '''malaksid:'''\n*No addan sigud nga awan linaonna a tungtungan ti panid babaen ti baro a nagan, wenno\n*No ikkatem ti kur-itna ti kahon iti baba.\n\nKadagitoy a kaso, masapul nga iyalis wenno itiponmo a manual ti panid no kayatmo.",
+       "movepagetext": "Ti panagusar ti porma dita baba, ket mangnagan manen ti panid, a mangiyalis amin ti pakasaritaanna iti baro a nagan.\nTi daan a titulo ket agbalin a baw-ing a panid iti baro a titulo.\nMapabarom a kas automatiko dagiti baw-ing a nakatudo dita kasisigud a titulo.\nNo agpilika a saanmo a kayat, siguraduem a kitaen ti [[Special:DoubleRedirects|doble]] wenno [[Special:BrokenRedirects|nadadael a baw-ing]].\nRenbbengmo ti mangpatalged nga amin a silpo ket agtultuloy a nakatudo iti nasken a papananda.\n\nLaglagipen a ti panid ket <strong>saan</strong> a maiyalis no addan sigud a panid iti baro a titulo, malaksid no ti kinaudi ket maysa a baw-ing ken awan ti napalabas a pakasaritaan ti panag-urnos. \nKayat a sawen daytoy a mabalinmo a suktan ti nagan ti maysa a panid manipud iti punto ti pannakasukat ti nagan no nagbiddutka, ken saan mo a mabalin a suratan manen ti addaan a panid.\n\n<strong>Ballaag!</strong>\nMabalin a maysa daytoy a nakaro ken saan a bigla a panagbaliw iti maysa a nasikat a panid;\npangngaasim a pasingkedam a maawatam ti ibunga daytoy sakbay nga agtuloyka a mangbaliw.",
+       "movepagetext-noredirectfixer": "Ti panagusar ti kinabuklan dita baba, ket panaganan ti panid, iyalisna amin ti pakasaritaanna iti baro a nagan.\nTi daan a titulo ket agbalin baw-ing a panid idiay baro a titulo.\nPasaruduam a kitaen ti [[Special:DoubleRedirects|doble]] wenno [[Special:BrokenRedirects|nadadael a baw-ing]].\nRebbengem ti mangpatalged nga amin a silpo ket agtultuloy a nakatudo iti nasken a papananda.\n\nLaglagipen a ti panid ket <strong>saan</strong> a maiyalis no addan sigud a panid iti baro a titulo, malaksid no awan linaonna wenno no maysa a baw-ing a panid ken awan ti panagbaliw iti pakasaritaan ti napalabas. \nKayat a sawen daytoy a mabalinmo a suktan ti nagan ti maysa a panid manipud iti punto ti pannakasukat ti nagan no nagbiddutka, ken saanmo a mabalin a suratan manen ti addaan a panid.\n\n<strong>Ballaag!</strong>\nMabalin a maysa daytoy a nakaro ken saan a bigla a panagbaliw iti maysa a nasikat a panid;\npangngaasim ta pasingkedam a maawatam ti ibunga daytoy sakbay nga agtuloyka a mangbaliw.",
+       "movepagetalktext": "Ti mainaig a tungtungan ti panid ket automatikonto a maiyalis a karamanna <strong>malaksid:</strong>\n*Ti addan ti awan linaon a tungtungan ti panid babaen ti baro a nagan, wenno\n*No ikkatem ti kur-itna ti kahon iti baba.\n\nKadagitoy a kaso, masapul nga iyalis wenno manual nga itiponmo ti panid no kayatmo.",
        "movearticle": "Iyalis ti panid:",
-       "moveuserpage-warning": "'''Ballaag:''' Mangrugrugika nga agiyalis ti panid ti agar-aramat. Pangngaasi a laglapipen a ti panid ket isu laeng ti mabalin nga iyalis ken ti agar-aramat ket ''saan'' a managanan.",
+       "moveuserpage-warning": "<strong>Ballaag:</strong> Mangrugrugika nga agiyalis ti panid ti agar-aramat. Pangngaasi a laglapipen a ti panid ket isu laeng ti maiyalis ken ti agar-aramat ket <em>saanto</em> a managanan.",
        "movecategorypage-warning": "<strong>Ballaag:</strong> Mangiyal-aliskan iti panid ti kategoria. Pangngaasi a laglagipen a ti maiyalisto laeng ket ti panid ken ti aniaman a pampanid iti daan a kategoria ket <em>saanto</em> a maikategoria iti baro.",
        "movenologintext": "Masapul a nakarehistroka nga agar-aramat ken [[Special:UserLogin|nakastrek]] tapno makaiyalis iti panid.",
        "movenotallowed": "Awan ti pammalubosmo nga agiyalis kadagiti panid.",
        "movenotallowedfile": "Awan ti pammalubosmo nga agiyalis kadagiti papeles.",
-       "cant-move-user-page": "Awan ti pammalubos mo nga agiyalis kadagiti panid ti agar-aramat (malaksid kadaiti subpanid).",
-       "cant-move-to-user-page": "Awan ti pammalubos mo nga agiyalis ti panid idiay panid ti agar-aramat (malaksid kadagiti subpanid ti agar-aramat).",
+       "cant-move-user-page": "Awan ti pammalubosmo nga agiyalis kadagiti panid ti agar-aramat (malaksid kadagiti subpanid).",
+       "cant-move-to-user-page": "Awan ti pammalubosmo nga agiyalis ti panid iti panid ti agar-aramat (malaksid kadagiti subpanid ti agar-aramat).",
        "cant-move-category-page": "Awan ti pammalubosmo nga agiyalis kadagiti panid ti kategoria.",
        "cant-move-to-category-page": "Awan ti pammalubosmo nga agiyalis ti panid iti panid ti kategoria.",
        "newtitle": "Iti baro a titulo:",
-       "move-watch": "Bantayan daytoy a panid",
+       "move-watch": "Bantayan ti taudan a panid ken puntaan a panid",
        "movepagebtn": "Iyalis ti panid",
        "pagemovedsub": "Balligi ti panangiyalis",
-       "movepage-moved": "Naiyalis ti '''\"$1\" iti \"$2\"'''",
+       "movepage-moved": "<strong>Naiyalisen ti \"$1\" iti \"$2\"</strong>",
        "movepage-moved-redirect": "Napartuaten ti maysa a baw-ing.",
-       "movepage-moved-noredirect": "Ti panagaramid ti baw-ing ket napasardeng.",
-       "articleexists": "Adda panid nga adda ti kasta a nagan, wenno ti nagan a pinilim ket saan a mabalin.\nPangngaasim a mangpilika iti sabali a nagan.",
-       "cantmove-titleprotected": "Saanmo a maiyalis ti panid iti daytoy a lokasion, ngamin ket ti baro a titulo ket nasalakniban para iti panakapartuat.",
+       "movepage-moved-noredirect": "Ti pannakapartuat ti baw-ing ket napasardeng.",
+       "articleexists": "Adda panid nga adda ti kastan a nagan, wenno ti nagan a pinilim ket saan a mabalin.\nPangngaasi nga agpili ti sabali a nagan.",
+       "cantmove-titleprotected": "Saanmo a maiyalis ti panid iti daytoy a lokasion ngamin ket ti baro a titulo ket nasalakniban manipud ti pannakapartuat",
        "movetalk": "Iyalis ti mainaig a panid ti tungtungan",
-       "move-subpages": "Iyalis dagiti subpanid (aginggana ti $1)",
-       "move-talk-subpages": "Iyalis dagiti subpanid ti tungtungan ti panid (aginggana ti $1)",
-       "movepage-page-exists": "Ti panid ti $1 ket addan ken saan a mautomatiko a suratan manen.",
-       "movepage-page-moved": "Naiyalis ti panid a $1 iti $2.",
-       "movepage-page-unmoved": "Saan a maiyalis ti panid $1 iti $2.",
-       "movepage-max-pages": "Ti kaadu iti $1 a {{PLURAL:$1|panid|pampanid}} ket naiyalis ken awanen ti automatiko a maiyalis.",
+       "move-subpages": "Iyalis dagiti subpanid (aginggana iti $1)",
+       "move-talk-subpages": "Iyalis dagiti subpanid ti tungtungan ti panid (aginggana iti $1)",
+       "movepage-page-exists": "Ti panid ti $1 ket addan ken saan a mabalin nga automatiko a masuratan manen.",
+       "movepage-page-moved": "Ti panid ti $1 ket naiyalisen iti $2.",
+       "movepage-page-unmoved": "Ti panid ti $1 ket saan a maiyalis iti $2.",
+       "movepage-max-pages": "Ti kaaduan iti $1 a {{PLURAL:$1|panid|pampanid}} ket naiyalisen ken awanton ti automatiko a maiyalis.",
        "movelogpage": "Listaan ti naiyalis",
-       "movelogpagetext": "Adda dita baba ti listaan dagiti naiyalis a panid.",
+       "movelogpagetext": "Adda dita baba ti listaan dagiti amin a naiyalis a panid.",
        "movesubpage": "{{PLURAL:$1|Subpanid|Dagiti subpanid}}",
-       "movesubpagetext": "Daytoy a panid ket adda $1 {{PLURAL:$1|a subpanid|kadagiti subpanid}} a naipakita dita baba.",
+       "movesubpagetext": "Daytoy a panid ket addaan iti $1 {{PLURAL:$1|a subpanid|kadagiti subpanid}} a naipakita dita baba.",
        "movenosubpage": "Daytoy a panid ket awan ti subpanidna.",
        "movereason": "Rason:",
        "revertmove": "isubli",
        "delete_and_move": "Ikkaten ken iyalis",
-       "delete_and_move_text": "== Masapul nga ikkaten ==\nTi pangipanan ti panid ket \"[[:$1]]\" addan.\nKayatmo nga ikkaten  tapno makaiyaliska?",
+       "delete_and_move_text": "== Masapul nga ikkaten ==\nTi pangipanan ti panid ket \"[[:$1]]\" addan.\nKayatmo nga ikkaten tapno makaiyaliska?",
        "delete_and_move_confirm": "Wen, ikkaten ti panid",
-       "delete_and_move_reason": "Naikkat tapno mawayaan ti pannaka-iyalis idiay \"[[$1]]\"",
+       "delete_and_move_reason": "Naikkat tapno mawayaan ti pannaka-iyalis manipud ti \"[[$1]]\"",
        "selfmove": "Ti titulo ti taudan ken ti pangipanan ket agpadpada;\nsaanmo a maiyalis ti panid ti isu met laeng a panid.",
-       "immobile-source-namespace": "Saan a maiyalis dagiti panid idiay nagan ti espasio ti  \"$1\"",
-       "immobile-target-namespace": "Saan a maiyalis dagiti panid idiay nagan ti espasio ti \"$1\"",
+       "immobile-source-namespace": "Saan a maiyalis dagiti panid iti nagan ti espasio ti \"$1\"",
+       "immobile-target-namespace": "Saan a maiyalis dagiti panid iti nagan ti espasio ti \"$1\"",
        "immobile-target-namespace-iw": "Ti silpo nga interwiki ket saan nga umiso a puntaan para iti panagiyalis ti panid.",
        "immobile-source-page": "Saan a mabalin nga iyalis daytoy a panid.",
-       "immobile-target-page": "Saan a maiyalis iti dayata a pangipanan a titulo.",
-       "bad-target-model": "Ti kinaykayat a pangipanan ket agus-usar ti sabali a modelo ti linaon. Saan a maipabalin manipud ti $1 iti $2.",
-       "imagenocrossnamespace": "Saan a maiyalis ti papeles idiay saan a papeles a nagan ti espasio",
-       "nonfile-cannot-move-to-file": "Saan a maiyalis ti saan a papeles idiay papeles a nagan ti espasio",
-       "imagetypemismatch": "Ti baro a pagpaatiddog ti papeles ket saan nga agpada ti kitana",
+       "immobile-target-page": "Saan a maiyalis iti dayta a pangipanan a titulo.",
+       "bad-target-model": "Ti kinaykayat a pangipanan ket agus-usar ti sabali a modelo ti linaon. Saan a mapagbaliwen manipud ti $1 iti $2.",
+       "imagenocrossnamespace": "Saan a maiyalis ti papeles iti saan nagan ti espasio ti papeles",
+       "nonfile-cannot-move-to-file": "Saan a maiyalis ti saan a papeles iti nagan ti espasio ti papeles",
+       "imagetypemismatch": "Ti baro a pagpaatiddog ti papeles ket saan a maipada iti bukodna a kita",
        "imageinvalidfilename": "Ti puntaan a nagan ti papeles ket imbalido",
-       "fix-double-redirects": "Agpabaro ti amin a baw-ing a mangipatudo ti kasisigud a titulo",
+       "fix-double-redirects": "Agpabaro kadagiti aniaman a baw-ing a mangipatudo ti kasisigud a titulo",
        "move-leave-redirect": "Mangibati ti baw-ing",
-       "protectedpagemovewarning": "'''Ballaag:''' Daytoy a panid ket nasalakniban tapno dagiti laeng agar-aramat nga addaan ti gundaway nga administrador ti makaiyalis.\nTi kinaudi a naikabil ti listaan ket adda dita baba tapno mausar a reperensia:",
-       "semiprotectedpagemovewarning": "'''Pakaammo:''' Nasalakniban daytoy a panid tapno dagiti laeng nakarehistro nga agar-aramat ti makaiyalis daytoy.\nTi kinaudi a naikabil ti listaan ket adda iti baba tapno mausar a reperensia:",
-       "move-over-sharedrepo": "== Addaan ti papeles ==\n[[:$1]] addaan idiay pagbingayan a repositorio. Ti panagiyalis ti papeles iti titulo nga itoy ket paawanenna ti pagbingayan a papeles.",
-       "file-exists-sharedrepo": "Ti napilim a nagan ti papeles ket naususaren idiay pagbingayan a pagikabilan.\nPangngaasi nga agpilika ti sabali a nagan.",
+       "protectedpagemovewarning": "<strong>Balaag:</strong> Daytoy a panid ket nasalakniban tapno dagiti laeng agar-aramat nga addaan ti gundaway nga administrador ti makaiyalis.\nTi naudi a naikabil iti listaan ket naited dita baba para iti reperensia:",
+       "semiprotectedpagemovewarning": "<strong>Nota:</strong> Nasalakniban daytoy a panid tapno dagiti laeng nakarehistro nga agar-aramat ti makaiyalis daytoy.\nTi naudi a naikabil iti listaan ket naited dita baba para iti reperensia:",
+       "move-over-sharedrepo": "== Addaan ti papeles ==\nTi [[:$1]] addaan iti pagbingayan a repositorio. Ti panagiyalis ti papeles iti daytoy a titulo ket tuonenna ti pagbingayan a papeles.",
+       "file-exists-sharedrepo": "Ti napilim a nagan ti papeles ket naususaren iti pagbingayan a repositorio.\nPangngaasi nga agpilika ti sabali a nagan.",
        "export": "Agipan kadagiti panid",
        "exporttext": "Maipanmo ti testo ken pakasaritaan ti inurnos iti maysa a panid wenno pampanid a nabalkut ti XML.\nDaytoy ket mabalin a maikabil iti sabali a wiki nga agususar ti MediaWiki nga usaren ti [[Special:Import|pinagala ti panid]].\n\nTi pinagipan ti panid, ikabil ti titulo dita kahon ti testo dita baba, maysa a titulo iti maysa a linia, ken agpili ka no ti kayatmo ket ti agdama a pinagbaliw ken amin nga daan a panagbalbaliw, nga addaan ti linia ti pakasaritaan ti pampanid, wenno ti agdama a panagbaliw nga addaan ti pakaammo a maipapan ti kinaudi a panagurnos.\n\nNo iti kinaudi a kaso mabalinmo nga usaren ti silpo, a kas pagarigan [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] para iti panid \"[[{{MediaWiki:Mainpage}}]]\".",
        "exportall": "Ipan amin a pampanid",
        "exportcuronly": "Iraman laeng ti kinaudi a panagbaliw, saan a ti napno a pakasaritaan",
-       "exportnohistory": "----\n'''Palagip:''' Ti pagipapan dagiti napno a pakasaritaan dagiti panid iti daytoy a kinabuklan ket nabaldado gapu dagiti pannakalaing ti panagandar a rason.",
+       "exportnohistory": "----\n<strong>Nota:</strong> Ti pagipapan dagiti napno a pakasaritaan dagiti panid iti daytoy a kinabuklan ket nabaldado gapu dagiti pannakalaing ti panagandar a rason.",
        "exportlistauthors": "Iraman ti amin a listaan kadagiti nagaramid iti tunggal a maysa a panid",
        "export-submit": "Agipan",
-       "export-addcattext": "Agnayon kadagiti panid a naggapu idiay kategoria:",
+       "export-addcattext": "Agnayon kadagiti panid manipud ti kategoria:",
        "export-addcat": "Inayon",
-       "export-addnstext": "Nayunan dagiti panid a naggapu idiay nagan ti espasio:",
+       "export-addnstext": "Agnayon kadagiti panid manipud ti nagan ti espasio:",
        "export-addns": "Inayon",
        "export-download": "Idulin a kas papeles",
        "export-templates": "Mangiraman kadagiti plantilia",
        "allmessagesname": "Nagan",
        "allmessagesdefault": "Kasisigud a testo ti mensahe",
        "allmessagescurrent": "Agdama a testo ti mensahe",
-       "allmessagestext": "Daytoy ti listaan dagiti mensahe ti sistema a magun-od idiay MediaWiki a nagan ti espasio.\nPangngaasi a bisitaen ti [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation Lokalisasion ti MediaWiki] ken [//translatewiki.net translatewiki.net] no kayatmo ti agparawad kadagiti sapasap a panagipatarus ti MediaWiki.",
-       "allmessagesnotsupportedDB": "Saan a mausar daytoy a panid ngamin ket ti '''$wgUseDatabaseMessages''' ket nabaldado.",
+       "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 [//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-filter-legend": "Sagat",
        "allmessages-filter": "Sagaten babaen ti naipaduma a kasasaad:",
        "allmessages-filter-unmodified": "Saan a nabaliwan",
        "allmessages-filter-submit": "Inkan",
        "allmessages-filter-translate": "Ipatarus",
        "thumbnail-more": "Padakkelen",
-       "filemissing": "Napukaw ti papeles",
-       "thumbnail_error": "Biddut ti panagaramid ti bassit a ladawan: $1",
+       "filemissing": "Awan ti papeles",
+       "thumbnail_error": "Biddut ti panagpartuat ti bassit a ladawan: $1",
        "thumbnail_error_remote": "Biddut a mensahe manipud ti $1: \n$2",
-       "djvu_page_error": "Ti DjVu a panid ket saan a nasakup",
+       "djvu_page_error": "Ti DjVu a panid ket saan a masakop",
        "djvu_no_xml": "Saan a naala ti XML iti DjVu a papeles",
-       "thumbnail-temp-create": "Saan a makaaramid ti temporario a bassit a ladawan ti papeles",
+       "thumbnail-temp-create": "Saan a makapartuat ti temporario a bassit a ladawan ti papeles",
        "thumbnail-dest-create": "Saan a maidulin ti basit a ladawan idiay pagipanan",
-       "thumbnail_invalid_params": "Imbalido a parametro ti bassit a ladawan",
-       "thumbnail_dest_directory": "Saan a nakaaramid ti pangipanan a direktorio.",
-       "thumbnail_image-type": "Daytoy a kita ti ladawan ket saan a nasuportaran.",
-       "thumbnail_gd-library": "Saan a kompleto a GD biblioteka a pannakaaramid: Awan ti opisio ti $1",
-       "thumbnail_image-missing": "Daytoy a papeles ket kasla napukaw: $1",
+       "thumbnail_invalid_params": "Imbalido dagiti parametro ti bassit a ladawan",
+       "thumbnail_dest_directory": "Saan a nakapartuat ti pangipanan a direktorio.",
+       "thumbnail_image-type": "Daytoy a kita ti ladawan ket saan a nasuportaran",
+       "thumbnail_gd-library": "Saan a kompleto a konpigurasion ti biblioteka ti GD: Awan ti annong ti $1",
+       "thumbnail_image-missing": "Kasla awan daytoy a papeles: $1",
        "thumbnail_image-failure-limit": "Adu unayen dagiti nabiit a napaay a panagipadas ($1 wenno ad-adu) a panangiparamg daytoy bassit a ladawan. Pangngaasi a padasen manen intono madamdama.",
        "import": "Agala kadagiti panid",
        "importinterwiki": "Agala ti transwiki",
-       "import-interwiki-text": "Agpilika ti wiki ken titulo ti panid nga alaem.\nDagit panagbaliw a petsa ken dagiti nagan ti mannurat ket maipreserba.\nAmin a transwiki nga alaem ket mailista idiay [[Special:Log/import|listaan ti pinagala]].",
+       "import-interwiki-text": "Agpilika ti wiki ken titulo ti panid nga alaem.\nDagiti rebision ti petsa ken dagiti nagan ti mannurat ket maipreserba.\nAmin a transwiki nga alaem ket mailista iti [[Special:Log/import|listaan ti panagala]].",
        "import-interwiki-source": "Taudan ti wiki/panid:",
-       "import-interwiki-history": "Kopiaen amin dagiti bersion ti pakasaritaan daytoy a panid",
+       "import-interwiki-history": "Kopiaen amin dagiti rebision ti pakasaritaan daytoy a panid",
        "import-interwiki-templates": "Iraman amin dagiti plantilia",
        "import-interwiki-submit": "Agala",
        "import-interwiki-namespace": "Pangipanan a nagan ti espasio:",
        "import-interwiki-rootpage": "Papanan a ramut ti panid (pagpilian):",
        "import-upload-filename": "Nagan ti papeles:",
        "import-comment": "Komentario:",
-       "importtext": "Pangngaasi nga ipanmo ti papeles a naggapu iti nagtaudan a wiki nga agusar ti [[Special:Export|agipan]].",
-       "importstart": "Agal-ala dagiti panid...",
-       "import-revision-count": "$1 {{PLURAL:$1|a pinagbaliwan|kadagiti pinagbaliwan}}",
-       "importnopages": "Awan dagiti panid ti maala.",
+       "importtext": "Pangngaasi nga ipanmo ti papeles manipud ti nagtaudan a wiki nga agusar ti [[Special:Export|ramit ti panagipan]].\nIdulinmo iti bukodmo a kompiuter ken ikarga ditoy.",
+       "importstart": "Agal-ala kadagiti panid...",
+       "import-revision-count": "$1 {{PLURAL:$1|a rebision|kadagiti rebision}}",
+       "importnopages": "Awan dagiti maala a panid.",
        "imported-log-entries": "Naala ti $1 {{PLURAL:$1|a nailista|kadagiti nailista}}.",
        "importfailed": "Napaay ti panagala: <nowiki>$1</nowiki>",
-       "importunknownsource": "Di amammo a kita ti taudan ti innala",
+       "importunknownsource": "Di ammmo a kita ti taudan ti innala",
        "importcantopen": "Saan a maluktan ti innala a papeles",
        "importbadinterwiki": "Saan a nasayaat a silpo ti interwiki",
-       "importsuccess": "Nalpasen ti pinagala!",
-       "importnosources": "Awan ti innala a taudan ti transwiki ti naipalawag ken ti dagus a pakasaritaan ti pinag-ipan ket nabaldado.",
-       "importnofile": "Awan ti inalam a papeles a naipapan.",
-       "importuploaderrorsize": "Ti pinag-ipan ti innala a papeles ket napaay.\nTi papeles ket dakdakel ngem ti mabalin a kadakkel ti pang-ipan.",
-       "importuploaderrorpartial": "Ti pinag-ipan ti innala a papeles ket napaay.\nPaset laeng ti papeles ti napag-ipan.",
-       "importuploaderrortemp": "Ti pinag-ipan ti papeles ket napaay.\nAwan ti saan nga agnayon a polder.",
-       "import-parse-failure": "Napaay ti pinagala ti XML parse",
+       "importsuccess": "Nalpasen ti panagala!",
+       "importnosources": "Awan ti innala a taudan ti transwiki ti naipalawag ken ti dagus a pakasaritaan ti panagikarga ket nabaldado.",
+       "importnofile": "Awan ti innalam a papeles ti naikarga.",
+       "importuploaderrorsize": "Ti panagikarga ti innala a papeles ket napaay.\nTi papeles ket dakdakel ngem ti maipalubos a kadakkel ti maikarga.",
+       "importuploaderrorpartial": "Ti panagikarga ti innala a papeles ket napaay.\nPaset laeng ti papeles ti naikarga.",
+       "importuploaderrortemp": "Ti panagikarga ti innala a papeles ket napaay.\nAwan ti temporario a polder.",
+       "import-parse-failure": "Napaay ti panagala ti panagwaswas ti XML",
        "import-noarticle": "Awan ti panid a maaala!",
-       "import-nonewrevisions": "Awan dagiti naala panagbalbaliw (mabalin nga adda amin dagitoyen, wenno nalabsan gapu kadagiti biddut).",
+       "import-nonewrevisions": "Awan dagiti naala a rebision (mabalin nga adda amin dagitoyen, wenno nalabsan gapu kadagiti biddut).",
        "xml-error-string": "$1 iti linia $2, tukol $3 (byte $4): $5",
-       "import-upload": "Ipan ti XML data",
-       "import-token-mismatch": "Napukaw ti gimong ti datos.\nPangngaasi a padasem manen.",
-       "import-invalid-interwiki": "Saan a makaala dita naited a wiki.",
+       "import-upload": "Ikarga ti datos ti XML",
+       "import-token-mismatch": "Napukaw ti sesion ti datos.\nPangngaasi a padasen manen.",
+       "import-invalid-interwiki": "Saan a makaala manipud ti nainaganan a wiki.",
        "import-error-edit": "Ti panid ti \"$1\" ket saan a naala ngamin ket saanmo a mabalin nga urnosen.",
-       "import-error-create": "Ti panid ti \"$1\" ket saan a naala ngamin ket saanmo a mabalin nga aramiden.",
-       "import-error-interwiki": "Ti panid ti \"$1\" ket saan a naala ngamin ket ti nagan ket nailasin para iti ruar a panagsilpo (interwiki).",
-       "import-error-special": "Ti panid ti \"$1\" ket saan a naala ngamin ket bukod ti  espesial a nagan a lugar a saan nga agpalubos ti pampanid.",
-       "import-error-invalid": "Ti panid ti \"$1\" ket saan a naala ngamin ket ti nagan ket imbalido.",
-       "import-error-unserialize": "Ti panagbaliw ti $2 iti panid ti \"$1\" ket di maipagsasaruno. Ti panagbalbaliw ket naireporta idi nga agus-usar ti modelo ti $3 a naipagsasaruno a kas $4.",
-       "import-error-bad-location": "Ti panagbaliw ti $2 nga agus-usar ti modelo a linaon ti $3 ket saan a maipenpen iti \"$1\" iti daytoy a wiki, gapu ta dayta a modelo ket saan a nasuportaran iti dayta a panid.",
+       "import-error-create": "Ti panid ti \"$1\" ket saan a naala ngamin ket saanmo a mabalin a partuaten.",
+       "import-error-interwiki": "Ti panid ti \"$1\" ket saan a naala ngamin ket ti nagan ket naireserba para iti ruar a panagsilpo (interwiki).",
+       "import-error-special": "Ti panid ti \"$1\" ket saan a naala ngamin ket bukod ti espesial a nagan ti espasio ket saan nga agpalubos iti pampanid.",
+       "import-error-invalid": "Ti panid ti \"$1\" ket saan a naala ngamin ket ti naganna ket imbalido.",
+       "import-error-unserialize": "Ti rebisionn ti $2 iti panid ti \"$1\" ket di maipagsasaruno. Ti rebision ket naireporta idi nga agus-usar ti modelo ti $3 a naipagsasaruno a kas $4.",
+       "import-error-bad-location": "Ti rebision ti $2 nga agus-usar ti modelo a linaon ti $3 ket saan a maipenpen iti \"$1\" iti daytoy a wiki, gapu ta dayta a modelo ket saan a nasuportaran iti dayta a panid.",
        "import-options-wrong": "Saan a husto {{PLURAL:$2|a pagpilian|a pagpilpilian}}: <nowiki>$1</nowiki>",
        "import-rootpage-invalid": "Ti naited a ramut ti panid ket imbalido a titulo.",
-       "import-rootpage-nosubpage": "Ti nagan ti lugar ti \"$1\" iti ramut ti panid ket saan amangpalubos kadagiti apo ti panid.",
-       "importlogpage": "Alaen ti listaan",
-       "importlogpagetext": "Ti administratibo a panagala dagiti panid nga adda ti pakasaritaanna nga urnos kadagiti sabsabali a wiki.",
-       "import-logentry-upload": "innala ti [[$1]] iti papeles a pinag-ipan",
-       "import-logentry-upload-detail": "$1 {{PLURAL:$1|a pinagbaliwan|kadagiti pinagbaliwan}}",
-       "import-logentry-interwiki": "nai-transwiki ti $1",
-       "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|pinagbaliwan|dagiti pinagbaliwan}} manipud iti $2",
-       "javascripttest": "Subsubokan ti JavaScript",
-       "javascripttest-title": "Agpatpataray ti $1 a subsubokan",
-       "javascripttest-pagetext-noframework": "Daytoy a panid ket nailasin para iti panagpataray ti subsubokan a JavaScript.",
-       "javascripttest-pagetext-unknownframework": "Di amamo a pagsubsubokan a tabas \"$1\".",
-       "javascripttest-pagetext-frameworks": "Pangngaasi nga agpili ti maysa kadagiti sumaganad a pagsubokan a tabas: $1",
-       "javascripttest-pagetext-skins": "Agpili ti kudil a pangipatarayan ti pagsubokan:",
+       "import-rootpage-nosubpage": "Ti nagan ti espasio ti \"$1\" iti ramut ti panid ket saan a mangpalubos kadagiti subpanid.",
+       "importlogpage": "Listaan ti panagala",
+       "importlogpagetext": "Dagiti administratibo a panagala kadagiti panid nga addaan iti pakasaritaan ti panag-urnos manipud kadagiti sabali a wiki.",
+       "import-logentry-upload": "innala ti [[$1]] babaen ti panagikarga ti papeles",
+       "import-logentry-upload-detail": "$1 {{PLURAL:$1|a rebision|kadagiti rebision}}",
+       "import-logentry-interwiki": "nai-transwiki iti $1",
+       "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|rebision|dagiti rebision}} manipud ti $2",
+       "javascripttest": "Panagsubok ti JavaScript",
+       "javascripttest-title": "Agpatpataray kadagiti panagsubok ti $1",
+       "javascripttest-pagetext-noframework": "Daytoy a panid ket naireserba para iti panagpataray kadagiti panagsubok ti JavaScript.",
+       "javascripttest-pagetext-unknownframework": "Di ammo a tabas ti panagsubok ti \"$1\".",
+       "javascripttest-pagetext-frameworks": "Pangngaasi nga agpili ti maysa kadagiti sumaganad a tabas ti panagsubok: $1",
+       "javascripttest-pagetext-skins": "Agpili ti kudil a pangipatarayan kadagiti panagsubok:",
        "javascripttest-qunit-intro": "Kitaen ti [ $1 dukomentasion ti panagsubok] idiay mediawiki.org.",
        "javascripttest-qunit-heading": "MediaWiki JavaScript QUnit test suite",
        "tooltip-pt-userpage": "Panidmo nga agar-aramat",
-       "tooltip-pt-anonuserpage": "Ti panid ti agar-aramat daytoy nga IP a pagtaengan nga urnosem a  kasla",
-       "tooltip-pt-mytalk": "Pakitungtungam a panid",
-       "tooltip-pt-anontalk": "Pakitungtungan a maipapan ti panagurnos a naggapu ditoy nga IP a pagtaengan",
+       "tooltip-pt-anonuserpage": "Ti panid ti agar-aramat para iti daytoy nga IP a pagtaengan a kas ur-urnosem",
+       "tooltip-pt-mytalk": "Tungtungam a panid",
+       "tooltip-pt-anontalk": "Pakitungtungan a maipanggep kadagiti panagurnos manipud ti daytoy nga IP a pagtaengan",
        "tooltip-pt-preferences": "Dagiti kakaykayatam",
-       "tooltip-pt-watchlist": "Listaan dagiti panid a sipsiputem para iti panakabalbaliw",
-       "tooltip-pt-mycontris": "Listaan dagiti inaramidmo",
+       "tooltip-pt-watchlist": "Listaan dagiti panid a sipsiputem para iti pannakabalbaliw",
+       "tooltip-pt-mycontris": "Ti listaan dagiti kontribusionmo",
        "tooltip-pt-login": "Maisingasing a sumrekka; nupay kasta, daytoy ket saan a maipapilit",
        "tooltip-pt-logout": "Rummuar",
        "tooltip-ca-talk": "Pagtungtungan a maipapan ti linaon ti panid",
        "tooltip-ca-edit": "Mabalinmo nga urnosen daytoy a panid. Pangngaasi nga aramatem ti buton ti panagipadas sakbay nga agidulin",
        "tooltip-ca-addsection": "Mangirugi ti baro a paset",
        "tooltip-ca-viewsource": "Nasalakniban daytoy a panid.\nMabalinmo a kitaen ti taudanna.",
-       "tooltip-ca-history": "Dagiti napalabas a panagbalbaliw iti daytoy a panid.",
+       "tooltip-ca-history": "Dagiti napalabas a rebision iti daytoy a panid.",
        "tooltip-ca-protect": "Salakniban daytoy a panid",
        "tooltip-ca-unprotect": "Sukatan ti salaknib daytoy a panid",
        "tooltip-ca-delete": "Ikkaten daytoy a panid",
-       "tooltip-ca-undelete": "Isubli dagiti inurnos ti daytoy a panid sakbay idi naikkat",
+       "tooltip-ca-undelete": "Isubli dagiti inurnos a naaramid iti daytoy a panid sakbay idi naikkat",
        "tooltip-ca-move": "Iyalis daytoy a panid",
-       "tooltip-ca-watch": "Inayon daytoy a panid kadagiti bambantayam",
-       "tooltip-ca-unwatch": "Ikkatem daytoy a panid kadagiti bambantayam",
-       "tooltip-search": "Biruken idiay {{SITENAME}}",
+       "tooltip-ca-watch": "Inayon daytoy a panid iti listaan ti bambantayam",
+       "tooltip-ca-unwatch": "Ikkaten daytoy a panid manipud ti listan ti bambantayam",
+       "tooltip-search": "Agbiruk iti {{SITENAME}}",
        "tooltip-search-go": "Inka idiay panid nga adda kastoy a naganna no adda",
        "tooltip-search-fulltext": "Biruken dagiti panid para iti daytoy a testo",
        "tooltip-p-logo": "Sarungkaran ti umuna a panid",
        "tooltip-n-mainpage": "Sarungkaran ti umuna a panid",
        "tooltip-n-mainpage-description": "Sarungkaran ti umuna a panid",
-       "tooltip-n-portal": "Maipapan ti gandat, ti aniaman a maaramidam, no sadino ti pagbirukam kadagiti banbanag",
-       "tooltip-n-currentevents": "Agsapul iti lugar ti likud a pakaammo kadagiti agdama a paspasamak",
-       "tooltip-n-recentchanges": "Listaan dagiti naudi a sinukatan iti wiki.",
-       "tooltip-n-randompage": "Mangiparuar iti pugto a panid",
+       "tooltip-n-portal": "Maipapan ti gandat, ti aniaman a maaramidmo, no sadino ti pagbirukam kadagiti banbanag",
+       "tooltip-n-currentevents": "Agsapul ti pakaammo kadagiti agdama a paspasamak",
+       "tooltip-n-recentchanges": "Listaan dagiti naudi a sinukatan iti wiki",
+       "tooltip-n-randompage": "Agikarga iti pugto a panid",
        "tooltip-n-help": "Ti lugar a pagsapulan",
-       "tooltip-t-whatlinkshere": "Listaan ti am-amin a pampanid ti wiki a nakasilpo ditoy",
-       "tooltip-t-recentchangeslinked": "Kinaudian a sinukatan  dagiti panid a nakasilpo ditoy a panid",
+       "tooltip-t-whatlinkshere": "Listaan ti amin a pampanid ti wiki a nakasilpo ditoy",
+       "tooltip-t-recentchangeslinked": "Kaudian a balbaliw kadagiti panid a naisilpo manipud ti daytoy a panid",
        "tooltip-feed-rss": "RSS a pakan para iti daytoy a panid",
        "tooltip-feed-atom": "Atom a pakan para iti daytoy a panid",
-       "tooltip-t-contributions": "Kitaen ti listaan dagiti naaramid daytoy nga agar-aramat",
+       "tooltip-t-contributions": "Ti lstaan dagiti kontribusion iti daytoy nga agar-aramat",
        "tooltip-t-emailuser": "Patulodan ti esurat daytoy nga agar-aramat",
-       "tooltip-t-upload": "Agipan iti papeles",
+       "tooltip-t-upload": "Agikarga kadagiti papeles",
        "tooltip-t-specialpages": "Listaan ti amin nga espesial a pampanid",
-       "tooltip-t-print": "Maimaldit a bersion ti panid",
-       "tooltip-t-permalink": "Agnanayon a silpo ti daytoy a panagbaliw ti panid",
+       "tooltip-t-print": "Maimaldit a bersion iti daytoy a panid",
+       "tooltip-t-permalink": "Permanente a silpo iti daytoy a rebision ti panid",
        "tooltip-ca-nstab-main": "Kitaen ti naglaon a panid",
        "tooltip-ca-nstab-user": "Kitaen ti panid ti agar-aramat",
        "tooltip-ca-nstab-media": "Kitaen ti panid ti midia",
-       "tooltip-ca-nstab-special": "Maysa daytoy nga espesial a panid, saanmo a mismo a maurnos daytoy a panid",
+       "tooltip-ca-nstab-special": "Daytoy ket espesial a panid, saanmo a mismo a maurnos daytoy a panid",
        "tooltip-ca-nstab-project": "Kitaen ti panid ti gandat",
        "tooltip-ca-nstab-image": "Kitaen ti panid ti papeles",
        "tooltip-ca-nstab-mediawiki": "Kitaen ti mensahe ti sistema",
        "tooltip-ca-nstab-category": "Kitaen ti panid ti kategoria",
        "tooltip-minoredit": "Markaan daytoy a kas bassit a panag-urnos",
        "tooltip-save": "Idulin dagiti sinukatam",
-       "tooltip-preview": "Ipadas dagiti sinukatam, pangngaasim nga usarem daytoy sakbay nga idulinmo ti panid!",
+       "tooltip-preview": "Ipadas dagiti sinukatam, pangngaasi nga usarem daytoy sakbay nga idulin ti panid!",
        "tooltip-diff": "Ipakita no ania dagiti sinukatan nga inaramidmo iti testo",
-       "tooltip-compareselectedversions": "Kitaen ti naggidiatan dagiti dua a napili a bersion ti daytoy a panid.",
-       "tooltip-watch": "Inayon daytoy a panid idiay listaan dagiti bambantayam",
+       "tooltip-compareselectedversions": "Kitaen ti naggidiatan dagiti dua a napili a bersion iti daytoy a panid.",
+       "tooltip-watch": "Inayon daytoy a panid iti listaan ti bambantayam",
        "tooltip-watchlistedit-normal-submit": "Ikkaten dagiti titulo",
        "tooltip-watchlistedit-raw-submit": "Pabaruen ti listaan ti bambantayan",
-       "tooltip-recreate": "Aramidem manen ti panid urayno dati a naikkat.",
-       "tooltip-upload": "Rugian ti agip-ipan",
-       "tooltip-rollback": "\"Baliktaden\"   isubli ti inurnos (dagiti inurnos) ti daytoy a panid ti kinaudi a nangaramid iti maysa a takla",
-       "tooltip-undo": "\"Ibabawi\" ipasubli daytoy nga urnos ken lukatanna ti kinabuklan ti urnos iti panagpadas. Agpabalin daytoy a mangikabil ti rason idiay pinakabuklan.",
+       "tooltip-recreate": "Partuaten manen ti panid urayno dati a naikkat.",
+       "tooltip-upload": "Irugi ti panagikarga",
+       "tooltip-rollback": "\"Baliktaden\"  isubli ti inurnos (dagiti inurnos) iti daytoy a panid iti naudi a kontributor iti maysa a pindut",
+       "tooltip-undo": "\"Ibabawi\" ipasubli daytoy nga urnos ken lukatanna ti porma ti pagurnosan iti panagpadas a moda. Mangpalubos daytoy ti agikabil ti rason iti pakabuklan.",
        "tooltip-preferences-save": "Idulin dagiti kakaykayatam",
-       "tooltip-summary": "Ikabil ti bassit a pakabuklan",
-       "anonymous": "Di am-ammo {{PLURAL:$1|nga agar-aramat|kadagiti agar-aramat}} iti {{SITENAME}}",
+       "tooltip-summary": "Agikabil ti bassit a pakabuklan",
+       "anonymous": "Di ammo {{PLURAL:$1|nga agar-aramat|kadagiti agar-aramat}} iti {{SITENAME}}",
        "siteuser": "{{SITENAME}} nga agar-aramat $1",
-       "anonuser": "{{SITENAME}} di amammo nga agar-aramat $1",
-       "lastmodifiedatby": "Daytoy a panid ket naudi a binalbaliwan idi $2, $1 ni $3.",
+       "anonuser": "{{SITENAME}} di ammo nga agar-aramat $1",
+       "lastmodifiedatby": "Daytoy a panid ket naudi a nabaliwan idi $2, $1 babaen ni $3.",
        "othercontribs": "Naibasar iti obra ni $1.",
        "others": "dadduma pay",
        "siteusers": "{{SITENAME}}  {{PLURAL:$2|agar-aramat|dagiti agar-aramat}}  $1",
-       "anonusers": "{{SITENAME}} di am-ammo {{PLURAL:$2|nga agar-aramat|a digiti agar-aramat}} $1",
-       "creditspage": "Dagiti pagdaydayaw ti panid",
-       "nocredits": "Awan dagiti pakaammo ti pammadayaw nga adda ditoy a panid.",
-       "spamprotectiontitle": "Panagsalaknib a sagat  para ti spam",
-       "spamprotectiontext": "Ti testo a kayatmo nga idulin ket sinerraan ti sagat ti spam.\nDaytoy ket mabalin a gapuanan babaen ti silpo a naiparit ti akin ruar a pagsaadan.",
-       "spamprotectionmatch": "Ti sumaganad a testo ti nangirugi ti sagat ti spam: $1",
-       "spambot_username": "Panagdalus iti MediaWiki spam",
-       "spam_reverting": "Ipasubli ti kinaudi a panagbaliw nga awan dagiti linaon a silpo idiay $1",
-       "spam_blanking": "Dagiti amin a panagbaliw ket aglaon kadagiti silpo idiay $1, iblanko",
-       "spam_deleting": "Dagiti amin a panagbaliw ket naglaon kadagiti silpo idiay $1, ik-ikkaten",
-       "simpleantispam-label": "Kontra-spam a panagkita.\n '''Saan''' a suratan daytoy!",
+       "anonusers": "{{SITENAME}} di ammo {{PLURAL:$2|nga agar-aramat|a digiti agar-aramat}} $1",
+       "creditspage": "Dagiti pammadayaw ti panid",
+       "nocredits": "Awan dagiti pakaammo ti pammadayaw a magun-od para iti daytoy a panid.",
+       "spamprotectiontitle": "Panagsalaknib a sagat para iti spam",
+       "spamprotectiontext": "Ti testo a kayatmo nga idulin ket sinerraan babaen ti sagat ti spam.\nDaytoy ket mabalin a gapuanan babaen ti silpo a naiparit ti akin ruar a sitio.",
+       "spamprotectionmatch": "Ti sumaganad a testo ket isu ti nangkalbit ti sagat ti spam: $1",
+       "spambot_username": "Panagdalus iti spam ti MediaWiki",
+       "spam_reverting": "Ipasubli ti naudi a rebision nga awan dagiti linaon a silpo iti $1",
+       "spam_blanking": "Amin dagiti rebision ket aglaon kadagiti silpo iti $1, iblanko",
+       "spam_deleting": "Amin dagiti rebision ket aglaon kadagiti silpo iti $1, ik-ikkaten",
+       "simpleantispam-label": "Pammasingked ti anti-spam.\n<strong>SAAN</strong> a kargaan daytoy!",
        "pageinfo-title": "Pakaammo para iti \"$1\"",
-       "pageinfo-not-current": "Pasensia, saan a mabalin ti mangited ti pakaammo para kadagiti daan a panagbalbaliw.",
+       "pageinfo-not-current": "Pasensia, saan a mabalin ti mangited ti pakaammo para kadagiti daan a rebision.",
        "pageinfo-header-basic": "Kangrunaan a pakaammo",
        "pageinfo-header-edits": "Pakasaritaan ti inurnos",
        "pageinfo-header-restrictions": "Panagsalaknib ti panid",
        "pageinfo-redirects-name": "Bilang dagiti baw-ing iti daytoy a panid",
        "pageinfo-subpages-name": "Bilang dagiti subpanid iti daytoy a panid",
        "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|baw-ing|bawbaw-ing}}; $3 {{PLURAL:$3|saan a baw-ing|saan a bawbaw-ing}})",
-       "pageinfo-firstuser": "Nagpartuat ti panid",
+       "pageinfo-firstuser": "Nagpartuat iti panid",
        "pageinfo-firsttime": "Petsa a pannakapartuat ti panid",
-       "pageinfo-lastuser": "Kinaudi a nagurnos",
+       "pageinfo-lastuser": "Kinaudi nga editor",
        "pageinfo-lasttime": "Petsa ti kinaudi a panag-urnos",
        "pageinfo-edits": "Dagup a bilang dagiti inurnos",
        "pageinfo-authors": "Dagup a bilang dagiti naisangsangayan a mannurat",
        "pageinfo-templates": "Nailak-am {{PLURAL:$1|a plantilia|a planplantilia}} ($1)",
        "pageinfo-transclusions": "{{PLURAL:$1|Panid|Pampanid}} a nakailak-aman ($1)",
        "pageinfo-toolboxlink": "Pakaammo ti panid",
-       "pageinfo-redirectsto": "Maibaw-ing idiay",
+       "pageinfo-redirectsto": "Maibaw-ing iti",
        "pageinfo-redirectsto-info": "pakaammo",
        "pageinfo-contentpage": "Naibilang a kas naglaon a panid",
        "pageinfo-contentpage-yes": "Wen",
        "pageinfo-protect-cascading": "Dagiti panagsalaknib ket agsariap manipud ditoy",
        "pageinfo-protect-cascading-yes": "Wen",
-       "pageinfo-protect-cascading-from": "Dagiti panagsalaknib ket agsariap manipud idiay",
+       "pageinfo-protect-cascading-from": "Dagiti panagsalaknib ket agsariap manipud ti",
        "pageinfo-category-info": "Pakaammo ti kategoria",
        "pageinfo-category-pages": "Bilang dagiti panid",
        "pageinfo-category-subcats": "Bilang dagiti subkategoria",
        "markaspatrolleddiff": "Markaan a kas napatruliaan",
        "markaspatrolledtext": "Markaan daytoy a panid a kas napatruliaan",
        "markedaspatrolled": "Markaan a kas napatruliaan",
-       "markedaspatrolledtext": "Ti napili a panagbaliw iti [[:$1]] ket namarkaan a kas napatrulian.",
-       "rcpatroldisabled": "Nabaldado ti panagpatrulia kadagiti kinaudi a pinagbaliw",
-       "rcpatroldisabledtext": "Dagiti langa a patrulia ti kinaudi a pinagbaliw ket agdama a nabaldado",
+       "markedaspatrolledtext": "Ti napili a rebision iti [[:$1]] ket namarkaan a kas napatrulian.",
+       "rcpatroldisabled": "Nabaldado ti panagpatrulia iti kaudian balbaliw",
+       "rcpatroldisabledtext": "Dagiti langa ti patrulia iti kaudian a balbaliw ket agdama a nabaldado.",
        "markedaspatrollederror": "Madi a mamarkaan a kas napatruliaan",
        "markedaspatrollederrortext": "Nasken a naganam ti maysa a rebision tapno mamarkaan a kas napatruliaan.",
        "markedaspatrollederror-noautopatrol": "Saanmo a mabalin a markaan dagita sinukatam a kas napatruliaan.",
-       "markedaspatrollednotify": "Daytoy a panagbaliw ti $1 ket namarkaanen a kas napatruliaan.",
+       "markedaspatrollednotify": "Daytoy a panagbaliw iti $1 ket namarkaanen a kas napatruliaan.",
        "markedaspatrollederrornotify": "Ti panagmarka a kas napatruliaan ket napaay.",
        "patrol-log-page": "Listaan ti napatruliaan",
-       "patrol-log-header": "Daytoy ket listaan dagiti napatruliaan a panagbabaliw.",
+       "patrol-log-header": "Daytoy ket listaan dagiti napatruliaan a rebision.",
        "log-show-hide-patrol": "$1 listaan ti napatruliaan",
-       "deletedrevision": "Naikkat ti daan a binaliwan $1",
+       "deletedrevision": "Naikkat a daan a rebision ti $1",
        "filedeleteerror-short": "Biddut ti panakaikkat ti papeles: $1",
        "filedeleteerror-long": "Adda nasarakan a biddut idi agikikkat ti papeles:\n\n$1",
-       "filedelete-missing": "Ti papeles \"$1\" ket saan a maikkat, ngamin ket awanen dita.",
-       "filedelete-old-unregistered": "Ti nainagan a pinagbaliw ti papeles \"$1\" ket awan idiay database.",
-       "filedelete-current-unregistered": "Ti nainagan a papeles \"$1\" ket awan idiay database.",
-       "filedelete-archive-read-only": "Ti pagidulinan a direktorio \"$1\" ket saan a masuratan ti webserver.",
-       "previousdiff": "← Napalabas a naurnos",
-       "nextdiff": "Sumaruno a naurnos →",
-       "mediawarning": "'''Ballaag'': Daytoy a papeles ket naglaon ti dakes a kodigo.\nNo usarem daytoy, baka makompromiso ti sistema.",
-       "imagemaxsize": "Ti patingga a kadakkel ti papeles:<br />''(para dagiti pagpalpalawag ti papeles a panid)''",
+       "filedelete-missing": "Ti papeles ti \"$1\" ket saan a maikkat, ngamin ket awanen dita.",
+       "filedelete-old-unregistered": "Ti nainagan a rebison ti papeles ti \"$1\" ket awan iti database.",
+       "filedelete-current-unregistered": "Ti nainagan a papeles ti \"$1\" ket awan iti database.",
+       "filedelete-archive-read-only": "Ti arkibo a direktorio ti \"$1\" ket saan a masuratan babaen ti webserver.",
+       "previousdiff": "← Nadadaan nga urnos",
+       "nextdiff": "Barbaro nga urnos →",
+       "mediawarning": "<strong>Ballaag:</strong> Daytoy a papeles ket naglaon ti dakes a kodigo.\nNo usarem daytoy, baka makompromiso ti sistema.",
+       "imagemaxsize": "Ti patingga a kadakkel ti papeles:<br /><em>(para kadagiti panid ti deskripsion ti papeles)</em>",
        "thumbsize": "Rukod ti bassit a ladawan:",
        "widthheightpage": "$1 × $2, $3 a {{PLURAL:$3|panid|pampanid}}",
        "file-info": "kadakkel ti papeles: $1, MIME a kita: $2",
        "show-big-image-other": "Sabali {{PLURAL:$2|a resolusion|kadagiti resolusion}}: $1.",
        "show-big-image-size": "$1 × $2 dagiti piksel",
        "file-info-gif-looped": "nasiluan",
-       "file-info-gif-frames": "$1 {{PLURAL:$1|a kuadro| kadagiti kuadro}}",
+       "file-info-gif-frames": "$1 {{PLURAL:$1|a kuadro|a kuadkuadro}}",
        "file-info-png-looped": "nasiluan",
        "file-info-png-repeat": "inay-ayam ti $1 {{PLURAL:$1|a beses|a besbeses}}",
-       "file-info-png-frames": "$1 {{PLURAL:$1|a kuadro| kadagiti kuadro}}",
-       "file-no-thumb-animation": "'''Paammo: Gapu kadagiti teknikal a pannakaipatingga, dagiti bassit a ladawan ti daytoy a papeles ket saanto a maanimado.'''",
-       "file-no-thumb-animation-gif": "'''Paammo: Gapu kadagiti teknikal a pannakaipatingga, dagiti bassit a ladawan ti nangato a resolusion dagiti GIF a ladawan a kas daytoy ket saanto a maanimado.'''",
-       "newimages": "Galeria dagiti kabarbaro a papeles",
-       "imagelisttext": "Adda dita baba ti listaan ti ''$1''' {{PLURAL:$1|a papeles|dagiti papeles}} a nailasin a kas $2.",
-       "newimages-summary": "Daytoy nga espesial a panid ket ipakitana ti kinaudi a pinag-ipan kadagiti papeles.",
+       "file-info-png-frames": "$1 {{PLURAL:$1|a kuadro| a kuadkuadro}}",
+       "file-no-thumb-animation": "<strong>Nota: Gapu kadagiti teknikal a pannakaipatingga, dagiti bassit a ladawan iti daytoy a papeles ket saanto a maanimado.</strong>",
+       "file-no-thumb-animation-gif": "<strong>Nota: Gapu kadagiti teknikal a pannakaipatingga, dagiti bassit a ladawan ti nangato a resolusion dagiti GIF a ladawan a kas daytoy ket saanto a maanimado.</strong>",
+       "newimages": "Galeria dagiti baro a papeles",
+       "imagelisttext": "Adda dita baba ti listaan ti <strong>$1</strong> {{PLURAL:$1|a papeles|a pappapeles}} a nailasin a kas $2.",
+       "newimages-summary": "Daytoy nga espesial a panid ket ipakitana ti naudi a panagikarga kadagiti papeles.",
        "newimages-legend": "Sagat",
-       "newimages-label": "Nagan ti papeles (wenno paset na) :",
+       "newimages-label": "Nagan ti papeles (wenno pasetna) :",
        "newimages-showbots": "Ipakita dagiti naikarga babaen dagiti bot",
        "noimages": "Awan ti makita.",
        "ilsubmit": "Biruken",
        "bydate": "babaen ti petsa",
-       "sp-newimages-showfrom": "Iparang dagiti baro a papeles mangrugi iti $2, $1",
-       "seconds": "{{PLURAL:$1|$1 segundo|$1 segundo}}",
-       "minutes": "{{PLURAL:$1|$1 minuto|$1 minutos}}",
+       "sp-newimages-showfrom": "Iparang dagiti baro a papeles a mangrugi manipud idi $2, $1",
+       "seconds": "{{PLURAL:$1|$1 a segundo|$1 a segsegundo}}",
+       "minutes": "{{PLURAL:$1|$1 a minuto|$1 a minminuto}}",
        "hours": "{{PLURAL:$1|$1 nga oras|$1 nga or-oras}}",
        "days": "{{PLURAL:$1|$1 nga aldaw|$1 nga al-aldaw}}",
        "weeks": "{{PLURAL:$1|$1 a lawas|$1 a law-lawas}}",
        "months": "{{PLURAL:$1|$1 a bulan|$1 a bulbulan}}",
        "years": "{{PLURAL:$1|$1 a tawen|$1 a tawtawen}}",
-       "ago": "$1 nagtapos",
+       "ago": "nagtapos idi $1",
        "just-now": "tatta laeng",
-       "hours-ago": "$1 nga {{PLURAL:$1|oras|or-oras}} ti napalabas",
-       "minutes-ago": "$1 a {{PLURAL:$1|minuto|minutos}} ti napalabas",
-       "seconds-ago": "$1 a {{PLURAL:$1|segundo|seg-segundo}} ti napalabas",
-       "monday-at": "Lunes idiay $1",
-       "tuesday-at": "Martes idiay $1",
-       "wednesday-at": "Mierkoles idiay $1",
-       "thursday-at": "Huebes idiay $1",
-       "friday-at": "Biernes idiay $1",
-       "saturday-at": "Sabado idiay $1",
-       "sunday-at": "Dominggo idiay $1",
-       "yesterday-at": "Idi kalman idiay $1",
-       "bad_image_list": "Ti kinabuklan ket kas iti sumaganad:\n\nDagiti laeng banag iti listaan (linlinia a mangrugi iti *) ti mabalin.\nTi umuna a silpo iti maysa a linia ket nasken a nakasilpo iti maysa a saan a nasayaat a papeles.\nAnia man a sumarsaruno a silsilpo iti isu met laeng a linia ket maikonsidera kas mailaksid, kas pagarigan, dagiti panid a pakasarakan ti papeles a kas nakalinia.",
+       "hours-ago": "$1 nga {{PLURAL:$1|oras|or-oras}} ti nagtapos",
+       "minutes-ago": "$1 a {{PLURAL:$1|minuto|minminuto}} ti nagtapos",
+       "seconds-ago": "$1 a {{PLURAL:$1|segundo|segsegundo}} ti nagtapos",
+       "monday-at": "Lunes iti $1",
+       "tuesday-at": "Martes iti $1",
+       "wednesday-at": "Mierkoles iti $1",
+       "thursday-at": "Huebes iti $1",
+       "friday-at": "Biernes iti $1",
+       "saturday-at": "Sabado iti $1",
+       "sunday-at": "Domingo iti $1",
+       "yesterday-at": "Idi kalman iti $1",
+       "bad_image_list": "Ti pormat ket kas iti sumaganad:\n\nDagiti laeng banag iti listaan (linlinia a mangrugi iti *) ti mabalin.\nTi umuna a silpo iti maysa a linia ket nasken a nakasilpo iti maysa a saan a nasayaat a papeles.\nAnia man a sumarsaruno a silsilpo iti isu met laeng a linia ket maikonsidera kas mailaksid, kas pagarigan, dagiti panid a pakasarakan ti papeles a kas nakalinia.",
        "metadata": "Metadata",
        "metadata-help": "Daytoy a papeles ket naglaon ti naipatinayon a pakaammo, a mabalin a nainayon manipud ti dihital a kamera wenno skanner a naaramat a pangpartuat wenno pang-digitize itoy.\nNo ti papeles ket saan a nabalbaliwan manipud iti kasisigud a kasasaad, adda dagiti sumagmamano a salaysay a mabalin a saan a napno a maipakita ti nabaliwan a papeles.",
        "metadata-expand": "Ipakita dagiti napaatiddog a salaysay",
        "exif-orientation": "Pagturongan",
        "exif-samplesperpixel": "Bilang dagiti komponente",
        "exif-planarconfiguration": "Pannaka-urnos ti datos",
-       "exif-ycbcrsubsampling": "Subsampling ratio ti Y iti C",
+       "exif-ycbcrsubsampling": "Subwadan pannakaibagi ti Y iti C",
        "exif-ycbcrpositioning": "Y ken C a panakaipatakderan",
        "exif-xresolution": "Horisontal a resolusion",
-       "exif-yresolution": "nakatakder a resolusion",
-       "exif-stripoffsets": "Lokasion ti datos ti imahen",
-       "exif-rowsperstrip": "Bilang ti ar-aray tunggal maysa a strip",
-       "exif-stripbytecounts": "Bytes per compressed strip",
-       "exif-jpeginterchangeformat": "Offset to JPEG SOI",
-       "exif-jpeginterchangeformatlength": "Bytes ti JPEG a datos",
-       "exif-whitepoint": "White point chromaticity",
-       "exif-primarychromaticities": "Chromaticities dagiti primarities",
-       "exif-referenceblackwhite": "Reperensia a kuwenta iti agparis a nangisit ken puraw",
+       "exif-yresolution": "Bertikal a resolusion",
+       "exif-stripoffsets": "Lokasion ti datos ti ladawan",
+       "exif-rowsperstrip": "Bilang ti ar-aray tunggal maysa a pirgis",
+       "exif-stripbytecounts": "Dagiti byte tunggal maysa a natalmegan  a pirgis",
+       "exif-jpeginterchangeformat": "Timbengan iti JPEG SOI",
+       "exif-jpeginterchangeformatlength": "Dagiti byte ti datos ti JPEG",
+       "exif-whitepoint": "Kromatisidad ti puntos ti puraw",
+       "exif-primarychromaticities": "Dagiti kromasidad dagiti primaridad",
+       "exif-referenceblackwhite": "Reperensia a patpateg iti agparis a nangisit ken puraw",
        "exif-datetime": "Panagsukat ti papeles ti petsa ken oras",
-       "exif-imagedescription": "Titulo ti imahen",
+       "exif-imagedescription": "Titulo ti ladawan",
        "exif-make": "Nangpartuat iti kamera",
        "exif-model": "Modelo ti kamera",
-       "exif-software": "Naaramat a software",
+       "exif-software": "Naaramat a sopwer",
        "exif-artist": "Mannurat",
-       "exif-copyright": "Nakatengngel iti kaberngan ti kopia",
-       "exif-exifversion": "Exif a bersion",
-       "exif-flashpixversion": "Nasuportaran a Flashpix a bersion",
-       "exif-colorspace": "Kolor ti lugar",
-       "exif-componentsconfiguration": "Ti kayat a saoen ti tunggal maysa a nagyan",
-       "exif-compressedbitsperpixel": "Moda ti kompresion ti imahen",
-       "exif-pixelydimension": "Kaaba ti imahen",
-       "exif-pixelxdimension": "Katayag ti imahen",
+       "exif-copyright": "Nakatengngel iti karbengan ti kopia",
+       "exif-exifversion": "Bersion ti Exif",
+       "exif-flashpixversion": "Nasuportaran a bersion ti Flashpix",
+       "exif-colorspace": "Espasio ti maris",
+       "exif-componentsconfiguration": "Kaibuksilan iti tunggal maysa a komponente",
+       "exif-compressedbitsperpixel": "Moda ti kompresion ti ladawan",
+       "exif-pixelydimension": "Kaakaba ti ladawan",
+       "exif-pixelxdimension": "Katayag ti ladawan",
        "exif-usercomment": "Dagiti komentario ti agar-aramat",
-       "exif-relatedsoundfile": "Mainaig nga nangnangeg a papeles",
-       "exif-datetimeoriginal": "Petsa ken oras ti panakaaramid ti datos",
-       "exif-datetimedigitized": "Petsa ken oras ti panang-digitizing",
+       "exif-relatedsoundfile": "Mainaig a papeles ti audio",
+       "exif-datetimeoriginal": "Petsa ken oras ti pannakaaramid ti datos",
+       "exif-datetimedigitized": "Petsa ken oras ti panang-dihitado",
        "exif-subsectime": "DateTime subseconds",
        "exif-subsectimeoriginal": "DateTimeOriginal subseconds",
        "exif-subsectimedigitized": "DateTimeDigitized subseconds",
        "exif-gpstrackref": "Reperensia iti direksion ti panaggunay",
        "exif-gpstrack": "Direksion ti kuti",
        "exif-gpsimgdirectionref": "Reperensia iti direksion ti imahen",
-       "exif-gpsimgdirection": "Direksion ti imahen",
-       "exif-gpsmapdatum": "Naaramat a geodetic survey data",
-       "exif-gpsdestlatituderef": "Reperensia iti latitude a papanan",
-       "exif-gpsdestlatitude": "Latitude ti papanan",
-       "exif-gpsdestlongituderef": "Reperensia iti longitude a papanan",
-       "exif-gpsdestlongitude": "Longitude ti papanan",
+       "exif-gpsimgdirection": "Direksion ti ladawan",
+       "exif-gpsmapdatum": "Datos nga inaramat ti geodetiko a panagsukimat",
+       "exif-gpsdestlatituderef": "Reperensia iti papanan a latitud",
+       "exif-gpsdestlatitude": "Papanan a latitud",
+       "exif-gpsdestlongituderef": "Reperensia iti papanan a longitud",
+       "exif-gpsdestlongitude": "Papanan a longitud",
        "exif-gpsdestbearingref": "Reperensia iti dalan a papanan",
        "exif-gpsdestbearing": "Dalan ti papanan",
        "exif-gpsdestdistanceref": "Reperensia ti kaadayo  ti papanan",
-       "exif-gpsdestdistance": "Kaadayo iti papanan na",
-       "exif-gpsprocessingmethod": "Nagan ti kastoy a pinagaramid ti GPS",
-       "exif-gpsareainformation": "Nagan ti GPS area",
+       "exif-gpsdestdistance": "Kaadayo iti papanan",
+       "exif-gpsprocessingmethod": "Nagan ti panagproseo a pamay-an ti GPS",
+       "exif-gpsareainformation": "Nagan ti lugar ti GPS",
        "exif-gpsdatestamp": "Petsa ti GPS",
-       "exif-gpsdifferential": "Nasimpa apaggiddiatan ti GPS",
-       "exif-jpegfilecomment": "Komento ti JPEG a papeles",
-       "exif-keywords": "Nangnangruna a bal-balikas",
-       "exif-worldregioncreated": "Ti parte ti lubong nga nakaalaan ti litrato",
-       "exif-countrycreated": "Ti pagilian nga nakaalaan ti litrato",
-       "exif-countrycodecreated": "Kodigo ti pagilian nga nakaalaan ti litrato",
-       "exif-provinceorstatecreated": "Probinsia wenno estado nga nakaalaan ti litrato",
-       "exif-citycreated": "Ti siudad nga nakaalaan ti litrato",
+       "exif-gpsdifferential": "Nasimpa a paggiddiatan ti GPS",
+       "exif-jpegfilecomment": "Komentario ti papeles ti JPEG",
+       "exif-keywords": "Nangruna a balbalikas",
+       "exif-worldregioncreated": "Rehion ti lubong a nakaalaan ti retrato",
+       "exif-countrycreated": "Pagilian a nakaalaan ti retrato",
+       "exif-countrycodecreated": "Kodigo ti pagilian a nakaalaan ti retrato",
+       "exif-provinceorstatecreated": "Probinsia wenno estado a nakaalaan ti retrato",
+       "exif-citycreated": "Siudad a nakaalaan ti retrato",
        "exif-sublocationcreated": "Sabali pay a lokasion ti siudad a nakaalaan ti retrato",
-       "exif-worldregiondest": "Paset ti lubong a naipakita",
+       "exif-worldregiondest": "Rehion ti lubong a naipakita",
        "exif-countrydest": "Naipakita a pagilian",
-       "exif-countrycodedest": "Kodigo ti pagilian a naipakita",
+       "exif-countrycodedest": "Kodigo para ti pagilian a naipakita",
        "exif-provinceorstatedest": "Probinsia wenno estado a naipakita",
        "exif-citydest": "Naipakita a siudad",
-       "exif-sublocationdest": "Sabali pay a lokasion ti siudad a naipakita",
-       "exif-objectname": "Pandek a titulo",
+       "exif-sublocationdest": "Sublokasion ti siudad a naipakita",
+       "exif-objectname": "Ababa a titulo",
        "exif-specialinstructions": "Kangrunaan a panagipalpalawag",
        "exif-headline": "Paulo",
        "exif-credit": "Pammadayaw/Nangted",
        "exif-source": "Taudan",
-       "exif-editstatus": "Panagurnos a kasasaad ti imahen",
+       "exif-editstatus": "Panagurnos a kasasaad ti ladawan",
        "exif-urgency": "Ganat",
        "exif-fixtureidentifier": "Nagan ti naikabit a banag",
        "exif-locationdest": "Lugar a naibaga",
        "exif-iimversion": "Bersion ti IIM",
        "exif-iimcategory": "Kategoria",
        "exif-iimsupplementalcategory": "Dagiti sabali pay a kategoria",
-       "exif-datetimeexpires": "Saan nga usaren ti kallabes nga",
+       "exif-datetimeexpires": "Saan nga usaren kalpasanna",
        "exif-datetimereleased": "Nakairuar idi",
-       "exif-originaltransmissionref": "Kinasigud a pinagipatulod iti kodigo ti papanan",
-       "exif-identifier": "Panagilasin",
+       "exif-originaltransmissionref": "Kasisigud a transmision ti kodigo ti lokasion",
+       "exif-identifier": "Panangilasin",
        "exif-lens": "Lente nga inusar",
        "exif-serialnumber": "Agsasaruno a numero ti kamera",
        "exif-cameraownername": "Akinkukua ti kamera",
        "exif-label": "Etiketa",
        "exif-datetimemetadata": "Petsa ti kinaudi a panagbaliw ti metadata",
-       "exif-nickname": "Di pormal a nagan ti imahen",
-       "exif-rating": "Pategan (ti maysa kadagiti  5)",
-       "exif-rightscertificate": "Paneknek ti panagtaripatu dagiti karbengan",
-       "exif-copyrighted": "Kasasaad ti karbengan-panagipablaak",
-       "exif-copyrightowner": "Akinkukua ti kaberngan-pinagipablaak",
-       "exif-usageterms": "Panag-uasar a ban-banag",
-       "exif-webstatement": "Sarita ti insao ti karbengan ti kopia nga addan ti online",
-       "exif-originaldocumentid": "Naisangsangyan nga ID iti kinasigud a dokumento",
-       "exif-licenseurl": "URL iti ti karbengan ti kopia a lisensia",
+       "exif-nickname": "Di pormal a nagan ti ladwan",
+       "exif-rating": "Pategan (ti maysa kadagiti 5)",
+       "exif-rightscertificate": "Sertipikado ti panagtaripato kadagiti karbengan",
+       "exif-copyrighted": "Kasasaad ti karbengan ti kopia",
+       "exif-copyrightowner": "Akinkukua ti karbengan ti kopia",
+       "exif-usageterms": "Dagiti termino ti panag-usar",
+       "exif-webstatement": "Insasao ti karbengan ti kopia nga addaan iti online",
+       "exif-originaldocumentid": "Naisangayan nga ID iti kinasigud a dokumento",
+       "exif-licenseurl": "URL para iti lisensia ti karbengan ti kopia",
        "exif-morepermissionsurl": "Sabali a pakaammo ti lisensia",
-       "exif-attributionurl": "No usaren manen daytoy nga obra, pangngaasi nga agisilpo idiay",
-       "exif-preferredattributionname": "No usaren manen daytoy nga obra, pangngaasi a padayawen ni",
-       "exif-pngfilecomment": "Komentario ti PNG a papeles",
+       "exif-attributionurl": "No usaren manen daytoy nga obra, pangngaasi nga isilpo iti",
+       "exif-preferredattributionname": "No usaren manen daytoy nga obra, pangngaasi a padayawan ni",
+       "exif-pngfilecomment": "Komentario ti papeles ti PNG",
        "exif-disclaimer": "Renunsia",
-       "exif-contentwarning": "Ballaag ti nagyan",
-       "exif-giffilecomment": "Komentario ti GIF a papeles",
+       "exif-contentwarning": "Ballaag ti linaon",
+       "exif-giffilecomment": "Komentario ti papeles ti GIF",
        "exif-intellectualgenre": "Kita ti banag",
        "exif-subjectnewscode": "Kodigo ti suheto",
-       "exif-scenecode": "Buya ti kodigo nga IPTC",
-       "exif-event": "Paspasamak a naibaga",
-       "exif-organisationinimage": "Kaurnusan a naibaga",
-       "exif-personinimage": "Ti tao a naibaga",
-       "exif-originalimageheight": "Kangato ti imahen sakbay nga naputed",
-       "exif-originalimagewidth": "Kalawa ti imahen sakbay nga naputed",
+       "exif-scenecode": "Buya ti kodigo ti IPTC",
+       "exif-event": "Pasamak a naibaga",
+       "exif-organisationinimage": "Gunglo a naibaga",
+       "exif-personinimage": "Tao a naibaga",
+       "exif-originalimageheight": "Katayag ti ladawan sakbay a naputed",
+       "exif-originalimagewidth": "Kaakaba ti ladawan sakbay a naputed",
        "exif-compression-1": "Saan a napespes",
-       "exif-copyrighted-true": "Nakarbengan a kopia",
-       "exif-copyrighted-false": "Saan a naiyasentar ti kasasaad ti karbengan ti kopia",
+       "exif-copyrighted-true": "Nakarbengan ti kopia",
+       "exif-copyrighted-false": "Saan a naisaad ti kasasaad ti karbengan ti kopia",
        "exif-unknowndate": "Di ammo a petsa",
        "exif-orientation-1": "Kadawyan",
-       "exif-orientation-2": "Binaliktad a nagilad",
+       "exif-orientation-2": "Horisontal a binaliktad",
        "exif-orientation-3": "Naipusipus iti 180°",
-       "exif-orientation-4": "Binaliktad nga agpangato",
-       "exif-orientation-5": "Naipisipus iti 90° CCW ken nabaliktad nga agtindek",
+       "exif-orientation-4": "Bertikal a binaliktad",
+       "exif-orientation-5": "Naipisipus iti 90° CCW ken bertikal a binaliktad",
        "exif-orientation-6": "Naipusipus iti 90° CCW",
-       "exif-orientation-7": "Naipisipus iti 90° CW ken nabaliktad nga agtindek",
+       "exif-orientation-7": "Naipisipus iti 90° CW ken bertikal a nabaliktad",
        "exif-orientation-8": "Naipusipus iti 90° CW",
        "exif-planarconfiguration-1": "chunky format",
        "exif-planarconfiguration-2": "planar format",
        "exif-exposureprogram-0": "Saan a naipalpalawag",
        "exif-exposureprogram-1": "Manual",
        "exif-exposureprogram-2": "Kadawyan a programa",
-       "exif-exposureprogram-3": "Aperture priority",
+       "exif-exposureprogram-3": "Prioridad ti apertura",
        "exif-exposureprogram-4": "Shutter priority",
        "exif-exposureprogram-5": "Kreatibo a programa (di nalinteg iti  kauneg ti pagikabilan)",
        "exif-exposureprogram-6": "Aktion a programa (di nalinteg iti kapartak ti napardas a shutter)",
-       "exif-exposureprogram-7": "Retrato a kita (para iti naasideg nga imahen nga addaan ti lugar ti likud a saan a nai-focus)",
-       "exif-exposureprogram-8": "Ladawan ti daga a kita (para iti ladawan ti daga nga imahen nga addaan ti lugar ti likud a pinag- focus)",
-       "exif-subjectdistance-value": "$1 a metro",
-       "exif-meteringmode-0": "Di am-ammo",
-       "exif-meteringmode-1": "Napipia",
+       "exif-exposureprogram-7": "Retrato a kita (para iti asideg a ladladawan nga addaan ti lugar ti likud a saan a naipatengnga)",
+       "exif-exposureprogram-8": "Moda ti ladawan ti daga (para iti ladawan ti daga a retato nga addaan ti lugar ti likud a panaptengna)",
+       "exif-subjectdistance-value": "$1 a metmetro",
+       "exif-meteringmode-0": "Di ammo",
+       "exif-meteringmode-1": "Natimbeng",
        "exif-meteringmode-2": "Napipia nga agtennga a pinadagsenan",
        "exif-meteringmode-3": "Disso",
        "exif-meteringmode-4": "Sabsabali a disso",
-       "exif-meteringmode-5": "Alagad",
+       "exif-meteringmode-5": "Tabas",
        "exif-meteringmode-6": "Sangkapaset laeng",
        "exif-meteringmode-255": "Sabali",
        "exif-lightsource-0": "Di ammo",
        "scarytranscludefailed": "[Napaay ti panagala ti plantilia para iti $1]",
        "scarytranscludefailed-httpstatus": "[Napaay ti panagala ti plantilia para iti $1: HTTP $2]",
        "scarytranscludetoolong": "[Atiddog unay ti URL]",
-       "deletedwhileediting": "'''Ballaag''': Naikkaten daytoy a panid kalpasan a rinugiam nga agurnos!",
+       "deletedwhileediting": "<strong>Ballaag:</strong> Naikkaten daytoy a panid kalpasan idi rinugiam ti agurnos!",
        "confirmrecreate": "Ti ([[User talk:$1|patungtungan]]) ti agar-aramat [[User:$1|$1]] ket inikkatna daytoy a panid kalpasan ti panagrugim nga agurnos nga adda rason:\n: ''$2''\nPangngaasi a pasingkedam nga agpayso a kayatmo a partuten manen daytoy a panid.",
        "confirmrecreate-noreason": "Ti ([[User talk:$1|patungtungan]]) ti agar-aramat [[User:$1|$1]] ket inikkat na daytoy a panid idi kalkalpas mo a magirugi ti agurnos. Pangngaasi ta pasingkedam a kayatmo nga aramiden manen daytoy a panid.",
        "recreate": "Partuaten manen",
-       "confirm_purge_button": "OK",
+       "confirm_purge_button": "Sige",
        "confirm-purge-top": "Dalusan ti cache daytoy a panid?",
-       "confirm-purge-bottom": "Ti panagpurga ti panid ket dalusanna ti cache ken pursaranna nga agparang dagiti kinaudi a panagbaliw.",
-       "confirm-watch-button": "OK",
-       "confirm-watch-top": "Inayon daytoy a panid kadagiti bambantayam",
-       "confirm-unwatch-button": "OK",
-       "confirm-unwatch-top": "Ikkatem daytoy a panid ti bambantayam",
+       "confirm-purge-bottom": "Ti panagpurga ti panid ket dalusanna ti cache ken pursaranna nga iparang dagiti agdama rebision.",
+       "confirm-watch-button": "Sige",
+       "confirm-watch-top": "Inayon daytoy a panid iti listaan ti bambantayam?",
+       "confirm-unwatch-button": "Sige",
+       "confirm-unwatch-top": "Ikkatem daytoy a panid manipud ti listaan ti bambantayam?",
        "imgmultipageprev": "← napalabas a panid",
        "imgmultipagenext": "sumaruno a panid →",
        "imgmultigo": "Inkan!",
        "table_pager_prev": "Napalabas a panid",
        "table_pager_first": "Umuna a panid",
        "table_pager_last": "Maudi a panid",
-       "table_pager_limit": "Mangipakita iti $1 a banag tunggal maysa  a panid",
+       "table_pager_limit": "Mangipakita iti $1 a banag tunggal maysa a panid",
        "table_pager_limit_label": "Banag tunggal maysa a panid:",
        "table_pager_limit_submit": "Inkan",
        "table_pager_empty": "Awan dagiti nagbanagan",
        "autosumm-blank": "Naikkat amin ti linaon ti panid",
-       "autosumm-replace": "Sinukatan ti linaon iti '$1'",
+       "autosumm-replace": "Sinukatan ti linaon iti \"$1\"",
        "autoredircomment": "Naibaw-ing ti panid iti [[$1]]",
        "autosumm-new": "Pinartuat ti panid iti \"$1\"",
-       "lag-warn-normal": "Dagiti panangbalbaliw a nabarbaro ngem $1 {{PLURAL:$1|a segundo|kadagiti segundo}} ket mabalin a saan a maiparang itoy a listaan.",
-       "lag-warn-high": "Gapu ti kinabuntog ti database server, dagiti nasukatan a barbaro ngem $1 {{PLURAL:$1|a segundo|kadagiti segundo}} ket mabalin a saan nga agparang ditoy a listaan.",
-       "watchlistedit-normal-title": "Urnosem ti listaan ti bambantayan",
+       "lag-warn-normal": "Dagiti panangbalbaliw a nabarbaro ngem $1 {{PLURAL:$1|a segundo|a segsegundo}} ket mabalin a saan a maiparang iti daytoy a listaan.",
+       "lag-warn-high": "Gapu ti kinabuntog ti database server, dagiti nasukatan a barbaro ngem $1 {{PLURAL:$1|a segundo|a segegundo}} ket mabalin a saan nga agparang iti daytoy a listaan.",
+       "watchlistedit-normal-title": "Urnosen ti listaan ti bambantayan",
        "watchlistedit-normal-legend": "Ikkaten dagiti titulo manipud ti listaan ti bambantayam",
-       "watchlistedit-normal-explain": "Dagiti titulo ti listaan ti bambantayam ket naipakita dita baba.\nTi mangikkat ti titulo, ikur-it ti kaaripingna a kahon, ken agtakla ti \"{{int:Watchlistedit-normal-submit}}\".\nMabalinmo pay nga [[Special:EditWatchlist/raw|urnosen ti kilaw a listaan]].",
+       "watchlistedit-normal-explain": "Dagiti titulo ti listaan ti bambantayam ket naipakita dita baba.\nTi mangikkat ti titulo, ikur-it ti kaaripingna a kahon, ken pinduten ti \"{{int:Watchlistedit-normal-submit}}\".\nMabalinmo pay nga [[Special:EditWatchlist/raw|urnosen ti naata a listaan]].",
        "watchlistedit-normal-submit": "Ikkaten dagiti titulo",
-       "watchlistedit-normal-done": "{{PLURAL:$1|1 ti titulo a|$1 dagiti titulo a}} naikkat iti listaan ti bambantayam:",
-       "watchlistedit-raw-title": "Urnosen ti kilaw a listaan ti bambantayan",
-       "watchlistedit-raw-legend": "Urnosen ti kilaw a listaan ti bambantayan",
-       "watchlistedit-raw-explain": "Dagiti titulo ti listaan ti bambantayam ket naipakita dita baba, ken mabaliwam nga urnosen babaen ti panagnayon ken panagkissay manipud ti listaan;\nmaysa a titulo tunggal maysa a linia.\nNo malpaska, itakla ti \"{{int:Watchlistedit-raw-submit}}\".\nMabalinmo pay nga [[Special:EditWatchlist|usaren ti dati a panagurnos]].",
+       "watchlistedit-normal-done": "{{PLURAL:$1|1 ti titulo|$1 dagiti titulo}} a naikkat manipud ti listaan ti bambantayam:",
+       "watchlistedit-raw-title": "Urnosen ti naata a listaan ti bambantayan",
+       "watchlistedit-raw-legend": "Urnosen ti naata a listaan ti bambantayan",
+       "watchlistedit-raw-explain": "Dagiti titulo ti listaan ti bambantayam ket naipakita dita baba, ken mabaliwam nga urnosen babaen ti panagnayon ken panagkissay manipud ti listaan;\nmaysa a titulo tunggal maysa a linia.\nNo malpaska, pinduten ti \"{{int:Watchlistedit-raw-submit}}\".\nMabalinmo pay nga [[Special:EditWatchlist|usaren ti pagalagadan nga editor]].",
        "watchlistedit-raw-titles": "Dagiti titulo:",
        "watchlistedit-raw-submit": "Pabaruen ti listaan ti bambantayan",
-       "watchlistedit-raw-done": "Napabaro ti listaan ti bambantayam.",
-       "watchlistedit-raw-added": "{{PLURAL:$1|1 a titulo ti|dagiti $1 a titulo ti}} nainayon:",
-       "watchlistedit-raw-removed": "{{PLURAL:$1|1 a titulo ti|dagiti $1 dagiti titulo ti}} naikkat:",
+       "watchlistedit-raw-done": "Napabaron ti listaan ti bambantayam.",
+       "watchlistedit-raw-added": "{{PLURAL:$1|1 a titulo|$1 kadagiti titulo}} ti nainayon:",
+       "watchlistedit-raw-removed": "{{PLURAL:$1|1 a titulo|$1 kadagiti titulo}} ti naikkat:",
        "watchlistedit-clear-title": "Nadalusanen ti listaan ti bambantayan",
        "watchlistedit-clear-legend": "Dalusan ti listaan ti bambantayan",
-       "watchlistedit-clear-explain": "Amin dagiti titulo ket maikkatto manipud ti listaan ti bambantayam.",
+       "watchlistedit-clear-explain": "Amin dagiti titulo ket maikkatto manipud ti listaan ti bambantayam",
        "watchlistedit-clear-titles": "Dagiti titulo:",
        "watchlistedit-clear-submit": "Dalusan ti listaan ti bambantayan (Daytoy ket permanente!)",
        "watchlistedit-clear-done": "Nadalusanen ti bambantayam.",
        "watchlisttools-clear": "Dalusan ti listaan ti bambantayan",
        "watchlisttools-view": "Kitaen dagiti maitunos a sinukatan",
        "watchlisttools-edit": "Kitaen ken urnosen ti listaan ti bambantayan",
-       "watchlisttools-raw": "Urnosen ti kilaw a listaan ti bambantayan",
+       "watchlisttools-raw": "Urnosen ti naata a listaan ti bambantayan",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|tungtungan]])",
-       "unknown_extension_tag": "Di ammo a pagpaatiddog nga etiketa \"$1\"",
-       "duplicate-defaultsort": "'''Ballaag:''' Kinasigud a panagilasin ti \"$2\" ket sukatanna ti immuna a kinasigud a panagilasin \"$1\".",
+       "unknown_extension_tag": "Di ammo a pagpaatiddog nga etiketa ti \"$1\"",
+       "duplicate-defaultsort": "<strong>Ballag:</strong> Kasisigud a panagilasin ti \"$2\" ket tuonana ti immuna a kasisigud a panagilasin ti \"$1\".",
+       "duplicate-displaytitle": "<strong>Ballaag:</strong> Ti maiparang a titulo ti \"$2\" ket tuonanna ti immmuna a maiparang a titulo ti \"$1\".",
        "version": "Bersion",
        "version-extensions": "Dagiti naisaad a pagpaatiddog",
+       "version-skins": "Naisaad a kudkudil",
        "version-specialpages": "Espesial a pampanid",
        "version-parserhooks": "Dagiti parser a kawit",
        "version-variables": "Nadumaduma a kita",
-       "version-antispam": "Pawilan ti spam",
-       "version-skins": "Dagiti Kudil",
+       "version-antispam": "Panagpawil iti spam",
        "version-other": "Sabali",
-       "version-mediahandlers": "Agtengtengngel kadagiti midia",
+       "version-mediahandlers": "Panagtengngel kadagiti midia",
        "version-hooks": "Dagiti kawit",
-       "version-parser-extensiontags": "Dagiti parser a pagpaatiddog nga etiketa",
-       "version-parser-function-hooks": "Parser a pamay-an dagiti kawit",
+       "version-parser-extensiontags": "Dagiti etiketa ti pagpaatiddog ti parser",
+       "version-parser-function-hooks": "Dagiti kawit nga annong ti parser",
        "version-hook-name": "Nagan ti kawit",
        "version-hook-subscribedby": "Umanamong babaen ti",
        "version-version": "($1)",
+       "version-no-ext-name": "[awan nagan]",
        "version-license": "Lisensia ti MediaWiki",
        "version-ext-license": "Lisensia",
        "version-ext-colheader-name": "Pagpaatiddog",
+       "version-skin-colheader-name": "Kudil",
        "version-ext-colheader-version": "Bersion",
        "version-ext-colheader-license": "Lisensia",
        "version-ext-colheader-description": "Deskripsion",
        "version-license-not-found": "Awan ti nabirukan a naisalaysay a pakaammo ti lisensia para iti daytoy a pagpaatiddog.",
        "version-credits-title": "Dagiti pammadayaw para iti $1",
        "version-credits-not-found": "Awan dagiti nabirukan a naisalaysay a pammadayaw para iti daytoy a pagpaatiddog.",
-       "version-poweredby-credits": "Daytoy a wiki ket pinaandar ti '''[https://www.mediawiki.org/ MediaWiki]''', karbengan a kopia © 2001-$1 $2.",
+       "version-poweredby-credits": "Daytoy a wiki ket pinaandar babaen ti '''[https://www.mediawiki.org/ MediaWiki]''', karbengan ti kopia © 2001-$1 $2.",
        "version-poweredby-others": "dadduma pay",
-       "version-poweredby-translators": "agipatpatarus ti translatewiki.net",
-       "version-credits-summary": "Kayatmi koma a pammadayawan dagiti sumaganad a tao para kadagiti inparawadda iti [[Special:Version|MediaWiki]].",
-       "version-license-info": "Ti MediaWiki ket nawaya a sopwer; maiwarasmo ken/wenno mabaliwam babaen ti banag iti GNU General Public License a naipablaak babaen ti Free Software Foundation; nupay iti bersion 2 iti Lisensia, wenno (ti panagpilim) ti  aniaman a bersion.\n\nTi MediaWiki ket naiwarwaras nga adda ti namnama a makatulong, ngem AWAN TI ANIA MAN A GARANTIA; nga awan pay ti naibagbaga a PANAKAILAKO wenno KALAINGAN NA ITI DAYTOY A PANGGEP. Kitaen ti GNU Sapasap a Publiko a Lisensia para kadagiti adu pay a salaysay.\n\nNaka-awatka koman ti [{{SERVER}}{{SCRIPTPATH}}/COPYING kopia iti GNU Sapasap a  Publiko a Lisensia] a nairaman iti daytoy a programa; no saan, agsuratka idiay Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA wenno [//www.gnu.org/licenses/old-licenses/gpl-2.0.html basaem idiay online].",
+       "version-poweredby-translators": "dagiti agipatpatarus ti translatewiki.net",
+       "version-credits-summary": "Kayatmi koma a pammadayawan dagiti sumaganad a tao para kadagiti kontribusonda iti [[Special:Version|MediaWiki]].",
+       "version-license-info": "Ti MediaWiki ket nawaya a sopwer; mabalinmo nga iwaras ken/wenno baliwan babaen kadagiti termino ti GNU General Public License a naipablaak babaen ti Free Software Foundation; wenno bersion 2 iti Lisensia, wenno (ti panagpilim) ti  aniaman a naudi a bersion.\n\nTi MediaWiki ket naiwarwaras iti namnama a makatulongto, ngem AWAN TI ANIA MAN A GARANTIA; nga awan pay ti naibagbaga a PANNAKAILAKO wenno KALAINGANNA ITI DAYTOY A PANGGEP. Kitaen ti GNU General Public License para kadagiti adu pay a salaysay.\n\nNaka-awatka koman ti [{{SERVER}}{{SCRIPTPATH}}/COPYING kopia iti GNU General Public License] a nairaman iti daytoy a programa; no saan, agsuratka idiay Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA wenno [//www.gnu.org/licenses/old-licenses/gpl-2.0.html basaem iti online].",
        "version-software": "Naisaad a sopwer",
        "version-software-product": "Produkto",
        "version-software-version": "Bersion",
        "version-entrypoints": "Pagserrekan a puntos dagiti URL",
        "version-entrypoints-header-entrypoint": "Pagserrekan a puntos",
        "version-entrypoints-header-url": "URL",
-       "redirect": "Ibaw-ing babaen ti papeles, agar-aramat, panid wenno ID ti panagbaliw",
+       "redirect": "Ibaw-ing babaen ti papeles, agar-aramat, panid wenno ID ti rebision",
        "redirect-legend": "Ibaw-ing iti papeles wenno panid",
-       "redirect-summary": "Daytoy nga espesial a panid ket maibaw-ing iti papeles (iti nagan ti papeles), ti panid (iti ID wenno panid ti panagbaliw), wenno ti panid ti agar-aramat (iti numeriko nga ID ti agar-aramat). Panag-usar:\n[[{{#Special:Redirect}}/file/Example.jpg]], \n[[{{#Special:Redirect}}/page/64308]], \n[[{{#Special:Redirect}}/revision/328429]], wenno\n[[{{#Special:Redirect}}/user/101]].",
+       "redirect-summary": "Daytoy nga espesial a panid ket maibaw-ing iti papeles (iti nagan ti papeles), ti panid (iti ID ti rebision wenno ID ti panid), wenno ti panid ti agar-aramat (iti numeriko nga ID ti agar-aramat). Panag-usar:\n[[{{#Special:Redirect}}/file/Example.jpg]], \n[[{{#Special:Redirect}}/page/64308]], \n[[{{#Special:Redirect}}/revision/328429]], wenno\n[[{{#Special:Redirect}}/user/101]].",
        "redirect-submit": "Inkan",
        "redirect-lookup": "Kitaen:",
        "redirect-value": "Pateg:",
        "redirect-user": "ID ti agar-aramat",
        "redirect-page": "ID ti panid",
-       "redirect-revision": "Panagbaliw ti panid",
+       "redirect-revision": "Rebision ti panid",
        "redirect-file": "Nagan ti papeles",
        "redirect-not-exists": "Saan a nabirukan ti pateg",
        "fileduplicatesearch": "Agbiruk kadagiti duplikado a papeles",
-       "fileduplicatesearch-summary": "Agbiruk kadagiti duplikado a papeles a naibatay kadagiti \"hash\" a pateg.",
-       "fileduplicatesearch-legend": "Agsapul iti duplikado",
+       "fileduplicatesearch-summary": "Agbiruk kadagiti duplikado a papeles a naibatay kadagiti pateg ti hash.",
+       "fileduplicatesearch-legend": "Agbiruk para iti duplikado",
        "fileduplicatesearch-filename": "Nagan ti papeles:",
        "fileduplicatesearch-submit": "Biruken",
-       "fileduplicatesearch-info": "$1 × $2 pixel<br />Rukod ti papeles: $3<br />Kita ti MIME: $4",
-       "fileduplicatesearch-result-1": "Awan ti kapadpadana a duplikado ti papeles a \"$1\".",
-       "fileduplicatesearch-result-n": "Ti papeles a \"$1\" ket addaan {{PLURAL:$2|1 nga agpadpada a duplikado|dagiti $2  nga agpadpada a duplikado}}.",
-       "fileduplicatesearch-noresults": "Awan ti nagan ti papeles a \"$1\" ti nabirukan.",
+       "fileduplicatesearch-info": "$1 × $2 a piksel<br />Rukod ti papeles: $3<br />Kita ti MIME: $4",
+       "fileduplicatesearch-result-1": "Awan ti kapadpadana a duplikado ti papeles ti \"$1\".",
+       "fileduplicatesearch-result-n": "Ti papeles ti \"$1\" ket addaan {{PLURAL:$2|iti 1 nga agpadpada a duplikado|kadagiti $2 nga agpadpada a duplikado}}.",
+       "fileduplicatesearch-noresults": "Awan ti nabirukan a papeles a nanaganan ti \"$1\".",
        "specialpages": "Espesial a pampanid",
        "specialpages-note-top": "Leyenda",
        "specialpages-note": "* Kadawyan nga espesial a pampanid.\n* <span class=\"mw-specialpagerestricted\">Nagawidan nga espesial a pampanid.</span>",
-       "specialpages-group-maintenance": "Dagiti padamag ti panagtaripato",
-       "specialpages-group-other": "Sabsabali pay nga espesial a pampanid",
-       "specialpages-group-login": "Sumrek / agaramid ti pakabilangan",
-       "specialpages-group-changes": "Kaudian a sinukatan ken listaan",
-       "specialpages-group-media": "Dagiti padamag ti midia ken panag-ipan",
+       "specialpages-group-maintenance": "Dagiti reporta ti panagtaripato",
+       "specialpages-group-other": "Sabali nga espesial a pampanid",
+       "specialpages-group-login": "Sumrek / agpartuat ti pakabilangan",
+       "specialpages-group-changes": "Kaudian a balbaliw ken lislistaan",
+       "specialpages-group-media": "Dagiti reporta ti midia ken dagiti panagikarga",
        "specialpages-group-users": "Dagiti agar-aramat ken karkarbengan",
-       "specialpages-group-highuse": "Adu ti pannaka-usar a pampanid",
-       "specialpages-group-pages": "Listaan dagiti panid",
+       "specialpages-group-highuse": "Adu ti pannakausar a pampanid",
+       "specialpages-group-pages": "Lislistaan ti pampanid",
        "specialpages-group-pagetools": "Ramramit ti panid",
        "specialpages-group-wiki": "Datos ken ramramit",
        "specialpages-group-redirects": "Panangibaw-ing kadagiti espesial a pampanid",
        "blankpage": "Blanko a panid",
        "intentionallyblankpage": "Daytoy a panid  ket naigagara a blanko.",
        "external_image_whitelist": " #Baybayan daytoy a linia a kastoy<pre>\n#Ikabil ti \"regular expression fragments\" (idiay laeng paset nga ikabil ti tengnga ti  //) dita baba\n#Dagitoy ipada na ti URLs ti ruar (ti napudot a naikapet) imahen \n#Dagiti agpada ket agparang nga  imahen, ket no saan ti panilpo ti imahen ti agparang laeng\n#Dagiti linia nga umuna iti # ket maipabalin a komentario\n#Daytoy ket \"sensetibo ti kadakkel ti letra\"\n\n#Ikabil dagita \"regex fragment\" ti ngato daytoy a linia. Baybay-an a kastoy daytoy a linia</pre>",
-       "tags": "Umisu a sukatan dagiti etiketa",
-       "tag-filter": "[[Special:Tags|Ti etiketa]] a sagat:",
+       "tags": "Dagiti etiketa ti umiso a panagbaliw",
+       "tag-filter": "Sagat ti [[Special:Tags|etiketa]]:",
        "tag-filter-submit": "Sagat",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Etiketa|Et-etiketa}}]]: $2)",
        "tags-title": "Dagiti etiketa",
-       "tags-intro": "Daytoy a panid ket ilistana dagiti etiketa nga usaren ti sopwer nga agmarka ti panag-urnos, ken dagiti kaibuksilanda.",
+       "tags-intro": "Daytoy a panid ket ilistana dagiti etiketa a mablin nga usaren ti sopwer a mangmarka iti urnos, ken dagiti kaibuksilanda.",
        "tags-tag": "Nagan ti etiketa",
        "tags-display-header": "Tabas dagiti listaan ti panagsukat",
-       "tags-description-header": "Napno a panangipalpalawag iti kayatna a saoen.",
+       "tags-description-header": "Napno a deskripsion ti kaibuksilan.",
        "tags-active-header": "Aktibo?",
-       "tags-hitcount-header": "Dagiti etiketa a sinukatan",
+       "tags-hitcount-header": "Dagiti adda etiketana a sinukatan",
        "tags-active-yes": "Wen",
        "tags-active-no": "Saan",
        "tags-edit": "urnosen",
-       "tags-hitcount": "$1 {{PLURAL:$1|a sinukatan|kadagiti sinukatan}}",
+       "tags-hitcount": "$1 {{PLURAL:$1|a sinukatan|a sinuksukatan}}",
        "comparepages": "Ipada dagiti panid",
        "compare-page1": "Panid 1",
        "compare-page2": "Panid 2",
-       "compare-rev1": "Panagbaliw 1",
-       "compare-rev2": "Panagbaliw 2",
+       "compare-rev1": "Rebision 1",
+       "compare-rev2": "Rebision 2",
        "compare-submit": "Ipada",
-       "compare-invalid-title": "Ti titulo nga intedmo ket imbalido.",
-       "compare-title-not-exists": "Awan met dayta titulo a nainaganam.",
-       "compare-revision-not-exists": "Awan met ti pinagbaliw dayta titulo a nainaganam.",
-       "dberr-problems": "Pasensian a! Daytoy a pagsaadan ket agdadama ti teknikal a pagrigrigatan.",
-       "dberr-again": "Padasem ti agururay to manu a minutos ken agikarga.",
-       "dberr-info": "(Saan a makontak ti database server: $1)",
-       "dberr-info-hidden": "(Saan a makontak ti database server)",
-       "dberr-usegoogle": "Padasem  ti agbiruk idiay Google tatta.",
-       "dberr-outofdate": "Palagip a dagiti listaan da kadagiti kukuami a nagyan ket baka nagpaso.",
+       "compare-invalid-title": "Ti titulo nga innaganam ket imbalido.",
+       "compare-title-not-exists": "Awan ti innaganam a titulo.",
+       "compare-revision-not-exists": "Awan ti innaganam a rebision.",
+       "dberr-problems": "Pasensia! Daytoy a sitio ket agdadama nga agsansanay kadagiti teknikal a pagrigatan.",
+       "dberr-again": "Padasem ti aguray kadagiti mano a minuto ken agikarga manen.",
+       "dberr-info": "(Saan a makontak ti server ti database: $1)",
+       "dberr-info-hidden": "(Saan a makontak ti server ti database)",
+       "dberr-usegoogle": "Iti agdama mabalinmo a padasen ti agbiruk babaen ti Google.",
+       "dberr-outofdate": "Palagip a dagiti listaanda kadagiti kukuami a linaon ket mabalin a nagpaso.",
        "dberr-cachederror": "Daytoy ket naidulin a kopia ti kiniddawmo a panid, ken mabalin a saan a kabarbaro.",
-       "htmlform-invalid-input": "Adda pakirut kadagiti inkabilmo",
-       "htmlform-select-badoption": "Ti kuwenta a nainaganam ket saan a mabalin a pagpilian.",
-       "htmlform-int-invalid": "Ti kuwenta a nainaganam ket saan a sibubukel.",
-       "htmlform-float-invalid": "Ti kuwenta a nainaganam ket saan a numero.",
-       "htmlform-int-toolow": "Ti kuwenta a nainaganam ket baba ti mabalin a kababaan ti $1",
-       "htmlform-int-toohigh": "Ti kuwenta a nainaganam ket ngato ti mabalin a kangatuan ti $1",
-       "htmlform-required": "Masapul daytoy a kuwenta",
+       "htmlform-invalid-input": "Adda pakirut kadagiti dadduma nga inkabilmo.",
+       "htmlform-select-badoption": "Ti pateg a nainaganam ket saan a mabalin a pagpilian.",
+       "htmlform-int-invalid": "Ti pateg a nainaganam ket saan a maysa a sibubukel.",
+       "htmlform-float-invalid": "Ti pateg a nainaganam ket saan a numero.",
+       "htmlform-int-toolow": "Ti pateg a nainaganam ket baba ti mabalin a kababaan ti $1.",
+       "htmlform-int-toohigh": "Ti pateg a nainaganam ket ngato ti mabalin a kangatuan ti $1.",
+       "htmlform-required": "Masapul daytoy a pateg.",
        "htmlform-submit": "Ited",
-       "htmlform-reset": "Ibabawi ti sinukatan",
+       "htmlform-reset": "Ibabawi dagiti sinukatan",
        "htmlform-selectorother-other": "Sabali",
        "htmlform-no": "Saan",
        "htmlform-yes": "Wen",
-       "htmlform-chosen-placeholder": "Agpili ti pagpilian",
+       "htmlform-chosen-placeholder": "Agpili ti maysa a pagpilian",
        "htmlform-cloner-create": "Agnayon pay ti adu",
        "htmlform-cloner-delete": "Ikkaten",
        "htmlform-cloner-required": "Saan a basbassit ngem maysa a pateg ti masapul.",
-       "sqlite-has-fts": "$1 adda ti suporta ti napno a testo ti panagbiruk",
-       "sqlite-no-fts": "$1 awan ti suporta ti napno a testo ti panagbiruk",
+       "sqlite-has-fts": "Ti $1 nga addaan iti suporta ti panagbiruk ti napno a testo",
+       "sqlite-no-fts": "Ti $1 nga awan iti suporta ti panagbiruk ti napno a testo",
        "logentry-delete-delete": "Ni $1 ket {{GENDER:$2|inikkatna}} ti panid ti $3",
        "logentry-delete-restore": "Ni $1 ket {{GENDER:$2|insublina}} ti panid ti $3",
        "logentry-delete-event": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti panagkita {{PLURAL:$5|iti listaan ti pasamak |dagiti $5 a listaan ti pasamak }} iti $3: $4",
        "logentry-delete-revision": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti panagkita  {{PLURAL:$5|iti panagbaliw |dagiti $5 a panagbaliw}} iti panid $3: $4",
-       "logentry-delete-event-legacy": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti panagkita ti listaan dagiti pasamak idiay $3",
-       "logentry-delete-revision-legacy": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti panagkita dagiti panagbaliw idiay panid $3",
+       "logentry-delete-event-legacy": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti panagkita ti listaan dagiti pasamak iti $3",
+       "logentry-delete-revision-legacy": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti panagkita dagiti rebision iti panid ti $3",
        "logentry-suppress-delete": "Ni $1 ket {{GENDER:$2|pinasardengna}} ti panid ti $3",
        "logentry-suppress-event": "Ni $1 ket sekreto a {{GENDER:$2|binaliwanna}} ti panagkita {{PLURAL:$5|iti listaan ti pasamak |dagiti $5 a listaan ti pasamak }} iti $3: $4",
        "logentry-suppress-revision": "Ni $1 ket sekreto a {{GENDER:$2|binaliwanna}} ti panagkita {{PLURAL:$5|iti panagbaliw |dagiti $5 a panagbaliw}} iti panid $3: $4",
-       "logentry-suppress-event-legacy": "Ni $1 ket sekreto a {{GENDER:$2|binaliwanna}} ti panagkita ti listaan dagiti pasamak idiay $3",
-       "logentry-suppress-revision-legacy": "Ni $1 ket sekreto a {{GENDER:$2|binaliwanna}} ti panagkita dagiti panagbaliw idiay panid $3",
-       "revdelete-content-hid": "nailemmeng ti nagyanna",
-       "revdelete-summary-hid": "nailemmeng ti pakabuklan a naurnos",
+       "logentry-suppress-event-legacy": "Ni $1 ket sekreto a {{GENDER:$2|binaliwanna}} ti panagkita ti listaan dagiti pasamak iti $3",
+       "logentry-suppress-revision-legacy": "Ni $1 ket sekreto a {{GENDER:$2|binaliwanna}} ti panagkita dagiti panagbaliw iti panid ti $3",
+       "revdelete-content-hid": "nailemmeng ti linaon",
+       "revdelete-summary-hid": "nailemmeng ti pakabuklan ti inurnos",
        "revdelete-uname-hid": "nailemmeng ti nagan ti agar-aramat",
-       "revdelete-content-unhid": "saan a nailemmeng ti nagyanna",
-       "revdelete-summary-unhid": "saan a nailemmeng ti  pakabuklan a naurnos",
+       "revdelete-content-unhid": "saan a nailemmeng ti linaon",
+       "revdelete-summary-unhid": "saan a nailemmeng ti pakabuklan ti inurnos",
        "revdelete-uname-unhid": "saan a nailemmeng ti nagan ti agar-aramat",
-       "revdelete-restricted": "naipakat dagiti pammarit kadagiti administrador",
-       "revdelete-unrestricted": "naikkat dagiti pammarit para kadagiti administrador",
-       "logentry-move-move": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid $3 idiay $4",
-       "logentry-move-move-noredirect": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid ti $3 idiay $4 a saan a nangibati ti baw-ing",
-       "logentry-move-move_redir": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid ti $3 idiay $4 nga adda iti maysa a baw-ing",
-       "logentry-move-move_redir-noredirect": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid ti $3 idiay $4 nga adda iti maysa a baw-ing a saan a nangibati ti baw-ing",
-       "logentry-patrol-patrol": "Ni $1 ket {{GENDER:$2|minarkaanna}} ti panagbaliw a $4 ti panid ti $3 a napatruliaan",
-       "logentry-patrol-patrol-auto": "Ni $1 ket automatiko a {{GENDER:$2|minarkaanna}} ti panagbaliw a $4 ti panid ti $3 a napatruliaan",
+       "revdelete-restricted": "naipakat dagiti panangigawid kadagiti administrador",
+       "revdelete-unrestricted": "inikkat dagiti panangigawid para kadagiti administrador",
+       "logentry-move-move": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid $3 iti $4",
+       "logentry-move-move-noredirect": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid ti $3 iti $4 a saan a nangibati ti baw-ing",
+       "logentry-move-move_redir": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid ti $3 iti $4 a nagtuon iti baw-ing",
+       "logentry-move-move_redir-noredirect": "Ni $1 ket {{GENDER:$2|inyalisna}} ti panid ti $3 iti $4 a nagtuon iti baw-ing a saan a nangibati ti baw-ing",
+       "logentry-patrol-patrol": "Ni $1 ket {{GENDER:$2|minarkaanna}} ti rebision ti $4 iti panid ti $3 a napatruliaan",
+       "logentry-patrol-patrol-auto": "Ni $1 ket automatiko a {{GENDER:$2|minarkaanna}} ti rebision ti $4 iti panid ti $3 a napatruliaan",
        "logentry-newusers-newusers": "Ti pakabilangan idi ni $1 ket {{GENDER:$2|napartuat}}",
        "logentry-newusers-create": "Ti pakabilangan idi ni $1 ket {{GENDER:$2|napartuat}}",
        "logentry-newusers-create2": "Ti pakabilangan ti agar-aramat $3 ket {{GENDER:$2|napartuat}} idi babaen ni $1",
        "logentry-rights-rights-legacy": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti grupo a pannakaikameng para kenni $3",
        "logentry-rights-autopromote": "Ni $1 ket automatiko idi a {{GENDER:$2|naipangato}} manipud ti $4 iti $5",
        "rightsnone": "(awan)",
-       "feedback-bugornote": "No agsagana kan nga agibaga ti teknikal a pakirut a naisalaysay pangngaasi nga [$1 ireporta ti kiteb].\nNupay kasta, mau-sarmo ti nakabuklan dita baba. Ti komentario nga itedmo ket mainayon iti panid \"[$3 $2], a mairaman ti naganmo nga agar-aramat ken no ania ti pagbasabasa nga us-sarem.",
+       "feedback-bugornote": "No sisasagakan nga agibaga ti teknikal a pakirut a naisalaysay pangngaasi nga [$1 ireporta ti parikut].\nNupay kasta, mausarmo ti nalaka a porma dita baba. Ti komentario nga itedmo ket mainayon iti panid \"[$3 $2], a mairaman ti naganmo nga agar-aramat ken no ania ti pagbasabasa nga us-sarem.",
        "feedback-subject": "Suheto:",
        "feedback-message": "Mensahe:",
        "feedback-cancel": "Ukasen",
-       "feedback-submit": "Agited ti Pagipagarupan",
-       "feedback-adding": "Agnaynayon ti pagipagarupan iti panid...",
-       "feedback-error1": "Biddut: Saan a malasin dagiti nagbanagan manipud iti API",
+       "feedback-submit": "Agited ti Feedback",
+       "feedback-adding": "Agnaynayon ti feedback iti panid...",
+       "feedback-error1": "Biddut: Saan a malasin dagiti nagbanagan manipud ti API",
        "feedback-error2": "Biddut: Napaay ti panagurnos",
-       "feedback-error3": "Biddut: Awan ti sungbat manipud iti API",
-       "feedback-thanks": "Agyaman! Ti panangparupaam ket naipablaak iti panid \"[$2 $1]\".",
+       "feedback-error3": "Biddut: Awan ti sungbat manipud ti API",
+       "feedback-thanks": "Agyaman! Ti feedbackmo ket naipablaak iti panid \"[$2 $1]\".",
        "feedback-close": "Nalpasen",
-       "feedback-bugcheck": "Nasayaaten! Kitaem tapno saan a dagiti adda idin a [$1 nga amammo a kitkiteb].",
-       "feedback-bugnew": "Kinitak. Ireporta ti baro a kiteb",
+       "feedback-bugcheck": "Nasayaaten! Kitaem tapno saan a dagiti adda idin a [$1 nga ammo a parparikut].",
+       "feedback-bugnew": "Kinitak. Agireporta ti baro a parikut",
        "searchsuggest-search": "Biruken",
        "searchsuggest-containing": "naglaon ti...",
-       "api-error-badaccess-groups": "Saanmo a mabalin ti agipan kadagiti papeles iti daytoy a wiki.",
-       "api-error-badtoken": "Kinauneg a biddut: Dakes a tandaan.",
-       "api-error-copyuploaddisabled": "Ti mangipan babaen ti URL ket nabaldado ditoy a server.",
-       "api-error-duplicate": "Adda {{PLURAL:$1|ket [$2 a sabali a papeles] |dagiti [$2 sabsabali a papeles]}} nga addan ditoy a pagsaadan nga agpada ti nagyanda.",
-       "api-error-duplicate-archive": "Adda {{PLURAL:$1|idi [$2 sabali a papeles]|dagidi [$2 sabali a papeles]}} nga adda ditoy a pagsaadan nga agpada ti nagyan da, ngem {{PLURAL:$1|daytoy|dagitoy}} ket naikkat.",
+       "api-error-badaccess-groups": "Saanka mapalubosan nga agikarga kadagiti papeles iti daytoy a wiki.",
+       "api-error-badtoken": "Akin-uneg a biddut: Dakes a tandaan.",
+       "api-error-copyuploaddisabled": "Ti panagikarga babaen ti URL ket nabaldado iti daytoy server.",
+       "api-error-duplicate": "Adda {{PLURAL:$1|ket [$2 a sabali a papeles] |dagiti [$2 sabsabali a papeles]}} nga addaan ditoy a sitio nga agpada ti linaon.",
+       "api-error-duplicate-archive": "Adda {{PLURAL:$1|idi [$2 sabali a papeles]|dagidi [$2 sabali a papeles]}} nga addaan ditoy a sitio nga agpada ti linaonda, ngem {{PLURAL:$1|daytoy|dagitoy}} ket naikkat.",
        "api-error-duplicate-archive-popup-title": "Duplikado {{PLURAL:$1|ti papeles|dagiti papeles}} a naikkaten.",
        "api-error-duplicate-popup-title": "Duplikado {{PLURAL:$1|ti papeles|dagiti papeles}}.",
-       "api-error-empty-file": "Ti papeles nga intedmo ket awan ti nagyanna.",
-       "api-error-emptypage": "Agar-aramid ti baro, dagiti awan ti linaonna a panid ket saan a maipalubos.",
-       "api-error-fetchfileerror": "Kinauneg a biddut: Addaan ti dakes a napasamak idi agalala ti papeles.",
+       "api-error-empty-file": "Ti papeles nga intedmo ket awan linaon.",
+       "api-error-emptypage": "Agparprtuat ti baro, dagiti awan ti linaon a panid ket saan a maipalubos.",
+       "api-error-fetchfileerror": "Akin-uneg a biddut: Addaan ti dakes a napasamak bayat nga agal-ala ti papeles.",
        "api-error-fileexists-forbidden": "Ti papeles nga agnagan ti \"$1\" ket addan, ken saan a mabalin a masuratan manen.",
        "api-error-fileexists-shared-forbidden": "Ti papeles nga agnagan ti \"$1\" ket adda idiay pagbibingayan a repositorio ti papeles, ken saan a mabalin a masuratan manen.",
        "api-error-file-too-large": "Ti papeles nga intedmo ket dakkel unay.",
        "api-error-filename-tooshort": "Ti nagan daytoy a papeles ket bassit unay.",
        "api-error-filetype-banned": "Ti kita daytoy a papeles ket maiparit.",
-       "api-error-filetype-banned-type": "Ti $1 {{PLURAL:$4|ket saan a mapalubusan a kita ti papeles|ket dagiti saan a mapalubusan a kita ti papeles}}. Ti mapalubusan {{PLURAL:$3|a kita ti papeles ket|kadagiti kita ti papeles ket}} $2.",
-       "api-error-filetype-missing": "Ti papeles ket agkurang ti pagpa-atiddog.",
-       "api-error-hookaborted": "Ti panagbabaro a pinadasmo ket napasardeng iti pangpa-atiddog a kawit.",
-       "api-error-http": "Kinauneg a biddut: Saan a makaikabit idiay server.",
+       "api-error-filetype-banned-type": "Ti $1 {{PLURAL:$4|ket saan a mapalubosan a kita ti papeles|ket dagiti saan a mapalubusan a kita ti papeles}}. Ti mapalubosan {{PLURAL:$3|a kita ti papeles ket|kadagiti kita ti papeles ket}} $2.",
+       "api-error-filetype-missing": "Ti papeles ket awan ti maysa a pagpaatiddog.",
+       "api-error-hookaborted": "Ti panagbabaro a pinadasmo ket pinasardeng babaen ti maysa a pagpaatiddog.",
+       "api-error-http": "Akin-uneg a biddut: Saan a makaikabit iti server.",
        "api-error-illegal-filename": "Ti nagan daytoy a papeles ket saan a maipalubos.",
-       "api-error-internal-error": "Kinauneg a biddut: Addaan ti dakes a napasamak ti panagaramid ti panagipanmo iti daytoy a wiki.",
-       "api-error-invalid-file-key": "Kinauneg a biddut: Saan a nabirukan ti papeles idiay temporario a nagidulinan.",
-       "api-error-missingparam": "Kinauneg a biddut: Kurang dagiti parametro iti kiddaw.",
-       "api-error-missingresult": "Kinauneg a biddut: Saan a na-ammoan no ti kopia ket nagballigi.",
-       "api-error-mustbeloggedin": "Masapul a nakastrek ka tapno makaipan ka kadagiti papeles.",
-       "api-error-mustbeposted": "Kinauneg a biddut: Ti kiddaw ket masapul ti HTTP POST.",
-       "api-error-noimageinfo": "Balligi ti panag-ipan, ngem ti server ket saan a nagited kadakami ti pakaammo a maipanggep iti daytoy a papeles.",
-       "api-error-nomodule": "Kinauneg a biddut: Awan ti panagipan a modulo a disso.",
-       "api-error-ok-but-empty": "Kinauneg a biddut: Awan ti sungbat manipud idiay server.",
-       "api-error-overwrite": "Saan a mabalin a suratan manen iti papeles nga adda ditan.",
-       "api-error-stashfailed": "Kinauneg a biddut: Napaay ti server ti agidulin ti temporario a papeles",
-       "api-error-publishfailed": "Kinauneg a biddut: Napaay ti server a nagipablaak ti temporario a papeles.",
+       "api-error-internal-error": "Akin-uneg a biddut: Addaan ti dakes a napasamak iti panagproseso ti inkargam iti daytoy a wiki.",
+       "api-error-invalid-file-key": "Akin-uneg a biddut: Saan a nabirukan ti papeles idiay temporario a nagidulinan.",
+       "api-error-missingparam": "Akin-uneg a biddut: Awan dagiti parametro iti kiddaw.",
+       "api-error-missingresult": "Akin-uneg a biddut: Saan a naikeddeng no ti kopia ket nagballigi.",
+       "api-error-mustbeloggedin": "Masapul a nakastrekka tapno makaiarga kadagiti papeles.",
+       "api-error-mustbeposted": "Akin-uneg a biddut: Ti kiddaw ket masapul ti HTTP POST.",
+       "api-error-noimageinfo": "Balligi ti panagikarga, ngem ti server ket saan a nagited kadakami ti aniaman a pakaammo a maipanggep iti daytoy a papeles.",
+       "api-error-nomodule": "Akin-uneg a biddut: Awan ti naisad a modulo ti panagikarga.",
+       "api-error-ok-but-empty": "Akin-uneg a biddut: Awan ti sungbat manipud ti server.",
+       "api-error-overwrite": "Saan a maipalubos a suratan manen iti papeles nga addan.",
+       "api-error-stashfailed": "Akin-uneg a biddut: Napaay ti server nga agidulin ti temporario a papeles.",
+       "api-error-publishfailed": "Akin-uneg a biddut: Napaay ti server nga agipablaak ti temporario a papeles.",
        "api-error-stasherror": "Adda maysa a biddut bayat nga agikarkarga ti papeles iti stash.",
        "api-error-timeout": "Saan a simmungbat ti server iti nanamnama nga oras.",
-       "api-error-unclassified": "Adda di amammo a biddut a rumsua.",
-       "api-error-unknown-code": "Di am-ammo a biddut: \"$1\".",
-       "api-error-unknown-error": "Kinauneg a biddut: Addaan ti dakes a napasamak idi nagipadaska ti agipan ti papelesmo.",
-       "api-error-unknown-warning": "Di am-ammo a ballaag: \"$1\".",
-       "api-error-unknownerror": "Di am-ammo a biddut: \"$1\".",
-       "api-error-uploaddisabled": "Nabaldado ti mangipapan iti daytoy a wiki.",
-       "api-error-verification-error": "Dakes ngata daytoy a papeles, wenno addaan ti madi a pagpa-atiddog.",
-       "duration-seconds": "$1 {{PLURAL:$1|segundo|seg-segundo}}",
-       "duration-minutes": "$1 {{PLURAL:$1|minuto|min-minuto}}",
+       "api-error-unclassified": "Adda rimsua a di ammo a biddut.",
+       "api-error-unknown-code": "Di ammo a biddut: \"$1\".",
+       "api-error-unknown-error": "Akin-uneg a biddut: Addaan ti dakes a napasamak bayat idi nagipadaska nga agikarga iti papelesmo.",
+       "api-error-unknown-warning": "Di ammo a ballaag: \"$1\".",
+       "api-error-unknownerror": "Di ammo a biddut: \"$1\".",
+       "api-error-uploaddisabled": "Nabaldado ti panagikarga iti daytoy a wiki.",
+       "api-error-verification-error": "Mabalin a dakes daytoy a papeles, wenno addaan iti madi a pagpaatiddog.",
+       "duration-seconds": "$1 {{PLURAL:$1|segundo|segsegundo}}",
+       "duration-minutes": "$1 {{PLURAL:$1|minuto|minminuto}}",
        "duration-hours": "$1 {{PLURAL:$1|oras|or-oras}}",
        "duration-days": "$1 {{PLURAL:$1|aldaw|al-aldaw}}",
-       "duration-weeks": "$1 {{PLURAL:$1|lawas|law-lawas}}",
-       "duration-years": "$1 {{PLURAL:$1|tawen|taw-tawen}}",
-       "duration-decades": "$1 {{PLURAL:$1|dekada|dek-dekada}}",
-       "duration-centuries": "$1 {{PLURAL:$1|siglo|sig-siglo}}",
-       "duration-millennia": "$1 {{PLURAL:$1|milenio|mil-milenio}}",
-       "rotate-comment": "Ti ladawan ket napusipos babaen ti $1 {{PLURAL:$1|a degrado|a degdegrado}} nga agpakanawan",
+       "duration-weeks": "$1 {{PLURAL:$1|lawas|lawlawas}}",
+       "duration-years": "$1 {{PLURAL:$1|tawen|tawtawen}}",
+       "duration-decades": "$1 {{PLURAL:$1|dekada|dekdekada}}",
+       "duration-centuries": "$1 {{PLURAL:$1|siglo|sigsiglo}}",
+       "duration-millennia": "$1 {{PLURAL:$1|milenio|milmilenio}}",
+       "rotate-comment": "Ti ladawan ket napusipos babaen ti $1 {{PLURAL:$1|a grado|a gradgrado}} nga agpakanawan",
        "limitreport-title": "Panagbariweswes a datos ti parser:",
        "limitreport-cputime": "Panagusar nga oras ti CPU",
-       "limitreport-cputime-value": "$1 {{PLURAL:$1|segundo|seg-segundo}}",
+       "limitreport-cputime-value": "$1 {{PLURAL:$1|segundo|segsegundo}}",
        "limitreport-walltime": "Pudno nga oras a panagusar",
-       "limitreport-walltime-value": "$1 {{PLURAL:$1|segundo|seg-segundo}}",
+       "limitreport-walltime-value": "$1 {{PLURAL:$1|segundo|segsegundo}}",
        "limitreport-ppvisitednodes": "Nabisita a bilang ti nodo ti preproseso",
        "limitreport-ppgeneratednodes": "Napataud a bilang ti nodo ti preproseso",
        "limitreport-postexpandincludesize": "Pannakairaman a kadakkel ti kalpasan a panagpadakkel",
        "limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|a byte|kadagiti byte}}",
-       "limitreport-templateargumentsize": "Argumento a kadakkel ti plantilia",
+       "limitreport-templateargumentsize": "Kadakkel ti argumento ti plantilia",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|a byte|kadagiti byte}}",
-       "limitreport-expansiondepth": "Kangatuan a panagpadakkel ti kauneg",
+       "limitreport-expansiondepth": "Kangatuan a kauneg ti panagpadakkel",
        "limitreport-expensivefunctioncount": "Bilang ti nangina nga annong ti parser",
        "expandtemplates": "Palawaen dagiti plantilia",
-       "expand_templates_intro": "Daytoy nga espesial a panid ket agala ti testo ken palawaenna amin dagiti plantilia iti unegna a minaig iti daytoy.\nPalawaenna pay dagiti nasuportaran a parser a pamay-an a kas ti\n<code><nowiki>{{</nowiki>#language:…}}</code> ken dagiti nadumaduma a kita a kas ti\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>. \nIti kinapudno, palawaenna amin dagiti adda ti doble a tukol.",
+       "expand_templates_intro": "Daytoy nga espesial a panid ket agala ti testo ken palawaenna amin dagiti plantilia iti unegna a minaig iti daytoy.\nPalawaenna pay dagiti nasuportaran a parser a pamay-an a kas ti\n<code><nowiki>{{</nowiki>#language:…}}</code> ken dagiti nadumaduma a kita a kas ti\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>. \nIti kinapudno, palawaenna amin dagiti addaan iti doble a pangrikep.",
        "expand_templates_title": "Titulo ti kontesto, para iti {{FULLPAGENAME}} kdpy.:",
        "expand_templates_input": "Maikabil a testo:",
        "expand_templates_output": "Nagbanagan",
-       "expand_templates_xml_output": "XML a maiparang",
+       "expand_templates_xml_output": "Maiparuar a XML",
        "expand_templates_html_output": "Naata a maiparuar a HTML",
-       "expand_templates_ok": "OK",
+       "expand_templates_ok": "Sige",
        "expand_templates_remove_comments": "Ikkaten dagiti komentario",
-       "expand_templates_remove_nowiki": "Parmeken dagiti <nowiki> nga etiketa kadagiti nagbanagan",
-       "expand_templates_generate_xml": "Iparang ti XML parse a kayo",
+       "expand_templates_remove_nowiki": "Parmeken dagiti etiketa ti <nowiki> iti nagbanagan",
+       "expand_templates_generate_xml": "Iparang ti pangwaswas a kayo ti XML",
        "expand_templates_generate_rawhtml": "Ipakita ti naata a HTML",
-       "expand_templates_preview": "Pamadasan"
+       "expand_templates_preview": "Ipadas",
+       "pagelanguage": "Pagpilian ti pagsasao ti panid",
+       "pagelang-name": "Panid",
+       "pagelang-language": "Pagsasao",
+       "pagelang-use-default": "Usaren ti kasisigud a pagsasao",
+       "pagelang-select-lang": "Agpili iti pagsasao",
+       "right-pagelang": "Baliwan ti pagsasao ti panid",
+       "action-pagelang": "baliwan ti pagsasao ti panid",
+       "log-name-pagelang": "Listaan ti panagbaliw ti pagsasao",
+       "log-description-pagelang": "Daytoy ket listaan dagiti panagbaliw kadagiti pagsasao ti panid.",
+       "logentry-pagelang-pagelang": "Ni $1 ket {{GENDER:$2|binaliwanna}} ti pagsasao ti panid para iti $3 manipud ti $4 iti $5."
 }
index 6f2334c..d65c9b7 100644 (file)
        "talkpagelinktext": "Spjall",
        "specialpage": "Kerfissíða",
        "personaltools": "Tenglar",
-       "postcomment": "Nýr hluti",
        "articlepage": "Sýna núverandi síðu",
        "talk": "Spjall",
        "views": "Sýn",
        "externaldberror": "Uppfærsla mistókst. Annaðhvort varð villa í gagnasafninu eða að þér sé óheimilt að uppfæra aðra aðganga.",
        "login": "Innskrá",
        "nav-login-createaccount": "Innskrá / Búa til aðgang",
-       "loginprompt": "Þú verður að leyfa vefkökur til þess að geta skráð þig inn á {{SITENAME}}.",
        "userlogin": "Innskrá / Búa til aðgang",
        "userloginnocreate": "Innskrá",
        "logout": "Útskráning",
        "loginreqlink": "innskrá",
        "loginreqpagetext": "Þú þarft að $1 þig til að geta séð aðrar síður.",
        "accmailtitle": "Lykilorð sent.",
-       "accmailtext": "Lykilorðið fyrir [[User talk:$1|$1]] hefur verið sent á $2.\n\nHægt er að breyta lykilorðinu fyrir aðganginn á ''[[Special:ChangePassword|change password]]'' þegar notandinn hefur skráð sig inn.",
+       "accmailtext": "Lykilorðið fyrir [[User talk:$1|$1]] hefur verið sent á $2. Hægt er að breyta því á síðunni ''[[Special:ChangePassword|breyta lykilorði]]'' þegar notandinn hefur skráð sig inn.",
        "newarticle": "(Ný)",
        "newarticletext": "Þú hefur fylgt tengli á síðu sem ekki er til ennþá.\nÞú getur búið til síðu með þessu nafni með því að skrifa í formið fyrir neðan\n(meiri upplýsingar í [$1 hjálpinni]).\nEf þú hefur óvart villst hingað geturðu notað '''til baka'''-hnappinn í vafranum þínum.",
        "anontalkpagetext": "----''Þetta er spjallsíða fyrir óþekktan notanda sem hefur ekki búið til aðgang ennþá, eða notar hann ekki.\nÞar af leiðandi þurfum við að nota vistfang til að bera kennsli á hann/hana.\nNokkrir notendur geta deilt sama vistfangi.\nEf þú ert óþekktur notandi og finnst að óviðkomandi athugasemdum hafa verið beint að þér, gjörðu svo vel og [[Special:UserLogin/signup|búðu til aðgang]] eða [[Special:UserLogin|skráðu þig inn]] til þess að koma í veg fyrir þennan rugling við aðra óþekkta notendur í framtíðinni.''",
        "content-failed-to-parse": "Gat ekki þáttað $2 efni samkvæmt $1 líkani: $3",
        "invalid-content-data": "Ógild efnisgögn.",
        "content-not-allowed-here": "„$1“ efni er ekki leyfilegt á síðunni [[$2]]",
-       "editwarning-warning": "Ef farið er frá þessari síðu gætu þær breytingar sem þú hefur gert tapast.\nEf þú ert skráður inn, þá getur þú óvirkjað þessi skilaboð í „Breytingarflipanum\" undir stillingum.",
+       "editwarning-warning": "Ef farið er frá þessari síðu gætu þær breytingar sem þú hefur gert tapast.\nEf þú ert skráður inn, þá getur þú óvirkjað þessi skilaboð í „{{int:prefs-editing}}\" undir stillingum.",
        "content-model-wikitext": "wiki-texti",
        "content-model-text": "hreinn texti",
        "content-model-javascript": "JavaScript",
        "currentrev": "Núverandi útgáfa",
        "currentrev-asof": "Núverandi breyting frá og með $1",
        "revisionasof": "Útgáfa síðunnar $1",
-       "revision-info": "Útgáfa frá $1 eftir $2",
+       "revision-info": "Útgáfa frá $1 eftir $2\nÚtgáfa frá $1 eftir {{GENDER:$6|$2}}$7",
        "previousrevision": "←Fyrri útgáfa",
        "nextrevision": "Næsta útgáfa→",
        "currentrevisionlink": "Núverandi útgáfa",
        "search-file-match": "(passar við innihald skráa)",
        "search-suggest": "Varstu að leita að: $1",
        "search-interwiki-caption": "Systurverkefni",
-       "search-interwiki-default": "$1 útkomur:",
+       "search-interwiki-default": "Útkomur frá $1:",
        "search-interwiki-more": "(fleiri)",
        "search-relatedarticle": "Tengt",
        "searchrelated": "tengt",
        "gender-unknown": "Ég vil heldur ekki gefa upp",
        "gender-male": "Hann breytir wikisíðum",
        "gender-female": "Hún breytir wikisíðum",
-       "prefs-help-gender": "Valfrjálst: notað til að aðgreina kynin í meldingum hugbúnaðarins. Þessar upplýsingar verða aðgengilegar öllum.",
+       "prefs-help-gender": "Þessi stilling er valfrjáls. Notað til að aðgreina kynin í meldingum hugbúnaðarins. Þessar upplýsingar verða aðgengilegar öllum.",
        "email": "Tölvupóstur",
        "prefs-help-realname": "Alvöru nafn er valfrjálst.\nEf þú kýst að gefa það upp, verður það notað til að gefa þér heiður af verkum þínum.",
        "prefs-help-email": "Tölvupóstfang er valfrjálst, en gerir þér kleift að fá nýtt lykilorð ef þú gleymir lykilorðinu þínu.",
        "right-reupload-shared": "Hunsa skrár á sameiginlegu myndasafni staðbundið",
        "right-upload_by_url": "Hlaða inn skrám frá vefslóð",
        "right-purge": "Hreinsa skyndiminni síðu án staðfestingar",
-       "right-autoconfirmed": "Breyta hálfvernduðum síðum",
+       "right-autoconfirmed": "Sneiða hjá takmörkunum vistfanga",
        "right-bot": "Eru meðhöndlaðir eins og sjálfvirk aðgerð",
        "right-nominornewtalk": "Ekki láta minniháttar breytingar á spjallsíðum kveða upp áminningu um ný skilaboð",
        "right-apihighlimits": "Setja hærri mörk á fjölda API fyrirspurna",
        "largefileserver": "Þessi skrá er of stór. Vefþjónninn getur ekki tekið við skránni.",
        "emptyfile": "Skráin sem þú hlóðst inn virðist vera tóm.\nÞetta gæti verið vegna ásláttarvillu í skráarnafninu.\nVinsamlegast athugaðu hvort þú viljir hlaða skránni inn.",
        "windows-nonascii-filename": "Þessi wiki styður ekki skráarnöfn með sérstökum stöfum",
-       "fileexists": "Skrá með þessu nafni er þegar til, skoðaðu <strong>[[:$1]]</strong> ef þú ert óviss um hvort þú viljir breyta henni, ekki verður skrifað yfir gömlu skránna hlaðiru inn nýrri með sama nafni heldur verður núverandi útgáfa geymd í útgáfusögu.\n[[$1|thumb]]",
+       "fileexists": "Skrá með þessu nafni er þegar til, skoðaðu <strong>[[:$1]]</strong> ef þú ert óviss um hvort þú viljir breyta henni.\n[[$1|thumb]]",
        "filepageexists": "Myndasíðan fyrir þessa síðu hefur þegar verið búin til <strong>[[:$1]]</strong>, en engin skrá er til með þessu nafni.\nLýsingin sem þú skrifaðir verður ekki birt á myndasíðunni.\nTil þess að lýsingin geti birst á síðunni, þá þarft þú að breyta síðunni sérstaklega.\n[[$1|thumb]]",
-       "fileexists-extension": "Skrá með svipuðu nafni er til: [[$2|thumb]]\n*Nafn skráarinnar sem hlaða á inn: <strong>[[:$1]]</strong>\n*Nafn skráarinnar sem er þegar til: <strong>[[:$2]]</strong>\nVinsamlegast veldu annað skráarnafn.",
+       "fileexists-extension": "Skrá með svipuðu nafni er til: [[$2|thumb]]\n*Nafn skráarinnar sem hlaða á inn: <strong>[[:$1]]</strong>\n*Nafn skráarinnar sem er þegar til: <strong>[[:$2]]</strong>\nVilt þú kanski nota annað nafn sem er meira lýsandi fyrir skránna ?",
        "fileexists-thumbnail-yes": "Skráin virðist vera smámynd [[$1|thumb]]\nVinsamlegast athugaðu skránna <strong>[[:$1]]</strong>.\nEf skráin er sama myndin í upprunalegri stærð er ekki þörf á annari smámynd.",
        "file-thumbnail-no": "Skráin er líklega smámynd, því skráarnafnið byrjar á <strong>$1</strong>.\nEf skráin er í fullri upplausn haltu þá áfram að hlaða henni inn, en ef ekki breyttu þá skráarnafninu.",
        "fileexists-forbidden": "Skrá með þessu nafni er þegar til og ekki er hægt að skrifa yfir skránna.\nEf þú villt hlaða inn skránni þinni engu að síður, farðu þá til baka og veldu annað skráarnafn.\n[[File:$1|thumb|center|$1]]",
        "filedelete-maintenance": "Á meðan viðhaldi stendur er lokað fyrir eyðingu og endurvakningu skráa.",
        "filedelete-maintenance-title": "Mistókst að eyða skrá",
        "mimesearch": "MIME-leit",
-       "mimesearch-summary": "Þessi síða gerir þér kleift að leita eftir skrám eftir MIME-gerð þeirra.\n\nLeitarstrengurinn á að vera á þessu formi: efnistag/myndasnið, t.d. <code>image/jpeg</code>.",
+       "mimesearch-summary": "Þessi síða gerir þér kleift að leita eftir skrám eftir MIME-gerð þeirra.\n\nLeitarstrengurinn á að vera á þessu formi: efnistag/myndasnið eða efnistag/*, t.d. <code>image/jpeg</code>.",
        "mimetype": "MIME-tegund:",
        "download": "Hlaða niður",
        "unwatchedpages": "Óvaktaðar síður",
        "pageswithprop-submit": "Áfram",
        "doubleredirects": "Tvöfaldar tilvísanir",
        "doubleredirectstext": "Þessi síða er listi yfir skrár sem eru tilvísanir á aðrar tilvísanir.\nHver lína inniheldur tengla á fyrstu og aðra tilvísun auk þeirrar síðu sem seinni tilvísunin beinist að, sem er oftast sú síða sem allar tilvísanirnar eiga að benda á.\n<del>Yfirstrikaðar</del> færslur hafa verið leiðréttar.",
-       "double-redirect-fixed-move": "[[$1]] hefur verið færð.\nHún er tilvísun á [[$2]].",
-       "double-redirect-fixed-maintenance": "Laga tvöfalda tilvísun frá [[$1]] til [[$2]].",
+       "double-redirect-fixed-move": "[[$1]] hefur verið færð.\nHún var uppfærð sjálfkrafa og tilvísar núna á [[$2]].",
+       "double-redirect-fixed-maintenance": "Laga sjálfvirkt tvöfalda tilvísun frá [[$1]] til [[$2]] í viðhalds aðgerð.",
        "double-redirect-fixer": "Laga tilvísun",
        "brokenredirects": "Brotnar tilvísanir",
        "brokenredirectstext": "Eftirfarandi tilvísanir vísa á síður sem ekki eru til:",
        "wantedtemplates": "Eftirsótt snið",
        "mostlinked": "Mest ítengdu síður",
        "mostlinkedcategories": "Mest ítengdu flokkar",
-       "mostlinkedtemplates": "Mest ítengdu snið",
+       "mostlinkedtemplates": "Mest ítengdu síður",
        "mostcategories": "Mest flokkaðar greinar",
        "mostimages": "Mest ítengdu skrárnar",
        "mostinterwikis": "Síður með flestm tungumálatenglum",
        "enotif_lastvisited": "Heimsóttu eftirfarandi tengil til að sjá allar breytingar síðan \nþú heimsóttir síðuna síðast:\n  $1",
        "enotif_lastdiff": "Einnig getur þú heimsótt eftirfarandi tengil til að skoða þessa breytingu:\n  $1",
        "enotif_anon_editor": "ónefndum notanda $1",
-       "enotif_body": "Kæri $WATCHINGUSERNAME,\n\n$PAGEINTRO\n$NEWPAGE\n\nTil þess að hafa samband við $PAGEEDITOR, smelltu á:\n\n   $PAGEEDITOR_WIKI\n\nAthugaðu að frekari breytingar á $PAGETITLE leiða\nekki af sér fleiri tilkynningar fyrr en þú hefur heimsótt síðuna á meðan þú ert skráð/ur inn.\n\nKveðja,\n{{SITENAME}}\n\n--\n\nTil þess að breyta stillingum um hvenær þú færð sendar tilkynningar, smelltu á:\n\n{{canonicalurl:{{#special:Preferences}}}}\n\n\nTil þess að hætta að fylgjast með „$PAGETITLE”, smelltu á:\n\n$UNWATCHURL",
+       "enotif_body": "Kæri $WATCHINGUSERNAME,\n\n$PAGEINTRO\n$NEWPAGE\n\n$PAGEEDITOR skildi eftir eftirfarandi breytingarágrip: $PAGESUMMARY $PAGEMINOREDIT\n\nTil þess að hafa samband við $PAGEEDITOR, smelltu á $PAGEEDITOR_WIKI eða sentu tölvupóst á $PAGEEDITOR_EMAIL\n\nAthugaðu að frekari aðgerðir á $PAGETITLE leiða\nekki af sér fleiri tilkynningar fyrr en þú hefur heimsótt síðuna á meðan þú ert skráð/ur inn. Þú getur einnig endursett tilkynningar fyrir allar þær síður sem þú fylgist með.\n\nKveðja,\n{{SITENAME}}\n\n--\n\nTil þess að breyta stillingum um hvenær þú færð sendar tilkynningar, smelltu á:\n\n{{canonicalurl:{{#special:Preferences}}}}\n\n\nTil þess að hætta að fylgjast með „$PAGETITLE”, smelltu á:\n\n$UNWATCHURL\n\nFrekari hjálp er að finna á $HELPPAGE.",
        "created": "búin til",
        "changed": "breytt",
        "deletepage": "Eyða",
        "protect-locked-blocked": "Þú getur ekki breytt verndunarstigi á meðan þú ert bannaður.\nHérna er núverandi verndunarstig fyrir síðuna '''$1''':",
        "protect-locked-dblock": "Á meðan gangnabankinn er læstur er ekki hægt að breyta verndunarstigi.\nHér eru núverandi verndunarstig fyrir síðuna '''$1''':",
        "protect-locked-access": "Þú hefur ekki heimild til þess að vernda eða afvernda síður.\nNúverandi staða síðunnar er '''$1''':",
-       "protect-cascadeon": "Þessi síða er vernduð vegna þess að hún er innifalin í eftirfarandi {{PLURAL:$1|síðu, sem er keðjuvernduð|síðum, sem eru keðjuverndaðar}}.\nÞú getur breytt verndunarstigi þessarar síðu, en það mun ekki hafa áhrif á keðjuverndunina.",
+       "protect-cascadeon": "Þessi síða er vernduð vegna þess að hún er innifalin í eftirfarandi {{PLURAL:$1|síðu, sem er keðjuvernduð|síðum, sem eru keðjuverndaðar}}.\nBreytingar á verndunarstigi þessarar síðu munu ekki hafa áhrif á keðjuverndunina.",
        "protect-default": "Leyfa öllum notendum",
        "protect-fallback": "Leyfa eingöngu notendur með „$1“ réttindi",
        "protect-level-autoconfirmed": "Leyfa aðeins sjálkrafa staðfesta notendur",
        "pageinfo-length": "Lengd síðunnar (í bætum)",
        "pageinfo-article-id": "Einkennisnúmer síðunnar",
        "pageinfo-language": "Tungumál síðunnar",
-       "pageinfo-robot-policy": "Leitarvélastaða",
+       "pageinfo-robot-policy": "Attriðaskráning af vélmennum",
        "pageinfo-robot-index": "Heimilað",
        "pageinfo-robot-noindex": "Ekki heimilað",
        "pageinfo-views": "Fjöldi innlita",
        "duplicate-defaultsort": "'''Viðvörun:''' Sjálfgildur flýtihnappur \"$2\" tekur yfir fyrri flýtihnapp \"$1\".",
        "version": "Útgáfa",
        "version-extensions": "Uppsettar viðbætur",
+       "version-skins": "Uppsett þemu",
        "version-specialpages": "Kerfissíður",
        "version-variables": "Breytur",
        "version-antispam": "Amapósts sía",
-       "version-skins": "Þemu",
        "version-other": "Aðrar",
        "version-mediahandlers": "Rekill margmiðlunarskráa",
        "version-parser-extensiontags": "Þáttuð smáforrita tög",
index 4a8673a..dd285a5 100644 (file)
        "talkpagelinktext": "Discussione",
        "specialpage": "Pagina speciale",
        "personaltools": "Strumenti personali",
-       "postcomment": "Nuova sezione",
        "articlepage": "Visualizza la voce",
        "talk": "Discussione",
        "views": "Visite",
        "externaldberror": "Si è verificato un errore con il server di autenticazione esterno, oppure non si dispone delle autorizzazioni necessarie per aggiornare il proprio accesso esterno.",
        "login": "Entra",
        "nav-login-createaccount": "Entra / registrati",
-       "loginprompt": "Per accedere a {{SITENAME}} è necessario abilitare i cookie.",
        "userlogin": "Entra / registrati",
        "userloginnocreate": "Entra",
        "logout": "Esci",
        "license": "Licenza:",
        "license-header": "Licenza",
        "nolicense": "Nessuna licenza indicata",
+       "licenses-edit": "Modifica opzioni di licenza",
        "license-nopreview": "(Anteprima non disponibile)",
        "upload_source_url": " (una URL corretta e accessibile)",
        "upload_source_file": " (un file sul proprio computer)",
+       "listfiles-delete": "cancella",
        "listfiles-summary": "Questa pagina speciale mostra tutti i file caricati.",
        "listfiles_search_for": "Ricerca immagini per nome:",
        "imgfile": "file",
        "wantedpages": "Pagine più richieste",
        "wantedpages-badtitle": "Titolo non valido nel gruppo di risultati: $1",
        "wantedfiles": "File richiesti",
-       "wantedfiletext-cat": "I seguenti file sono richiamati da wikilink, ma non esistono. I file ospitati su repository esterni potrebbero essere elencati anche se di fatto esistenti. Questi falsi positivi saranno <del>barrati</del>. Le pagine che incorporano i file che non esistono sono elencate in [[:$1]].",
+       "wantedfiletext-cat": "I seguenti file sono utilizzati, ma non esistono. I file ospitati su repository esterni potrebbero essere elencati anche se di fatto esistenti. Questi falsi positivi saranno <del>barrati</del>. Le pagine che incorporano i file che non esistono sono elencate in [[:$1]].",
+       "wantedfiletext-cat-noforeign": "I seguenti file sono utilizzati, ma non esistono. Inoltre, le pagine che incorporano questi file sono elencate nella [[:$1]].",
        "wantedfiletext-nocat": "I seguenti file sono richiamati da wikilink, ma non esistono. I file ospitati su repository esterni potrebbero essere elencati anche se di fatto esistenti. Questi falsi positivi saranno <del>barrati</del>.",
+       "wantedfiletext-nocat-noforeign": "I seguenti file sono utilizzati, ma non esistono.",
        "wantedtemplates": "Template richiesti",
        "mostlinked": "Pagine più richiamate",
        "mostlinkedcategories": "Categorie più richiamate",
-       "mostlinkedtemplates": "Pagine più inlcuse",
+       "mostlinkedtemplates": "Pagine più incluse",
        "mostcategories": "Pagine con più categorie",
        "mostimages": "File più richiamati",
        "mostinterwikis": "Pagine con più interwiki",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discussioni]])",
        "unknown_extension_tag": "Tag estensione sconosciuto: \"$1\"",
        "duplicate-defaultsort": "Attenzione: la chiave di ordinamento predefinita \"$2\" sostituisce la precedente \"$1\".",
+       "duplicate-displaytitle": "<strong>Attenzione:</strong> il titolo visualizzato \"$2\" sostituisce il precedente titolo \"$1\".",
        "version": "Versione",
        "version-extensions": "Estensioni installate",
        "version-skins": "Skin installate",
index 4457755..9554fe8 100644 (file)
        "newwindow": "(新しいウィンドウで開きます)",
        "cancel": "中止",
        "moredotdotdot": "続き...",
-       "morenotlisted": "ã\81\93ã\81®ä¸\80覧ã\81®ç¶\9aã\81\8d",
+       "morenotlisted": "ã\81\93ã\81®ä¸\80覧ã\81¯å®\8cå\85¨ã\81§ã\81¯ã\81\82ã\82\8aã\81¾ã\81\9bã\82\93ã\80\82",
        "mypage": "ページ",
        "mytalk": "トーク",
        "anontalk": "このIPアドレスのトーク",
        "talkpagelinktext": "トーク",
        "specialpage": "特別ページ",
        "personaltools": "個人用ツール",
-       "postcomment": "新しい節",
        "articlepage": "本文を表示",
        "talk": "議論",
        "views": "表示",
        "externaldberror": "認証データベースでエラーが発生した、または外部アカウントの更新が許可されていません。",
        "login": "ログイン",
        "nav-login-createaccount": "ログインまたはアカウント作成",
-       "loginprompt": "{{SITENAME}}にログインするにはCookieを有効にする必要があります。",
        "userlogin": "ログインまたはアカウント作成",
        "userloginnocreate": "ログイン",
        "logout": "ログアウト",
        "logdelete-selected": "{{PLURAL:$1|選択された記録項目}}:",
        "revdelete-text-text": "削除された版は履歴に表示され続けますが、一般の利用者が内容を閲覧できなくなります。",
        "revdelete-text-file": "削除されたファイルの版はファイルの履歴に表示されつづけますが、一般の利用者はその内容の一部を閲覧できなくなります。",
-       "logdelete-text": "削除された記録項目は記録に表示されつづけますが、一般の利用者はその内容の一部を閲覧できなくなります。",
-       "revdelete-text-others": "追加の制限を設定しない限り、{{SITENAME}} の他の管理者は非表示コンテンツにまだアクセスでき、この同じインターフェースを通してそれを復元することができます。",
+       "logdelete-text": "削除された記録項目は記録に表示されけますが、一般の利用者はその内容の一部を閲覧できなくなります。",
+       "revdelete-text-others": "追加の制限を設定しない限り、他の管理者は非表示コンテンツにまだアクセスすることも復元することもできます。",
        "revdelete-confirm": "この操作を行おうとしていること、その結果を理解していること、[[{{MediaWiki:Policy-url}}|方針]]に従っていること、を確認してください。",
        "revdelete-suppress-text": "秘匿は、<strong>以下の場合に限って</strong>使用すべきです:\n* 名誉毀損のおそれがある記述\n* 非公開個人情報\n*: <em>自宅の住所、電話番号、個人を識別できる公的な番号など</em>",
        "revdelete-legend": "閲覧レベル制限を設定",
        "right-deletedtext": "削除された本文と削除された版間の差分を閲覧",
        "right-browsearchive": "削除されたページを検索",
        "right-undelete": "ページを復元",
-       "right-suppressrevision": "管理者から隠された版を確認/復元",
+       "right-suppressrevision": "すべての利用者からの特定の版を見る、隠す、あるいは隠すのをやめる",
+       "right-viewsuppressed": "すべての利用者から隠された版を閲覧",
        "right-suppressionlog": "非公開記録を閲覧",
        "right-block": "他の利用者の編集をブロック",
        "right-blockemail": "利用者のメール送信をブロック",
        "license": "ライセンス:",
        "license-header": "ライセンス",
        "nolicense": "選択なし",
+       "licenses-edit": "ライセンスオプションを編集",
        "license-nopreview": "(プレビューはありません)",
        "upload_source_url": "(有効かつ一般に公開されている URL)",
        "upload_source_file": "(あなたのコンピューター上のファイル)",
+       "listfiles-delete": "削除",
        "listfiles-summary": "この特別ページでは、アップロードされたファイルをすべて表示します。",
        "listfiles_search_for": "検索するメディア名:",
        "imgfile": "ファイル",
        "wantedpages-badtitle": "結果が、無効なページ名を含んでいます: $1",
        "wantedfiles": "ファイル情報ページが存在しないファイル",
        "wantedfiletext-cat": "以下のファイルは使用されていますが存在しません。外部リポジトリ由来のファイルは、存在していてもここに列挙される場合があります。その場合は<del>取り消し線</del>が付きます。さらに、存在しないファイルを埋め込んでいるページは[[:$1]]に列挙されます。",
+       "wantedfiletext-cat-noforeign": "以下のファイルは使用されていますが存在しません。さらに、存在しないファイルを埋め込んでいるページは[[:$1]]に列挙されます。",
        "wantedfiletext-nocat": "以下のファイルは使用されていますが存在しません。外部リポジトリ由来のファイルは、存在していてもここに列挙される場合があります。その場合は<del>取り消し線</del>が付きます。",
+       "wantedfiletext-nocat-noforeign": "以下のファイルは使用されていますが存在しません。",
        "wantedtemplates": "呼び出し先が存在しないテンプレート呼び出し",
        "mostlinked": "被リンク数の多いページ",
        "mostlinkedcategories": "被リンク数の多いカテゴリ",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|トーク]])",
        "unknown_extension_tag": "不明な拡張機能タグ「$1」です",
        "duplicate-defaultsort": "<strong>警告:</strong> 既定のソートキー「$2」が、その前に書かれている既定のソートキー「$1」を上書きしています。",
+       "duplicate-displaytitle": "<strong>警告:</strong> 既定のDISPLAYTITLE「$2」が、その前に書かれている既定のDISPLAYTITLE「$1」を上書きしています。",
        "version": "バージョン情報",
        "version-extensions": "インストール済み拡張機能",
        "version-skins": "インストール済み外装",
index c5d401d..7006a1e 100644 (file)
        "talkpagelinktext": "Hurênayis",
        "specialpage": "Pela xısusiye",
        "personaltools": "Hacetê keşi",
-       "postcomment": "Qısımo newe",
        "articlepage": "Pela zerreki bıvêne",
        "talk": "Hurênais",
        "views": "Asaişi",
        "externaldberror": "Cıfeteliyaisê naskerdene de ya xeta esta ya ki tebera vırastena hesabê sıma rê destur çino.",
        "login": "Cı kuye",
        "nav-login-createaccount": "Cı kuye / hesab vıraze",
-       "loginprompt": "Cıkotena {{SITENAME}} rê gunê ''cookies'' akerdey bê.",
        "userlogin": "Cı kuye / hesab vıraze",
        "userloginnocreate": "Cı kuye",
        "logout": "Veciye",
        "mergehistory-into": "Pela hedefi:",
        "mergehistory-reason": "Sebeb:",
        "revertmerge": "Cia ke",
-       "history-title": "Rewizyonê $1:",
+       "history-title": "Tarixê çımraviyarnayişê \"$1\"",
        "lineno": "Rêza $1i:",
        "compareselectedversions": "Varyantunê weçinıtun têver sane",
        "editundo": "peyser bia",
index 884aac4..32c88ba 100644 (file)
        "talkpagelinktext": "Талқылауы",
        "specialpage": "Арнайы бет",
        "personaltools": "Жеке құралдар",
-       "postcomment": "Жаңа бөлім",
        "articlepage": "Мәлімет бетін қарау",
        "talk": "Талқылау",
        "views": "Көрініс",
        "externaldberror": "Осы арада не шеттік растау дерекқорында қате болды, немесе шеттік тіркелгіңізді жаңалау рұқсаты жоқ.",
        "login": "Кіру",
        "nav-login-createaccount": "Кіру / Тіркелу",
-       "loginprompt": "{{SITENAME}} торабына кіруіңіз үшін «cookies» қосылуы керек.",
        "userlogin": "Кіру / Тіркелу",
        "userloginnocreate": "Кіру",
        "logout": "Шығу",
        "watchthis": "Бұл бетті бақылау",
        "savearticle": "Бетті сақтау",
        "preview": "Қарап шығу",
-       "showpreview": "Алдын ала қарау",
+       "showpreview": "Алдын-ала қарау",
        "showdiff": "Өзгерістерді көрсет",
        "anoneditwarning": "<strong> Ескерту:</strong>  Сіз жүйеге кірмегенсіз.\nIP мекенжайыңыз бұл беттің өңделу тарихында жазылып алынады.",
        "anonpreviewwarning": "<em>Сіз жүйеге кірмегенсіз. IP мекенжайыңыз бұл беттің өңделу тарихында жазылып алынады.</em>",
        "rev-suppressed-unhide-diff": "Бір түзетуі (нұсқасы) <strong>жасырылған</strong>.\nЕгжей-тегжейін [{{fullurl:{{#Special:Log}}/delete|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}}/delete|page={{FULLPAGENAMEE}}}} Жасыру журналынан] егжей-тегжейін таба аласыз.",
-       "rev-delundel": "көÑ\80Ñ\96нÑ\96Ñ\81Ñ\96н Ó©Ð·Ð³ÐµÑ\80Ñ\82Ñ\83",
+       "rev-delundel": "көÑ\80Ñ\81еÑ\82/жаÑ\81Ñ\8bÑ\80",
        "rev-showdeleted": "көрсету",
        "revisiondelete": "Нұсқаларды жою/жоюды болдырмау",
        "revdelete-nooldid-title": "Нысана түзету жарамсыз",
        "revdelete-success": "'''Түзету көрінісі сәтті жаңартылды.'''",
        "revdelete-failure": "'''Түзету көрінісі жаңартылмады:'''\n$1",
        "logdelete-success": "'''Журнал көрінісі сәтті қойылды.'''",
-       "revdel-restore": "Ð\9aөрінісін өзгерту",
+       "revdel-restore": "көрінісін өзгерту",
        "pagehist": "Бет тарихы",
        "deletedhist": "Жойылған тарихы",
        "revdelete-otherreason": "Басқа/қосымша себеп:",
        "powersearch-togglelabel": "Белгілеу:",
        "powersearch-toggleall": "Барлығы",
        "powersearch-togglenone": "Ешқандай",
+       "powersearch-remember": "Келесі іздеулер үшін таңдалғанды есте сақтау",
        "search-external": "Сыртқы іздеу",
        "searchdisabled": "{{SITENAME}} іздеу қызметі өшірілген.\nӘзірше Google арқылы іздеуге болады.\nАңғартпа: {{SITENAME}} торабының мағлұмат тізбелері ескірген болуы мүмкін.",
        "search-error": "Іздеген кезде қате кездесті: $1",
        "license-nopreview": "(Қарап шығу жетімді емес)",
        "upload_source_url": "(жарамды, баршаға қатынаулы URL)",
        "upload_source_file": "(компьютеріңіздегі файл)",
+       "listfiles-delete": "жою",
        "listfiles-summary": "Бұл арнайы бетте барлық жүктелген файлдар көрсетіледі.",
        "listfiles_search_for": "Медиа атауын іздеу:",
        "imgfile": "файл",
        "nolinkshere": "'''[[:$1]]''' дегенге еш бет сілтемейді.",
        "nolinkshere-ns": "Таңдалған есім кеңістігінде '''[[:$1]]''' дегенге ешқандай бет сілтемейді.",
        "isredirect": "бағыттау беті",
-       "istemplate": "кірікбет",
+       "istemplate": "кіріcтірілген",
        "isimage": "файл сілтемесі",
        "whatlinkshere-prev": "{{PLURAL:$1|алдыңғы|алдыңғы $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|келесі|келесі $1}}",
        "whatlinkshere-links": "← сілтемелер",
-       "whatlinkshere-hideredirs": "Ð\91аÒ\93Ñ\8bÑ\82Ñ\82аÑ\83Ñ\88Ñ\8bлаÑ\80дÑ\8b $1",
+       "whatlinkshere-hideredirs": "баÒ\93Ñ\8bÑ\82Ñ\82аÑ\83 Ð±ÐµÑ\82Ñ\82еÑ\80Ñ\96н $1",
        "whatlinkshere-hidetrans": "кіріcтірілген беттерді $1",
        "whatlinkshere-hidelinks": "сілтемелерді $1",
        "whatlinkshere-hideimages": "файл сілтемелерін $1",
        "ipblocklist-empty": "Бұғаттау тізімі бос.",
        "ipblocklist-no-results": "Сұратылған IP мекенжай немесе қатысушы аты бұғатталмаған.",
        "blocklink": "бұғаттау",
-       "unblocklink": "бұÒ\93аÑ\82Ñ\82амау",
+       "unblocklink": "бұÒ\93аÑ\82Ñ\8bнан Ñ\88Ñ\8bÒ\93аÑ\80у",
        "change-blocklink": "бұғаттауын өзгерту",
        "contribslink": "үлесі",
        "emaillink": "хат жіберу",
index 159b32b..bc8eef8 100644 (file)
        "talkpagelinktext": "토론",
        "specialpage": "특수 문서",
        "personaltools": "개인 도구",
-       "postcomment": "새 문단",
        "articlepage": "문서 보기",
        "talk": "토론",
        "views": "보기",
        "externaldberror": "바깥 인증 데이터베이스에 오류가 있거나 바깥 계정을 새로 고칠 권한이 없습니다.",
        "login": "로그인",
        "nav-login-createaccount": "로그인 / 계정 만들기",
-       "loginprompt": "{{SITENAME}}에 로그인하려면 쿠키를 사용할 수 있어야 합니다.",
        "userlogin": "로그인 / 계정 만들기",
        "userloginnocreate": "로그인",
        "logout": "로그아웃",
        "nologin": "계정이 없나요? $1.",
        "nologinlink": "계정을 만드세요",
        "createaccount": "계정 만들기",
-       "gotaccount": "계정이 이미 있다면, $1.",
+       "gotaccount": "계정이 이미 있습니까? $1.",
        "gotaccountlink": "로그인하세요",
        "userlogin-resetlink": "로그인 정보를 잊으셨나요?",
        "userlogin-resetpassword-link": "비밀번호를 잊으셨나요?",
        "userlogin-helplink2": "로그인에 대한 도움말",
-       "userlogin-loggedin": "이미 $1로 로그인되어 있습니다. 아래의 양식을 사용하여 다른 계정으로 로그인하세요.",
+       "userlogin-loggedin": "이미 {{GENDER:$1|$1}} 사용자로 로그인되어 있습니다.\n다른 사용자로 로그인하려면 아래의 양식을 사용하세요.",
        "userlogin-createanother": "다른 계정 만들기",
        "createacct-emailrequired": "이메일 주소",
        "createacct-emailoptional": "이메일 주소 (선택 사항)",
        "revdelete-text-text": "삭제된 판은 여전히 문서 역사에 남게 되지만, 그 내용의 일부는 다른 사람들이 접근할 수 없게 됩니다.",
        "revdelete-text-file": "삭제된 파일 버전은 계속 파일 역사에 남게 되지만, 내용의 일부는 다른 사람들이 접근할 수 없게 됩니다.",
        "logdelete-text": "삭제된 로그 내용은 로그에 보여지겠지만, 내용의 일부는 다른 사람들이 접근할 수 없게 됩니다.",
-       "revdelete-text-others": "{{SITENAME}}에 있는 다른 관리자는 여전히 숨겨진 내용에 접근할 수 있고 추가 제한이 설정되어 있지 않으면, 이 같은 인터페이스를 통해 다시 되살릴 수 있습니다.",
+       "revdelete-text-others": "다른 관리자는 여전히 숨겨진 내용에 접근할 수 있고 추가 제한이 설정되어 있지 않으면, 다시 되살릴 수 있습니다.",
        "revdelete-confirm": "이 작업을 수행하는 것의 결과를 알고 있으며, [[{{MediaWiki:Policy-url}}|정책]]에 맞는 행동인지 확인해주세요.",
        "revdelete-suppress-text": "숨기기는 '''다음 경우에만''' 사용되어야 합니다:\n* 잠재적인 비방 정보\n* 부적절한 개인 정보\n*: 집 주소, 전화번호, 주민등록번호 등",
        "revdelete-legend": "보이기 제한을 설정",
        "prefs-dateformat": "날짜 형식",
        "prefs-timeoffset": "시차 설정",
        "prefs-advancedediting": "일반 설정",
-       "prefs-editor": "편집",
+       "prefs-editor": "편집",
        "prefs-preview": "미리 보기",
        "prefs-advancedrc": "고급 설정",
        "prefs-advancedrendering": "고급 설정",
        "rcshowhidemine-show": "보이기",
        "rcshowhidemine-hide": "숨기기",
        "rclinks": "최근 $2일간의 $1개 바뀐 문서 보기<br />$3",
-       "diff": "비교",
+       "diff": "차이",
        "hist": "역사",
        "hide": "숨기기",
        "show": "보이기",
        "license": "라이선스:",
        "license-header": "라이선스",
        "nolicense": "선택하지 않음",
+       "licenses-edit": "라이선스 옵션 편집",
        "license-nopreview": "(미리 보기 불가능)",
        "upload_source_url": "(올바르고, 공개적으로 접근할 수 있는 URL)",
        "upload_source_file": " (당신의 컴퓨터에 있는 파일)",
+       "listfiles-delete": "삭제",
        "listfiles-summary": "이 특수 문서는 모든 올려진 파일을 보여줍니다.",
        "listfiles_search_for": "다음 미디어 이름 검색:",
        "imgfile": "파일",
        "wantedpages-badtitle": "문서 제목이 잘못되었습니다: $1",
        "wantedfiles": "필요한 파일 목록",
        "wantedfiletext-cat": "다음 파일은 쓰이고는 있지만 없는 파일입니다. 바깥 저장소에 있는 파일은 실제로는 있지만 여기 올라 있을 수 있습니다. 그런 오류는 <del>삭제선</del>이 그어질 것입니다. 또한 없는 파일을 포함하고 있는 문서는 [[:$1]]에 올라 있습니다.",
-       "wantedfiletext-nocat": "다음 파일은 쓰이고는 있지만 없는 파일입니다. 바깥 저장소에 있는 파일은 실제로는 있지만 여기 올라 있을 수 있습니다. 그런 오류는 <del>삭제선</del>이 그어질 것입니다.",
+       "wantedfiletext-cat-noforeign": "다음 파일은 쓰이고 있지만 존재하지 않습니다. 또한, 존재하지 않는 파일이 포함된 문서가 [[:$1]]에 나열되어 있습니다.",
+       "wantedfiletext-nocat": "다음 파일은 쓰이고 있지만 존재하지 않습니다. 바깥 저장소에 있는 파일은 실제로는 있지만 여기 올라 있을 수 있습니다. 그런 오류는 <del>삭제선</del>이 그어질 것입니다.",
+       "wantedfiletext-nocat-noforeign": "다음 파일은 쓰이고 있지만 존재하지 않습니다.",
        "wantedtemplates": "필요한 틀 목록",
        "mostlinked": "가장 많이 연결된 문서 목록",
        "mostlinkedcategories": "가장 많이 연결된 분류 목록",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|토론]])",
        "unknown_extension_tag": "알 수 없는 확장 기능 태그 \"$1\"",
        "duplicate-defaultsort": "'''경고:''' 기본 정렬 키 \"$2\"가 이전의 기본 정렬 키 \"$1\"를 덮어쓰고 있습니다.",
+       "duplicate-displaytitle": "<strong>경고:</strong> \"$2\" 제목 표시는 기존의 표시되는 제목 \"$1\"을 덮어씁니다.",
        "version": "버전",
        "version-extensions": "설치된 확장 기능",
        "version-skins": "설치된 스킨",
        "expand_templates_remove_nowiki": "결과에서 <nowiki> 태그를 숨기기",
        "expand_templates_generate_xml": "XML 구문 트리 보기",
        "expand_templates_generate_rawhtml": "원본 HTML 보이기",
-       "expand_templates_preview": "미리 보기"
+       "expand_templates_preview": "미리 보기",
+       "pagelanguage": "문서 언어 선택기",
+       "pagelang-name": "문서",
+       "pagelang-language": "언어",
+       "pagelang-use-default": "기본 언어 사용",
+       "pagelang-select-lang": "언어 선택",
+       "right-pagelang": "문서 언어 바꾸기",
+       "action-pagelang": "문서 언어 바꾸기",
+       "log-name-pagelang": "언어 바꾸기 기록",
+       "log-description-pagelang": "문서 언어를 바꾼 기록입니다.",
+       "logentry-pagelang-pagelang": "$1 사용자가 $3의 문서 언어를 $4에서 $5로 {{GENDER:$2|바꾸었습니다}}."
 }
index aba2a76..583b573 100644 (file)
        "pagecategories": "{{PLURAL:$1|Saachjrupp|Saachjruppe}}",
        "category_header": "Atikkele en dä Saachjrupp „$1“",
        "subcategories": "Ungerjruppe",
-       "category-media-header": "Dateie en de Saachjrupp \"$1\"",
+       "category-media-header": "Dateije en dä Saachjropp „$1“",
        "category-empty": "''En dä Saachjrupp heh sin kein Sigge un kein Dateie.''",
        "hidden-categories": "Verstoche Saachjrupp{{PLURAL:$1||e|e}}",
        "hidden-category-category": "Verstoche Saachjruppe",
        "duplicate-defaultsort": "'''Opjepaß:'''\nDä Shtanndat-Zoot-Schlößel „$1“ övverschriif dä älldere Zoot-Schlößel „$2“.",
        "version": "Väsjohn vun de Wiki Soffwär zeije",
        "version-extensions": "Installeete Erjänzunge un Zohsätz",
+       "version-skins": "Ovverflääsche",
        "version-specialpages": "{{int:nstab-special}}e",
        "version-parserhooks": "De Parser-Hooke",
        "version-variables": "Variable",
        "version-antispam": "SPAM verhendere",
-       "version-skins": "Ovverflääsche",
        "version-api": "<i lang=\"en\">API</i>",
        "version-other": "Söns",
        "version-mediahandlers": "Medije-Handler",
index f4ecf82..611f1a2 100644 (file)
        "talkpagelinktext": "gotûbêj",
        "specialpage": "Rûpela taybet",
        "personaltools": "Amûrên kesane",
-       "postcomment": "Beşeke nû",
        "articlepage": "Li rûpela naverokê binêre",
        "talk": "Gotûbêj",
        "views": "Dîtin",
        "externaldberror": "Çewtiyeke bingeha daneyan heye, an jî destûra te ya rojanekirina hesabê xweyê navxweyî nîne.",
        "login": "Têkeve",
        "nav-login-createaccount": "Têkeve / hesabekî nû çêke",
-       "loginprompt": "<b>Eger tu xwe nû tomar bikî, nav û şîfreya xwe hilbijêre.</b> Ji bo tomarkirina te ya di {{SITENAME}} de divê ku ''cookies'' gengaz bin.",
        "userlogin": "Têkeve an hesabekî nû çêke",
        "userloginnocreate": "Têkeve",
        "logout": "Derkeve",
        "gotaccountlink": "Têkeve",
        "userlogin-resetlink": "Te agahiyên hesabê xwe ji bîr kirin?",
        "userlogin-resetpassword-link": "Şîfreyê ji nû ve çêke",
+       "userlogin-helplink2": "Alîkariya têketinê",
        "createacct-emailrequired": "E-name",
        "createaccountmail": "Use a temporary random password and send it to the email address specified below",
        "createaccountreason": "Sedem:",
        "recentchanges-legend-newpage": "$1 - rûpela nû",
        "rclistfrom": "Guherandinên ji $3 $2 şûnde nîşan bide",
        "rcshowhideminor": "Guherandinên biçûk $1",
+       "rcshowhideminor-show": "nîşan bide",
+       "rcshowhideminor-hide": "veşêre",
        "rcshowhidebots": "Bot'an $1",
-       "rcshowhideliu": "Bikarhênerên qeydkirî $1",
-       "rcshowhideanons": "Bikarhênerên neqeydkirî (IP) $1",
+       "rcshowhidebots-show": "nîşan bide",
+       "rcshowhidebots-hide": "veşêre",
+       "rcshowhideliu": "Bikarhênerên tomarkirî $1",
+       "rcshowhideliu-show": "nîşan bide",
+       "rcshowhideliu-hide": "veşêre",
+       "rcshowhideanons": "Bikarhênerên netomarkirî (IP) $1",
+       "rcshowhideanons-show": "nîşan bide",
+       "rcshowhideanons-hide": "veşêre",
        "rcshowhidepatr": "Guherandinên kontrolkirî $1",
        "rcshowhidemine": "Guherandinên min $1",
+       "rcshowhidemine-show": "nîşan bide",
+       "rcshowhidemine-hide": "veşêre",
        "rclinks": "$1 guherandinên di $2 rojên dawî de nîşan bide<br />$3",
        "diff": "cudahî",
        "hist": "dîrok",
index 0eced07..6505da6 100644 (file)
        "talkpagelinktext": "Diskussioun",
        "specialpage": "Spezialsäit",
        "personaltools": "Perséinlech Tools",
-       "postcomment": "Neien Abschnitt",
        "articlepage": "Säit",
        "talk": "Diskussioun",
        "views": "Affichagen",
        "externaldberror": "Entweder ass e Feeler bei der externer Authentifizéierung geschitt, oder Dir däerft Ären externe Benotzerkont net aktualiséieren.",
        "login": "Aloggen",
        "nav-login-createaccount": "Aloggen / Benotzerkont uleeën",
-       "loginprompt": "Fir sech op {{SITENAME}} aloggen ze kënnen, mussen d'Cookien aktivéiert sinn.",
        "userlogin": "Aloggen / Benotzerkont uleeën",
        "userloginnocreate": "Umellen",
        "logout": "Ofmellen",
        "revdelete-selected-text": "{{PLURAL:$1|Erausgesicht Versioun|Erausgesicht Versioune}} vu(n) [[:$2]]:",
        "revdelete-selected-file": "{{PLURAL:$1|Erausgesicht Versioun|Erausgesicht Versioune}} vum Fichier vu(n) [[:$2]]:",
        "logdelete-selected": "Ausgewielten {{PLURAL:$1|Evenement|Evenementer}} aus dem Logbuch:",
-       "revdelete-text-others": "Aner Administrateuren op {{SITENAME}} kënnen nach ëmmer de verstoppten Inhalt gesinn an en iwwer deeselwechten Interface nees restauréieren, ausser wann zousätzlech Limitatiounen agestallt sinn.",
+       "revdelete-text-others": "Aner Administrateure kënnen nach ëmmer de verstoppten Inhalt gesinn an en nees restauréieren, ausser wann zousätzlech Limitatiounen agestallt sinn.",
        "revdelete-confirm": "Confirméiert w.e.g. datt Dir dat maache wëllt, datt Dir d'Konsequenze verstitt an datt Dir dëst an Aklang mat de [[{{MediaWiki:Policy-url}}|Richtlinne]] maacht.",
        "revdelete-suppress-text": "Ënnerdréckung sollt '''nëmmen''' an dëse Fäll benotzt ginn:\n* Informatiounen déi beleidege kéinten\n* Net ubruechte perséinlechen Informatiounen\n*: ''Adressen, Telefonsnummeren, Sozialversécherungsnummeren asw.''",
        "revdelete-legend": "Limitatioune fir d'Sichtbarkeet festleeën",
        "powersearch-togglelabel": "Markéieren:",
        "powersearch-toggleall": "All",
        "powersearch-togglenone": "Keen",
+       "powersearch-remember": "Auswiel fir zukünfteg Sichufroe verhalen",
        "search-external": "Extern sichen",
        "searchdisabled": "D'Sichfunktioun op {{SITENAME}} ass ausgeschalt. Dir kënnt iwwerdeems mat Hëllef vu Google sichen. Bedenkt awer, datt deenen hire  Sichindex fir {{SITENAME}} eventuell net dem aktuellste Stand entsprecht.",
        "search-error": "Beim Sichen ass e Feeler geschitt: $1",
        "right-deletedtext": "Geläschten Text an d'Ännerungen tëscht de geläschte Versioune weisen",
        "right-browsearchive": "Geläscht Säite sichen",
        "right-undelete": "Eng Säit restauréieren",
-       "right-suppressrevision": "Virun den Administrateure verstoppte Versiounen nokucken a restauréieren",
+       "right-suppressrevision": "Spezifesch Versioune vun alle Benotzer weisen, verstoppen a restauréieren",
+       "right-viewsuppressed": "Verstoppt Versioune weisen déi fir all Benotzer verstoppt sinn",
        "right-suppressionlog": "Privat Lëschte kucken",
        "right-block": "Aner Benotzer fir Ännerunge spären",
        "right-blockemail": "E Benotzer späre sou datt hie keng Maile verschécke kann",
        "license-nopreview": "(Kucken ouni ofzespäichere geet net)",
        "upload_source_url": " (gëlteg, ëffentlech zougänglech URL)",
        "upload_source_file": " (e Fichier op Ärem Computer)",
+       "listfiles-delete": "läschen",
        "listfiles-summary": "Op dëser Spezialsäit stinn all déi eropgeluede Fichieren.",
        "listfiles_search_for": "Sicht nom Fichier:",
        "imgfile": "Fichier",
        "wantedfiles": "Gewënscht Fichieren",
        "wantedfiletext-cat": "Dës Fichiere gi benotzt awer et gëtt se net. Fichiere aus frieme Repositorie kënnen hei gewise ginn och wann et se gëtt. All sou falsch Positiver ginn <del>duerchgestrach</del>. Zousätzlech gi Säiten an deene Fichieren dra sinn déi et net gëtt op [[:$1]] gewisen.",
        "wantedfiletext-nocat": "Dës Fichiere gi benotzt existéieren awer net. Fichieren aus frieme Repertoiren kënnen trotzdeem opgelëscht ginn. All dës positiv Fichiere ginn <del>duergestrach</del>.",
+       "wantedfiletext-nocat-noforeign": "Dës Fichiere gi benotzt awer et gëtt se net.",
        "wantedtemplates": "Gewënscht Schablounen",
        "mostlinked": "Dacks verlinkt Säiten",
        "mostlinkedcategories": "Dacks benotzt Kategorien",
        "expand_templates_generate_xml": "Weis d'Struktur vum XML",
        "expand_templates_generate_rawhtml": "HTML-Format weisen",
        "expand_templates_preview": "Kucken ouni ofzespäicheren",
+       "pagelanguage": "Eraussiche vun der Sprooch vun der Säit",
        "pagelang-name": "Säit",
        "pagelang-language": "Sprooch",
        "pagelang-use-default": "Standard-Sprooch benotzen",
        "pagelang-select-lang": "Sprooch eraussichen",
        "right-pagelang": "Sprooch vun der Säit änneren",
-       "action-pagelang": "d'Sprooch vun der Säit änneren"
+       "action-pagelang": "d'Sprooch vun der Säit änneren",
+       "log-name-pagelang": "Log vum Ännere vun der Sprooch",
+       "log-description-pagelang": "Dëst ass a Log mat den Ännerunge vun de Sprooche vun de Säiten."
 }
index 5352d96..bc79ee7 100644 (file)
        "deletethispage": "ای بلگه نه حذف بكيد",
        "undeletethispage": "ای بلگه نه حذف نكيد",
        "undelete_short": "زنه کردن {{جمی:$1|یه گل ویرایشت|$1 ویرایشتیا}}",
-       "viewdeleted_short": "بوینیت {{[جمی:$1|یه گل ویرایشت پاک بیه|$1ویرایشتیا پاک بیه}}",
+       "viewdeleted_short": "بوینیت {{[جمی:$1|یه گل ویرایشت پاکسا بیه|$1ویرایشتیا پاکسا بیه}}",
        "protect": "حمايت بكيد",
        "protect_change": "آلشت بكيد",
        "protectthispage": "ای بلگه نه حفاظت بكيد",
        "talkpagelinktext": "وت و واچ",
        "specialpage": "بلگه ويجه",
        "personaltools": "اوزاريا شصقی",
-       "postcomment": "بشه تازه",
        "articlepage": "ديئن محتوا بلگه",
        "talk": "گپ",
        "views": "ديئنيا",
        "badaccess-group0": "شما اجازه انجوم کاری که حاستیت نارین",
        "badaccess-groups": "ای کاری که شما هاستیته سی کاروریا د  {{جمی:$2|گرو|یکی د گرویا}}: $1 مئدود بیه",
        "versionrequired": "یه نسقه د نیازمنیا ویکی رسانه\n$1",
-       "versionrequiredtext": "نسقه $1 ویکی مدیا سی استفاده د ای بلگه لازم هئی .\nوه نه بوینیت [[ویجه:نسقه|نسقه بلگه]].",
+       "versionrequiredtext": "نسقه $1 ویکی مدیا سی وه کار بستن د ای بلگه لازم هئی .\nوه نه بوینیت [[ویجه:نسقه|نسقه بلگه]].",
        "ok": "خوئه",
        "retrievedfrom": "بازيافته د\"$1\"",
        "youhavenewmessages": "شما داريت $1($2)",
        "editlink": "ويرايشت",
        "viewsourcelink": "سرچشمه نه بوينيت",
        "editsectionhint": "ويرايشت يه بشق:$1",
-       "toc": "محتوايا",
+       "toc": "مینونه یا",
        "showtoc": "نشو دائن",
        "hidetoc": "قام كردن",
        "collapsible-collapse": "جم كردن",
        "thisisdeleted": "دیئن یا ورگنين $1?",
        "viewdeleted": "دیئن$1?",
        "restorelink": "{{جمی:$1|یه گل ویرایشت پاک بیه|$1 ویرایشتیا پاک بیه}}",
-       "feedlinks": "غذا Ø¯Ù\87Ù\86Ù\87:",
+       "feedlinks": "Ø®Ù\88رحÙ\88:",
        "feed-invalid": "نوع مشترک بین خورحو نامعتور",
        "feed-unavailable": "خور حونیا د دسرس نئین",
        "site-rss-feed": "خورخو RSS سی $1",
        "site-atom-feed": "خور حون Atom سی $1",
-       "page-rss-feed": "Ø®Ù\88رخو RSS سی «$1»",
+       "page-rss-feed": "Ø®Ù\88رحو RSS سی «$1»",
        "page-atom-feed": "خور حون Atom سی $1",
        "red-link-title": "$1(بلگه وجود ناره)",
        "sort-descending": "كم بيئن منظم",
        "nstab-project": "بلگه پروجه",
        "nstab-image": "جانیا",
        "nstab-mediawiki": "پيغوم",
-       "nstab-template": "قالو",
+       "nstab-template": "چوئه",
        "nstab-help": "بلگه هومياری",
        "nstab-category": "دسه",
        "nosuchaction": "چنو كاری وجود ناره",
        "badtitletext": "عنوان بلگه حاسته بیه معتور نی،یا  یه گل مئن زونی یا مئن ویکی عنوان غلطه.\nیه شایت شومل یکی با یا بیشتر کاراکتریا نبوئه سی ای موضوعیا استفاده بوئن",
        "viewsource": "سرچشمه نه بوينيت",
        "viewsource-title": "سرچشمه $1 بوينيت",
-       "actionthrottled": "عمل جلوگئری بیه",
+       "actionthrottled": "کنشت جلوگئری بیه",
        "protectedpagetext": "دای بلگه نبوئه ویرایشت یا کاریا هنی بکید",
        "viewsourcetext": "شما تونیت سرچشمه ای بلگه نه بوینیت و دش ورداریت:",
        "viewyourtext": "شما تونیت سرچشمه ویرایشتیا تونه ای د بلگه بوینیت و دشو ورداریت",
        "password-change-forbidden": "شما نتونید پاسوردیانه د ای ویکی آلشت بکید",
        "login": "اومائن",
        "nav-login-createaccount": " اومائن د سيستم/راس كردن حساو",
-       "loginprompt": "شما وا کوکیانه سی اومائن د {{SITENAME}} کوکیانه فعال بکید.",
        "userlogin": " اومائن د سيستم/راس كردن حساو",
        "userloginnocreate": "اومائن",
        "logout": "رئتن",
        "permissionserrors": "خطا اجازه دئین",
        "permissionserrorstext": "شما حق ناریت ونه انجوم بیئت, سی{{جمی:$1|دلیل|دلیلیا}} نهایی:",
        "permissionserrorstext-withaction": "شما سی $2 اجازه ناریت\nسی دمال کردن{{PLURAL:$1|reason|reasons}}:",
-       "recreate-moveddeleted-warn": "'''زنهار شما بلگه ای که وادما پاک بیه هنی راس کردیته'''\nشما باید دونسه بایت که آیا هنی سی نها گرتن ویرایشت ای بلگه خوئه.\nپاک بیئن و جمشت سی ای بلگه سی راحتی تو فراهم بیه:",
+       "recreate-moveddeleted-warn": "'''زنهار شما بلگه ای که وادما پاکسا بیه هنی راس کردیته'''\nشما باید دونسه بایت که آیا هنی سی نها گرتن ویرایشت ای بلگه خوئه.\nپاکسا بیئن و جمشت سی ای بلگه سی راحتی تو فراهم بیه:",
        "moveddeleted-notice": "ای بلگه پاک بیه.\nپاک بین و جمشت ای بلگه سی سرچشمه دئین فراهم بیه",
        "log-fulllog": "دیئن همه پهرستنومه یا",
        "edit-conflict": "مخالفت نه ویرایشت بکید",
        "page_last": "آخر",
        "histlegend": "انتخاو فرخدار:جعویا رادیو نه سی دوواره دیئن و وارسی نشو دار بکید و یا ری رئتن کلیک بکید .<br />\nشرح نوشته: '''({{int:cur}})''' = وا آخری دوواره دیئن فرخ داره '''({{ int:last}})'''= وا دواره دیئن انجوم دئنی فرخ داره  '''{{int:minoreditletter}}''' =ویرایشت کؤچک.",
        "history-fieldset-title": "ویرگار مرور ون",
-       "history-show-deleted": "فقط پاك بيه",
+       "history-show-deleted": "فقط پاكسا بيه",
        "histfirst": "قديمي تري",
        "histlast": "تازه تري",
        "historysize": "({{جمی:$1|1 بایت|$1 بایتیا}})",
        "history-feed-title": "ویرگار دوواره دیئن",
        "history-feed-description": "دوواره دیئن ویرگار سی بلگه د ویکی",
        "history-feed-item-nocomment": "$1 د\n$2",
-       "history-feed-empty": "بلگه حاسته بیه وجود ناره.\nشایت وه د ویکی پاک بیه، یا نومش آلشت بیه.\nسی بلگیا مرتوط تازه [[ویجه:پی جوری|پی جوری د ویکی]] کوششت بکید.",
+       "history-feed-empty": "بلگه حاسته بیه وجود ناره.\nشایت وه د ویکی پاکسا بیه، یا نومش آلشت بیه.\nسی بلگیا مرتوط تازه [[ویجه:پی جوری|پی جوری د ویکی]] کوششت بکید.",
        "rev-deleted-comment": "(ویرایشت چکسته جا وه جا بیه)",
        "rev-deleted-user": "(نوم کاروری جا وه جا بیه)",
        "rev-deleted-event": "(انجوم گر پهرستنومه جا وه جا بیه)",
        "rev-deleted-user-contribs": "[نوم کاروری یا نشونی آی پی جا وه جا بیه - چیا قام بیه د ور هوم یاریانه ویرایشت بکید]",
        "rev-delundel": "آلشت وضئيت ديئن",
        "rev-showdeleted": "نشو دائن",
-       "revisiondelete": "پاک کردن/زنه کردن وانئریا",
+       "revisiondelete": "پاکسا کردن/زنه کردن وانئریا",
        "revdelete-nooldid-title": "وانیری تمارزی بیه نامعتوره",
        "revdelete-no-file": "فایل مشقص بیه وجود ناره.",
        "revdelete-show-file-submit": "هری",
        "revdelete-failure": "'''دیئن وانیری وه خوئی وه هنگوم نبی:'''$1",
        "revdel-restore": "آلشت وضئيت ديئن",
        "pagehist": "ويرگار بلگه",
-       "deletedhist": "ویرگار پاک بیه",
+       "deletedhist": "ویرگار پاکسا بیه",
        "revdelete-otherreason": "دلیل هنی:",
        "revdelete-reasonotherlist": "دلیل هنی",
-       "revdelete-edit-reasonlist": "دلیلیا پاک کردنه نه ویرایشت بکید",
+       "revdelete-edit-reasonlist": "دلیلیا پاکسا کردنه نه ویرایشت بکید",
        "revdelete-offender": "نیسنه وانیری:",
        "mergehistory": "ویرگاریا بلگه نه یکی بکید",
        "mergehistory-header": "ای بلگه وه شما اجازه می ئه که وانیریانه ویرگار سرچشمه بلگه نه د یه گل بلگه تازه سریک سازی بکید.\nمطمئن بویت که ای آلشت د لحاظ ویرگاری د مین بلگه موندگار هئ.",
        "right-upload": "سوار کردن فايلا",
        "right-upload_by_url": "سوار کرد فایلیا د یو آر ال",
        "right-writeapi": "د نیسنن ای پی آی استفاده بکید",
-       "right-delete": "بلگیا نه پاک کو",
+       "right-delete": "بلگیا نه پاکسا کو",
        "right-browsearchive": "بلگه یا پاک بیه نه پی جوری کو",
        "right-undelete": "ای بلگه نه حذف نكيد",
        "right-suppressionlog": "دیئن پهرستنومه یا خصوصی",
        "action-upload": "ای فایل سوار بکید",
        "action-upload_by_url": "ای فایله نه د یو آر ال سوار بکید",
        "action-writeapi": "د نیسنن ای پی آی استفاده بکید",
-       "action-delete": "ای بلگه نه پاک کو",
+       "action-delete": "ای بلگه نه پاکسا کو",
        "action-deleterevision": "ای بازدئین پاک کو",
-       "action-deletedhistory": "ویرگار پاک بیه ای بلگه نه بوینیت",
+       "action-deletedhistory": "ویرگار پاکسا بیه ای بلگه نه بوینیت",
        "action-browsearchive": "بلگه یا پاک بیه نه پی جوری بکید",
        "action-undelete": "ای بلگه نه پاک نکو",
        "action-suppressionlog": "ای پهرستنومه خصوصی نه بوینیت",
        "upload-too-many-redirects": "ای یو آر ال د ورگیرنه واگردونیا فرئی هئ",
        "upload-copy-upload-invalid-domain": "ورداشتن سوارکردیا د ای پوشگئر د دسرس نئ.",
        "backend-fail-notexists": "فایل $1 وجود ناره.",
-       "backend-fail-delete": "نبوئه جانیا $1 پاک بوئه",
+       "backend-fail-delete": "نبوئه جانیا $1 پاکسا بوئه",
        "backend-fail-describe": "نبوئه گپ دونسمنیا سی جانیا\"$1\" آلشت بوئه.",
        "backend-fail-store": "نبوئه جانیا \"$1\" د \"$2\" امبار بوئه.",
        "backend-fail-move": "نبوئه جانیا \"$1\" د \"$2\" جا وه جا بوئه",
        "nolicense": "هیچی انتخاو نبیه",
        "license-nopreview": "(پیش سیل د دسرس نئ)",
        "upload_source_file": "(یه گل فایل د انجومیار تو)",
+       "listfiles-delete": "پاکسا کردن",
        "listfiles-summary": "ای بلگه یا ویجه همه جانیایا سوار بیه نه نشو می ئین.",
        "listfiles_search_for": "پی جوری سی نوم رسانه:",
        "imgfile": "فايل",
        "file-anchor-link": "فايل",
        "filehist": "ويرگار فايل",
        "filehist-help": "ری  ويرگاريا بپورنيت تا نسقه مرتوط بونيت.",
-       "filehist-deleteall": "همه نه پاک کو",
+       "filehist-deleteall": "همه نه پاکسا کو",
        "filehist-deleteone": "پاك كردن",
        "filehist-revert": "ورگنین",
        "filehist-current": "تازه باو",
        "shared-repo-from": "د $1",
        "filerevert-comment": "دليل:",
        "filerevert-submit": "ورگنین",
-       "filedelete": "$1 پاک کو",
+       "filedelete": "$1 پاکسا کو",
        "filedelete-legend": "فایل نه پاک کو",
        "filedelete-comment": "دليل:",
-       "filedelete-submit": "پاك كردن",
-       "filedelete-success": "$1 پاک بیه.",
+       "filedelete-submit": "پاكسا كردن",
+       "filedelete-success": "$1 پاکسا بیه.",
        "filedelete-nofile": "'''$1''' وجود ناره.",
        "filedelete-otherreason": "دلیل هنی:",
        "filedelete-reason-otherlist": "دليل هنی",
        "filedelete-edit-reasonlist": "دلیلیا پاک کردنه نه ویرایشت بکید",
-       "filedelete-maintenance-title": "نبوئه ای فایل پاک بوئه",
+       "filedelete-maintenance-title": "نبوئه ای فایل پاکسا بوئه",
        "mimesearch": "پی جوری ام آی ام ای",
        "download": "گرتن",
        "unwatchedpages": "بلگه یا ندئیه بیه",
        "double-redirect-fixer": "تعمیر کننه واگردونی",
        "brokenredirectstext": "واگردونیا نهاتر د بلگه یایی که وجود نارن هوم پیوند بینه.",
        "brokenredirects-edit": "ویرایشت",
-       "brokenredirects-delete": "پاك كردن",
+       "brokenredirects-delete": "پاكسا كردن",
        "withoutinterwiki": "بلگه یایی که هوم پیوند زون نارن",
        "withoutinterwiki-legend": "پیشون",
        "withoutinterwiki-submit": "نشون دائن",
        "allpages-hide-redirects": "واگردونیا قام بیه",
        "cachedspecial-refresh-now": "دیئن آخری.",
        "categories": "دسه يا",
-       "deletedcontributions": "هومیاریا پاک بیه کارور",
+       "deletedcontributions": "هومیاریا پاکسا بیه کارور",
        "deletedcontributions-title": "هومیاریا پاک بیه کارور",
        "sp-deletedcontributions-contribs": "هومیاریا",
        "linksearch-ns": "نوم جا:",
        "confirm": "مئكم كردن",
        "excontent": "مینونه :\"$1\" بی",
        "exbeforeblank": "مینونه حالی دمایی:\"$1\" بی",
-       "delete-confirm": "پاک کردن\"$1\"",
+       "delete-confirm": "پاکسا کردن\"$1\"",
        "delete-legend": "پاك كردن",
        "actioncomplete": "عملكرد كامل بيه",
        "actionfailed": "عملكرد شكست حرده",
        "deletecomment": "دليل:",
        "deleteotherreason": "دليليا هنی:",
        "deletereasonotherlist": "دلیل هنی",
-       "deletereason-dropdown": "* دلیلیا پاک کردن رسم بیه\n** اسپم\n** خراوکاری\n** رعایت نبین کپی رایت\n** درحاست نیسنه\n** نهاورگشت شکست حرده",
+       "deletereason-dropdown": "* دلیلیا پاکسا کردن رسم بیه\n** اسپم\n** خراوکاری\n** رعایت نبین کپی رایت\n** درحاست نیسنه\n** نهاورگشت شکست حرده",
        "rollbacklink": "ورگشتن",
        "sessionfailure-title": "شکست حردن نشینگه",
        "protectlogpage": "حفاظت کردن",
        "undeleteviewlink": "ديئن",
        "undeletecomment": "دليل:",
        "cannotundelete": "زنه کردن انجوم نبی:$1",
-       "undelete-search-title": "بلگه یا پاک بیه نه پی جوری کو",
+       "undelete-search-title": "بلگه یا پاکسا بیه نه پی جوری کو",
        "undelete-search-submit": "پی جوری",
        "undelete-error-short": "خطا پاک نبیئن جانیا:$1",
        "undelete-show-file-submit": "هری",
        "movelogpage": "جاوه جا کردن",
        "movelogpagetext": "د هار یه گل نوم گه د جا وه جایی یا بلگه هئ",
        "revertmove": "لرستن",
-       "delete_and_move": "پاک و جا وه جا بوئه",
+       "delete_and_move": "پاکسا و جا وه جا بوئه",
        "export": "وه صحرا ديئن بلگيا",
        "export-download": "ذخیره کردن جانیا",
        "allmessagesname": "نوم",
        "tooltip-ca-viewsource": "ای بلگه حفاظت بيه.\nشما تونيت سرچمه ش بئوينيت",
        "tooltip-ca-history": "دوواره ديئن ای بلگه",
        "tooltip-ca-protect": "ای بلگه نه حفاظت بكيد",
-       "tooltip-ca-delete": "ای بلگه نه حذف بكيد",
+       "tooltip-ca-delete": "ای بلگه نه پاکسا کو",
        "tooltip-ca-move": "ای بگله نه جا وه جا كو",
        "tooltip-ca-watch": "اضاف کردن ای بلگه وه نوم نوشت پیگئریاتو",
        "tooltip-ca-unwatch": "ورداشتن ای بلگه وه نوم نوشت پیگئریاتو",
index 70c362e..97903fc 100644 (file)
        "talkpagelinktext": "Diskusija",
        "specialpage": "Īpašā Lapa",
        "personaltools": "Lietotāja rīki",
-       "postcomment": "Pievienot komentāru",
        "articlepage": "Apskatīt rakstu",
        "talk": "Diskusija",
        "views": "Apskates",
        "externaldberror": "Notikusi vai nu ārējās autentifikācijas datubāzes kļūda, vai arī tev nav atļauts izmainīt savu ārējo kontu.",
        "login": "Pieslēgties",
        "nav-login-createaccount": "Izveidot jaunu lietotāju vai doties iekšā",
-       "loginprompt": "Lai ieietu {{grammar:lokatīvs|{{SITENAME}}}}, tavam datoram ir jāpieņem sīkdatnes (<i>cookies</i>).",
        "userlogin": "Izveidot jaunu lietotāju vai doties iekšā",
        "userloginnocreate": "Pieslēgties",
        "logout": "Iziet",
        "htmlform-no": "Nē",
        "htmlform-yes": "Jā",
        "htmlform-chosen-placeholder": "Izvēlieties iespēju",
+       "htmlform-cloner-create": "Pievienot vairāk",
        "sqlite-has-fts": "$1 ar pilnteksta meklēšanas atbalstu",
        "sqlite-no-fts": "$1 bez pilnteksta meklēšanas atbalsta",
        "logentry-delete-delete": "$1 {{GENDER:$2|izdzēsa}} lapu $3",
index 1379130..f6da81d 100644 (file)
@@ -8,11 +8,11 @@
                        "Erdemaslancan",
                        "Ibero-kolxi",
                        "Reedy",
-                       "The Evil IP address"
+                       "The Evil IP address",
+                       "아라"
                ]
        },
        "tog-underline": "Link'iş tude kogu3’uxaçki:",
-       "tog-rememberpassword": "Parola-skani goişini (for a maximum of $1 {{PLURAL:$1|day|days}})",
        "tog-showhiddencats": "Şinaxeri k'at'egorepe ko3'iri",
        "underline-always": "P'anda",
        "underline-never": "P'ot'e",
        "oct": "Gum",
        "nov": "Çxa",
        "dec": "Xri",
+       "january-date": "3ʼanağani $1",
+       "february-date": "Kʼundura $1",
+       "march-date": "Martʼi $1",
+       "april-date": "Apʼrili $1",
+       "may-date": "Maisi $1",
+       "june-date": "Mbuliştuta $1",
+       "july-date": "X3ala $1",
+       "august-date": "Maraşina $1",
+       "september-date": "Stʼaroşina $1",
+       "october-date": "Gumatuta $1",
+       "november-date": "Çxalva $1",
+       "december-date": "Xristʼana $1",
        "pagecategories": "Butʼkʼaşi {{PLURAL:$1|kʼatʼegori|kʼatʼegorepe}}",
        "category_header": "\"$1\" kʼatʼegoris butʼkʼape",
        "subcategories": "Tudekʼategorepe",
@@ -83,7 +95,7 @@
        "newwindow": "(ağne penceres guin3ʼkʼen)",
        "cancel": "İpʼtʼali qʼvi",
        "moredotdotdot": "Çkva…",
-       "mypage": "Çkimi sayfa",
+       "mypage": "Stʼatʼia",
        "mytalk": "Çkimi mesajepe",
        "anontalk": "Am IP'şi mesajepe",
        "navigation": "Goxtima",
        "qbedit": "Doktiri",
        "qbpageoptions": "Am sayfa",
        "qbmyoptions": "Çkimi sayfape",
-       "vector-action-delete": "Jili",
-       "vector-action-move": "Tori",
-       "vector-action-protect": "İçvi",
-       "vector-view-create": "dokʼidi",
-       "vector-view-edit": "Doktiri",
-       "vector-view-view": "İǩitxi",
        "variants": "Variant'epe",
        "errorpagetitle": "Çilata",
        "returnto": "$1 butʼkʼaşa goikti.",
        "youhavenewmessagesmulti": "$1's ağne mesajepe giğun",
        "editsection": "doktiri",
        "editold": "Doktiri",
+       "viewsourceold": "odude koz*iri",
        "editlink": "Doktiri",
        "viewsourcelink": "odude koz*iri",
        "editsectionhint": "$1 burme muşi doktiri",
        "toc": "Temaşi dudi-coxope",
        "showtoc": "ko3ʼiri",
        "hidetoc": "Doşinaxi",
+       "collapsible-collapse": "Nok’açi",
+       "viewdeleted": "Koziri $1?",
+       "feedlinks": "Omgvani:",
        "site-rss-feed": "$1 RSS-iş Feedi",
        "site-atom-feed": "$1 Atʼom-iş feedi",
        "page-rss-feed": "\"$1\" RSS-iş Feedi",
        "nstab-image": "Dosya",
        "nstab-mediawiki": "Mesaji",
        "nstab-template": "Şabloni",
+       "nstab-help": "Meşvelaşi but’k’a",
        "nstab-category": "Kʼatʼegori",
+       "error": "Çilata",
        "missing-article": "Datʼabeizik, na igoren \"$1\" $2 coxoni butʼkʼaşi tekstʼi var az*iru.\n\nMuşeni? Çunki am butʼkʼa, jileri na ren a butʼkʼaşi golaxteri versiyoni ren.\n\nEger sebebi aya na va renna, pʼrogramis ar çilata z*irit.\nMu iqʼven! Aya, a [[Special:ListUsers/sysop|adminis]], URL-ti çʼareli şekʼilite rapʼortʼi doçʼarit.",
        "missingarticle-rev": "(revizyoni#: $1)",
        "badtitle": "Varixmarinen boxoxia",
        "badtitletext": "Na içʼaren butʼkʼaşi coxo ya çilatoni ren ya boşi ren varna inter-nena do inter-vikʼişi kʼontʼaktʼis na uğutʼu şeni mtini varen.\nDudicoxopes oxmaruşi yasaği na ren ar, varna daha dido kʼarakʼtʼeri uğun.",
        "viewsource": "Odudes o3ʼkʼedi",
+       "welcomeuser": "K'aobaten, $1!",
        "yourname": "Skani maxmare-coxo:",
+       "userlogin-yourname": "Skani maxmare-coxo",
        "yourpassword": "Pʼarola-skani:",
+       "userlogin-yourpassword": "Pʼarola-skani",
        "remembermypassword": "Parola-skani goişini (for a maximum of $1 {{PLURAL:$1|day|days}})",
+       "yourdomainname": "Skani domaini:",
        "login": "Sitʼeşa amaxti",
        "nav-login-createaccount": "Sitʼeşa amaxti / hesabi dokʼidi",
        "userlogin": "Sitʼeşa amaxti / hesabi dokʼidi",
+       "userloginnocreate": "Sitʼeşa amaxti",
        "logout": "Siteşen Kogamaxti",
        "userlogout": "Siteşen Kogamaxti",
+       "userlogin-joinproject": "{{SITENAME}}işe ak’ati",
        "nologin": "Hesabi va giğuni? '''$1'''",
        "nologinlink": "Hesabi dokʼidi.",
        "createaccount": "Hesabi dokʼidi",
        "gotaccountlink": "Sitʼeşa amaxti",
+       "createaccountreason": "Muşen:",
+       "createacct-reason": "Muşen",
        "mailmypassword": "Ağne pʼarola-çkimi moncğoni",
        "loginlanguagelabel": "Nena: $1",
        "oldpassword": "Mcveşi p'arola:",
        "newpassword": "Ağani P'arola:",
+       "passwordreset-username": "Skani maxmare-coxo:",
        "bold_sample": "Mçxu nçʼara",
        "bold_tip": "Mçxu nçʼara",
        "italic_sample": "Elakteri nçʼara",
        "nextrevision": "Ağani xali-muşi →",
        "currentrevisionlink": "İrişen ağne xali-muşi ko3ʼiri",
        "cur": "farkʼi",
+       "next": "ok’uleni",
        "last": "çodina",
+       "page_first": "iptineri",
+       "page_last": "çodina",
        "histlegend": "Farkʼiş 3xuna: o3xunu şeni na ginon 2 versiyoniş na go3ʼadgin dairepeşa gebaz*gi, do ukvule entʼerişa gebaz*gi varna butʼkʼaşi tude na dgin tʼuşişa gebaz*gi.<br />\nOxo3ʼonapape: (a3ʼineri) = a3ʼineri versiyoni kʼala na ren farkʼi,\n(iptineri) = iptineri versiyoni kʼala na ren farkʼi, Çʼ = çʼitʼa oktiroba.",
        "history-fieldset-title": "Golaxteris o3ʼkʼedi",
        "history-show-deleted": "Xvala nijilenepe",
        "histfirst": "irişen mcveşi",
        "histlast": "irişen ağani",
        "rev-delundel": "ko3ʼiri/doşinaxi",
-       "revdelete-radio-set": "Ho",
+       "rev-showdeleted": "ko3ʼiri",
+       "revdelete-show-file-submit": "Ho",
+       "revdelete-radio-set": "Şinaxeri",
        "revdelete-radio-unset": "Var",
        "revdel-restore": "Ozʼiramuşi doktiri",
        "revertmerge": "Artikʼartişen okʼo3ʼkʼi",
        "search-section": "(burme $1)",
        "search-suggest": "Aya çʼari-i: $1",
        "search-interwiki-caption": "Cuma projepe",
-       "search-interwiki-default": "$1 sonucepe:",
+       "search-interwiki-default": "$1'işi sonucepe:",
        "search-interwiki-more": "(çkva)",
        "searchall": "mteli",
        "powersearch-legend": "Mordineri ogoru",
        "powersearch-ns": "Svacoxo-s mgori:",
-       "powersearch-redir": "Redirektʼepe ilistʼeli",
+       "powersearch-toggleall": "İri",
+       "powersearch-togglenone": "Çkari",
        "preferences": "Tercihepe",
        "mypreferences": "Çkimi tercihepe",
        "searchresultshead": "Mgori",
        "timezoneregion-antarctica": "Antartik'a",
        "timezoneregion-asia": "Asya",
        "timezoneregion-europe": "Avrop'a",
+       "prefs-searchoptions": "Mgori",
        "youremail": "E-maili:",
        "yourrealname": "Coxo skani:",
        "yourlanguage": "Nena skani:",
-       "gender-male": "Biç'i",
-       "gender-female": "Bozo (K'ulani)",
+       "gender-male": "Biç'ik wikişi but'k'ape nkturams",
+       "gender-female": "Bozok wikişi but'k'ape nkturams",
        "email": "E-maili",
        "group": "Grubi:",
+       "group-user": "K'oçepe",
+       "group-bot": "Botepe",
        "group-sysop": "Adminepe",
+       "group-all": "(iri)",
        "grouppage-sysop": "{{ns:project}}:Adminepe",
+       "right-read": "But’k’ape ik’itxi",
+       "right-edit": "But'k'ape nkturi",
        "right-delete": "Am sayfape jili",
        "newuserlogpage": "Ağani maxmareş kʼayitʼepe",
        "rightslog": "Maxmareş hakʼişi kʼayitʼepe",
        "recentchanges": "Çodinaşi oktirobape",
        "recentchanges-legend": "Çodinaşi oktirobape tercihepe",
        "recentchanges-feed-description": "Am feedis vikiʼs na ixvenu irişen sonni oktirobape gatxozi.",
-       "rclistfrom": "$1 tarixişen doni na ixvenu oktirobape ko3ʼiri",
+       "rclistfrom": "$3 $2 tarixişen doni na ixvenu oktirobape ko3ʼiri",
        "rcshowhideminor": "çʼitʼa oktirobape $1",
+       "rcshowhideminor-show": "Ko3ʼiri",
+       "rcshowhideminor-hide": "Şinaxi",
        "rcshowhidebots": "botʼepe $1",
+       "rcshowhidebots-show": "Ko3ʼiri",
+       "rcshowhidebots-hide": "Şinaxi",
        "rcshowhideliu": "meçʼareri maxmarepe $1",
+       "rcshowhideliu-show": "Ko3ʼiri",
+       "rcshowhideliu-hide": "Şinaxi",
        "rcshowhideanons": "anonimuri maxmarepe $1",
+       "rcshowhideanons-show": "Ko3ʼiri",
+       "rcshowhideanons-hide": "Şinaxi",
+       "rcshowhidepatr-show": "Ko3ʼiri",
+       "rcshowhidepatr-hide": "Şinaxi",
        "rcshowhidemine": "çkimi oktirobape $1",
+       "rcshowhidemine-show": "Ko3ʼiri",
+       "rcshowhidemine-hide": "Şinaxi",
        "rclinks": "Çodinaşi $2 ndğas na ixvenu çodinaşi $1 oktiroba ko3ʼiri;<br /> $3",
        "diff": "farkʼi",
        "hist": "tarixi",
        "booksources-go": "İgzali",
        "log": "Kʼayitʼepe",
        "allpages": "Mteli butʼkʼape",
-       "alphaindexline": "$1 butʼkʼa muşişen $2 butʼkʼa muşişa",
        "prevpage": "İptineri butʼkʼa ($1)",
        "allpagesfrom": "Olistʼeluşa na geiçʼkʼasen harfepe:",
        "allpagesto": "Amu kʼala na içodu butʼkʼape ko3ʼiri:",
index ccaae87..9ea3ca3 100644 (file)
        "talkpagelinktext": "Dinika",
        "specialpage": "Pejy manokana",
        "personaltools": "Fitaovana manokana",
-       "postcomment": "Hametraka fanamarihana",
        "articlepage": "Hijery ny votoatin'ny pejy",
        "talk": "dinika",
        "views": "Fijerena",
        "externaldberror": "Nisy tsy fetezana angamba teo amin'ny fanamarinana anao tamin'ny sehatra ivelan'ity wiki ity, na tsy manana alalana hanova ny kaontinao ivelany ianao.",
        "login": "Midira",
        "nav-login-createaccount": "Ampidiro ny solonanarana",
-       "loginprompt": "\nMila manaiky cookies ianao raha te hiditra amin'ny {{SITENAME}}.",
        "userlogin": "Hiditra na hanokatra kaonty",
        "userloginnocreate": "hiditra",
        "logout": "Hiala",
        "undo-summary-username-hidden": "Namafa ny famerenana $1 nataom-pikambana afenina",
        "cantcreateaccounttitle": "Tsy afaka manokatra kaonty ianao.",
        "cantcreateaccount-text": "Voasakan'i [[User:$3|$3]] ny fanokafana kaonty avy amin'ity adiresy IP (<b>$1</b>)\n\n''$2'' ny antony.",
+       "cantcreateaccount-range-text": "Nosakanan'i [[User:$3|$3]] ny fanokafana kaonty avy amin'ny adiresy IP ao amin'ny elanelana '''$1''' izay ahitana ny adiresy IP-nao ('''$4''').",
        "viewpagelogs": "Hijery ny fanovan'ity pejy ity",
        "nohistory": "Tsy manana tantaram-panovana io pejy io.",
        "currentrev": "Votoatiny ankehitriny",
        "currentrev-asof": "Endrika tamin'ity $1 ity",
        "revisionasof": "Endrik'io pejy io tamin'ny $1",
-       "revision-info": "Endrika tamin'ny $1 nataon'i $2",
+       "revision-info": "Endrika tamin'ny $1 nataon'i {{GENDER:$6|$2}}$7",
        "previousrevision": "← Endrika tranainy kokoa",
        "nextrevision": "Endrika vaovao kokoa →",
        "currentrevisionlink": "Endrika farany indrindra",
        "right-move": "Manakisaka pejy",
        "right-move-subpages": "Manakisaka pejy miarak'amin'ny zana-pejiny",
        "right-move-rootuserpages": "Mamindra ny renipejin'ny mpikambana",
+       "right-move-categorypages": "Hanetsika ny pejin-tsokajy",
        "right-movefile": "Manova anarana rakitra",
        "right-suppressredirect": "Afaka tsy manometraka redirect avy amin'ny lohateny fiavina",
        "right-upload": "Mampidi-drakitra",
        "action-createpage": "hanao pejy",
        "action-createtalk": "hanao pejin-dresaka",
        "action-createaccount": "amboary io kaontim-pikambana io",
+       "action-history": "hijery ny tantaran'ity pejy ity",
        "action-minoredit": "Mariho ho kely ity fanovana ity",
        "action-move": "hamindra io pejy io",
        "action-move-subpages": "hamindra io pejy io sy ny zanapejiny",
        "action-move-rootuserpages": "hanolo anaran'ny pejin'ny mpikambana",
+       "action-move-categorypages": "hanetsika ny pejin-tsokajy",
        "action-movefile": "manova anaran'ny rakitra iray",
        "action-upload": "hampiditra io rakitra io",
        "action-reupload": "Hanolo io rakitra efa misy io",
        "license-nopreview": "(Tsy misy topi-maso)",
        "upload_source_url": " (URL misy ary azo vangian'ny daholobe)",
        "upload_source_file": " (rakitra eo amin'ny milinao)",
+       "listfiles-delete": "fafao",
        "listfiles-summary": "Ahitana ny rakitra rehetra nampidirina ity pejy manokana ity.",
        "listfiles_search_for": "Hitady anarana media :",
        "imgfile": "rakitra",
        "listfiles_size": "Habe",
        "listfiles_description": "Visavisa",
        "listfiles_count": "Version",
+       "listfiles-show-all": "Hampiditra ny versiona talohan'ny sary",
        "listfiles-latestversion": "Filaza ankehitriny",
        "listfiles-latestversion-yes": "Eny",
        "listfiles-latestversion-no": "Tsia",
index d484acf..9728a18 100644 (file)
        "talkpagelinktext": "Разговор",
        "specialpage": "Специјална страница",
        "personaltools": "Лични алатки",
-       "postcomment": "Ново заглавие",
        "articlepage": "Преглед на содржината",
        "talk": "Разговор",
        "views": "Посети",
        "externaldberror": "Настана грешка при надворешното најавување на базата или пак немате дозвола да ја подновите вашата надворешна сметка.",
        "login": "Најава",
        "nav-login-createaccount": "Најава / регистрација",
-       "loginprompt": "За да се најавите на {{SITENAME}} мора да користите колачиња.",
        "userlogin": "Најава / регистрација",
        "userloginnocreate": "Најава",
        "logout": "Одјава",
        "revdelete-text-text": "Избришаните преработки сепак се појавуваат во историјата, но делови од нивната содржина ќе бидат недостапни за јавноста.",
        "revdelete-text-file": "Избришаните верзии на податотеките сепак се појавуваат во нејзината историја, но делови од нивната содржина ќе бидат недостапни за јавноста.",
        "logdelete-text": "Избришаните дневнички ставки сепак се појавуваат во дневниците, но делови од нивната содржина ќе бидат недостапни за јавноста.",
-       "revdelete-text-others": "Другите администратори на {{SITENAME}} сепак ќе имаат пристап до скриените содржини и ќе можат да го повратат избришаното преку овој ист посредник, доколку не ставите дополнителни ограничувања.",
+       "revdelete-text-others": "Другите администратори на сепак ќе имаат пристап до скриените содржини и ќе можат да го повратат избришаното преку овој ист посредник, доколку не ставите дополнителни ограничувања.",
        "revdelete-confirm": "Потврдете дека сакате да го направите ова, дека ги сфаќате последиците, и дека тоа го правите во согласност со [[{{MediaWiki:Policy-url}}|правилата]].",
        "revdelete-suppress-text": "Притајувањето се користи '''само''' во следниве случаи:\n* Потенцијално клеветнички информации\n* Несоодветни лични информации\n*: ''домашни адреси и телефонски броеви, матични броеви и тн.''",
        "revdelete-legend": "Постави ограничувања за видливост",
        "right-deletedtext": "Прегледување на избришан текст и промени помеѓу избришани преработки",
        "right-browsearchive": "Пребарување на избришани страници",
        "right-undelete": "Обновување избришана страница",
-       "right-suppressrevision": "Прегледување и враќање на преработки скриени од администратори",
+       "right-suppressrevision": "Прегледување, скривање и откривање на поединечни преработки на страници од било кој корисник",
+       "right-viewsuppressed": "Преглед на праработки скриени од било кој корисник",
        "right-suppressionlog": "Гледање на лични дневници",
        "right-block": "Оневозможување на останати корисници да уредуваат",
        "right-blockemail": "Оневозможување корисници да праќаат е-пошта",
        "emptyfile": "Податотеката што ја подигнавте е празна.\nОва може да се должи на грешка во нејзиното име.\nПроверете дали навистина сакате да ја подигнете ваквата податотека.",
        "windows-nonascii-filename": "Опслужувачот не поддржува податотечни имиња со специјални знаци.",
        "fileexists": "Податотека со ова име веќе постои. Проверете <strong>[[:$1]]</strong> ако не {{GENDER:|сте}} сигурни дали сакате да ја промените.\n[[$1|thumb]]",
-       "filepageexists": "СÑ\82Ñ\80аниÑ\86аÑ\82а Ð·Ð° Ð¾Ð¿Ð¸Ñ\81 Ð½Ð° Ð¾Ð²Ð°Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека Ðµ Ð²ÐµÑ\9cе Ñ\81оздадена Ð½Ð° <strong>[[:$1]]</strong>, Ð½Ð¾ Ð½Ðµ Ð¿Ð¾Ñ\81Ñ\82ои Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека Ñ\81о Ñ\82оа Ð¸Ð¼Ðµ.\nÐ\9eпиÑ\81оÑ\82 ÐºÐ¾Ñ\98 Ð³Ð¾ Ð²Ð½ÐµÑ\81овÑ\82е Ð½ÐµÐ¼Ð° Ð´Ð° Ñ\81Ñ\82ои Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86аÑ\82а Ð·Ð° Ð¾Ð¿Ð¸Ñ\81.\nДоколку сакате описот да стои тука, ќе морате да го уредите рачно.\n[[$1|thumb]]",
+       "filepageexists": "Ð\9eпиÑ\81наÑ\82а Ñ\81Ñ\82Ñ\80аниÑ\86а Ð½Ð° Ð¾Ð²Ð°Ð° Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека Ðµ Ð²ÐµÑ\9cе Ñ\81оздадена Ð½Ð° <strong>[[:$1]]</strong>, Ð½Ð¾ Ð½Ðµ Ð¿Ð¾Ñ\81Ñ\82ои Ð¿Ð¾Ð´Ð°Ñ\82оÑ\82ека Ñ\81о Ñ\82оа Ð¸Ð¼Ðµ.\nÐ\9eпиÑ\81оÑ\82 ÐºÐ¾Ñ\98 Ð³Ð¾ Ð²Ð½ÐµÑ\81овÑ\82е Ð½ÐµÐ¼Ð° Ð´Ð° Ñ\81Ñ\82ои Ð½Ð° Ð¾Ð¿Ð¸Ñ\81наÑ\82а Ñ\81Ñ\82Ñ\80аниÑ\86а.\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Ако податотеката која ја проверувате е истата слика во својата изворна големина тогаш не мора да ја подигате дополнително.",
        "file-thumbnail-no": "Името на податотеката почнува со <strong>$1</strong>.\nИзгледа дека е слика со намалена големина ''(мини, thumbnail)''.\nАко ја имате оваа слика во изворна големина, подигнете ја неја. Во спротивно сменете го името на податотеката.",
        "license": "Лиценцирање:",
        "license-header": "Лиценцирање",
        "nolicense": "Нема",
+       "licenses-edit": "Измени лиценцни можности",
        "license-nopreview": "(Прегледот не е достапен)",
        "upload_source_url": " (важечка, јавно достапна URL-адреса)",
        "upload_source_file": "(податотека на вашиот компјутер)",
+       "listfiles-delete": "избриши",
        "listfiles-summary": "Оваа специјална страница ги прикажува сите подигнати податотеки.",
        "listfiles_search_for": "Побарај име на податотека:",
        "imgfile": "податотека",
        "linkstoimage-redirect": "$1 (пренасочување) $2",
        "duplicatesoffile": "{{PLURAL:$1|Следната податотека е дупликат|$1 Следните податотеки се дупликати}} на оваа податотека ([[Special:FileDuplicateSearch/$2|повеќе информации]]):",
        "sharedupload": "Оваа податотека е од $1 и може да се користи во други проекти.",
-       "sharedupload-desc-there": "Оваа податотека е од $1 и може да се користи во други проекти.\nПогледнете ја [$2 страницата за опис на податотеката] за повеќе информации.",
-       "sharedupload-desc-here": "Оваа податотека е од $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 соодветната страница].",
        "filepage-nofile": "Не постои податотека со ова име.",
        "shared-repo-from": "од $1",
        "shared-repo": "заедничко складиште",
        "shared-repo-name-wikimediacommons": "Ризницата",
-       "filepage.css": "/* Тука поставените каскадни стилски страници (CSS) се вклучени во страницата за опис на податотеката, како и на клиентските викија */",
+       "filepage.css": "/* Тука поставените каскадни стилски страници (CSS) се вклучени во описната страница на податотеката, како и на клиентските викија */",
        "upload-disallowed-here": "Нажалост, не можете да презапишете врз сликава.",
        "filerevert": "Врати $1",
        "filerevert-legend": "Врати податотека",
        "wantedpages-badtitle": "Невалиден наслов во резултатите: $1",
        "wantedfiles": "Потребни податотеки",
        "wantedfiletext-cat": "Следниве податотеки се користат, но не постојат. Податотеките од други складишта може да се наведени дури и ако постојат. Таквите ќе бидат <del>поништени</del> од списокот. Покрај ова, страниците што содржат податотеки кои не постојат се наведени на [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Следниве податотеки се користат, но не постојат. Покрај ова, страниците што ги содржат непостоечките податотеки се наведени во [[:$1]].",
        "wantedfiletext-nocat": "Следниве податотеки се користат, но не постојат. Податотеките од други складишта може да се наведени дури и ако постојат. Таквите ќе бидат <del>поништени</del> од списокот.",
+       "wantedfiletext-nocat-noforeign": "Следниве податотеки се користат, но не постојат.",
        "wantedtemplates": "Потребни шаблони",
        "mostlinked": "Најмногу врски до страници",
        "mostlinkedcategories": "Најмногу врски до категории",
        "mostinterwikis": "Страници со најмногу меѓувики",
        "mostrevisions": "Статии со најмногу верзии",
        "prefixindex": "Сите страници (со претставка)",
-       "prefixindex-namespace": "СиÑ\82е Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81о Ð¿Ñ\80еÑ\84икÑ\81 (именски простор $1)",
+       "prefixindex-namespace": "СиÑ\82е Ñ\81Ñ\82Ñ\80аниÑ\86и Ñ\81о Ð¿Ñ\80еÑ\82Ñ\81Ñ\82авка (именски простор $1)",
        "prefixindex-strip": "Отстрани ја претставката во списокот",
        "shortpages": "Кратки страници",
        "longpages": "Долги страници",
        "allmessages-filter-unmodified": "Неизменети",
        "allmessages-filter-all": "Сите",
        "allmessages-filter-modified": "Изменети",
-       "allmessages-prefix": "ФилÑ\82Ñ\80иÑ\80аÑ\98 Ð¿Ð¾ Ð¿Ñ\80еÑ\84икÑ\81:",
+       "allmessages-prefix": "ФилÑ\82Ñ\80иÑ\80аÑ\98 Ð¿Ð¾ Ð¿Ñ\80еÑ\82Ñ\81Ñ\82авка:",
        "allmessages-language": "Јазик:",
        "allmessages-filter-submit": "Оди",
        "allmessages-filter-translate": "Преведување",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|разговор]])",
        "unknown_extension_tag": "Непозната ознака на додатокот „$1“",
        "duplicate-defaultsort": "Предупредување: Основниот клуч за подредување „$2“ го поништува претходниот основен клуч за подредување „$1“.",
+       "duplicate-displaytitle": "<strong>Предупредување:</strong> Приказниот наслов „$2“ го заменува претходнито приказен наслов „$1“.",
        "version": "Верзија",
        "version-extensions": "Воспоставени додатоци",
        "version-skins": "Воспоставени рува",
index 2244079..cf77e05 100644 (file)
        "talkpagelinktext": "സംവാദം",
        "specialpage": "പ്രത്യേക താൾ",
        "personaltools": "സ്വകാര്യതാളുകൾ",
-       "postcomment": "അഭിപ്രായം ചേർക്കുക",
        "articlepage": "ലേഖനം കാണുക",
        "talk": "സംവാദം",
        "views": "ദർശനീയത",
        "externaldberror": "ഒന്നുകിൽ ഡേറ്റാബേസ് സാധൂകരണത്തിൽ പ്രശ്നം ഉണ്ടായിരുന്നു അല്ലെങ്കിൽ നവീകരിക്കുവാൻ താങ്കളുടെ ബാഹ്യ അംഗത്വം താങ്കളെ അനുവദിക്കുന്നില്ല.",
        "login": "പ്രവേശിക്കുക",
        "nav-login-createaccount": "പ്രവേശിക്കുക / അംഗത്വമെടുക്കുക",
-       "loginprompt": "{{SITENAME}} സംരംഭത്തിൽ ലോഗിൻ ചെയ്യാൻ താങ്കൾ കുക്കികൾ (Cookies) സജ്ജമാക്കിയിരിക്കണം.",
        "userlogin": "പ്രവേശിക്കുക / അംഗത്വമെടുക്കുക",
        "userloginnocreate": "പ്രവേശിക്കുക",
        "logout": "ലോഗൗട്ട്",
        "revdelete-text-text": "മായ്ക്കപ്പെട്ട നാൾപ്പതിപ്പുകൾ താളിന്റെ നാൾവഴിയിൽ കാണാവുന്നതായിരിക്കുമെങ്കിലും, അവയുടെ ഉള്ളടക്കത്തിന്റെ ചില ഭാഗങ്ങൾ പൊതുജനങ്ങൾക്ക് ലഭ്യമായിരിക്കണമെന്നില്ല.",
        "revdelete-text-file": "പ്രമാണത്തിന്റെ മായ്ക്കപ്പെട്ട പതിപ്പുകൾ താളിന്റെ നാൾവഴിയിൽ കാണാവുന്നതായിരിക്കുമെങ്കിലും, അവയുടെ ഉള്ളടക്കത്തിന്റെ ചില ഭാഗങ്ങൾ പൊതുജനങ്ങൾക്ക് ലഭ്യമായിരിക്കണമെന്നില്ല.",
        "logdelete-text": "മായ്ക്കപ്പെട്ട പ്രവൃത്തികൾ പ്രവർത്തന രേഖകളിൽ കാണാവുന്നതായിരിക്കുമെങ്കിലും, അവയുടെ ഉള്ളടക്കത്തിന്റെ ചില ഭാഗങ്ങൾ പൊതുജനങ്ങൾക്ക് ലഭ്യമായിരിക്കണമെന്നില്ല.",
-       "revdelete-text-others": "{{SITENAME}} സംരംഭത്തിലെ മറ്റ് കാര്യനിർവ്വാഹകർക്ക് മറയ്ക്കപ്പെട്ട ഉള്ളടക്കം ഇപ്പോഴും എടുക്കാവുന്നതും ആവശ്യമെങ്കിൽ ഇതേ സമ്പർക്കമുഖം ഉപയോഗിച്ച് പുനഃസ്ഥാപിക്കാനോ അല്ലെങ്കിൽ കൂടുതൽ നിബന്ധനകൾ ചേർക്കാനോ കഴിയുന്നതുമാണ്.",
+       "revdelete-text-others": "കൂടുതൽ നിബന്ധനകൾ ചേർക്കാത്ത പക്ഷം, മറ്റ് കാര്യനിർവ്വാഹകർക്ക് മറയ്ക്കപ്പെട്ട ഉള്ളടക്കം എടുക്കാനും പുനഃസ്ഥാപിക്കാനും കഴിയുന്നതാണ്.",
        "revdelete-confirm": "ഇതിന്റെ അനന്തരഫലങ്ങളെക്കുറിച്ചറിയാമെന്നും, [[{{MediaWiki:Policy-url}}|നയങ്ങൾ]] പാലിച്ചാണ് താങ്കളിത് ചെയ്യുന്നതെന്നും ഉറപ്പാക്കുക.",
        "revdelete-suppress-text": "താഴെ പറയുന്ന സാഹചര്യങ്ങളിൽ '''മാത്രമേ''' ഒതുക്കൽ ഉപയോഗിക്കാവൂ:\n* അപകീർത്തികരമായ വിവരങ്ങൾ അടങ്ങിയവ\n* അനുയോജ്യമല്ലാത്ത വ്യക്തി വിവരങ്ങൾ\n*: ''വീട്ടുവിലാസങ്ങൾ, ടെലിഫോൺ നമ്പറുകൾ, സാമൂഹിക സുരക്ഷാ നമ്പരുകൾ, തുടങ്ങിയവ.''",
        "revdelete-legend": "നാൾപ്പതിപ്പിന്റെ ദർശനീയത സജ്ജീകരിക്കുക",
        "right-deletedtext": "മായ്ക്കപ്പെട്ട എഴുത്തും താളിന്റെ മായ്ക്കപ്പെട്ട പതിപ്പുകൾ തമ്മിലുള്ള വ്യത്യാസവും കാണുക",
        "right-browsearchive": "നീക്കം ചെയ്യപ്പെട്ട താളുകളിൽ തിരയുക",
        "right-undelete": "താൾ പുനഃസ്ഥാപിക്കുക",
-       "right-suppressrevision": "കാര്യനിർവാഹകരിൽ നിന്നും മറയ്ക്കപ്പെട്ട നാൾപ്പതിപ്പുകൾ സംശോധനം ചെയ്യുക, പുനഃസ്ഥാപിക്കുക",
+       "right-suppressrevision": "മറ്റുപയോക്താക്കൾക്കായി താളുകളുടെ നാൾപ്പതിപ്പുകൾ കാണാൻ കഴിയുന്നതാക്കുക, മറയ്ക്കുക, മറയ്ക്കൽ മാാറ്റുക",
+       "right-viewsuppressed": "മറ്റുപയോക്താക്കളിൽ നിന്നും മറയ്ക്കപ്പെട്ട നാൾപ്പതിപ്പുകൾ കാണുക",
        "right-suppressionlog": "പരസ്യമല്ലാത്ത രേഖകൾ കാണുക",
        "right-block": "മറ്റുള്ള ഉപയോക്താക്കളെ മാറ്റിയെഴുതുന്നതിൽനിന്നും തടയുക",
        "right-blockemail": "ഇമെയിൽ അയക്കുന്നതിൽ നിന്നും ഉപയോക്താവിനെ തടയുക",
        "license": "പകർപ്പവകാശ വിവരങ്ങൾ:",
        "license-header": "അനുമതി",
        "nolicense": "ഒന്നും തിരഞ്ഞെടുത്തിട്ടില്ല",
+       "licenses-edit": "ഉപയോഗാനുമതി ഐച്ഛികങ്ങൾ തിരുത്തുക",
        "license-nopreview": "(പ്രിവ്യൂ ലഭ്യമല്ല)",
        "upload_source_url": "(സാധുവായ, ആർക്കും ഉപയോഗിക്കാവുന്ന യൂ.ആർ.എൽ.)",
        "upload_source_file": "(താങ്കളുടെ കമ്പ്യൂട്ടറിലുള്ള ഒരു പ്രമാണം)",
+       "listfiles-delete": "മായ്ക്കുക",
        "listfiles-summary": "അപ്‌ലോഡ് ചെയ്തിട്ടുള്ള എല്ലാ പ്രമാണങ്ങളും ഈ പ്രത്യേക താളിൽ കാണാവുന്നതാണ്.",
        "listfiles_search_for": "മീഡിയ പ്രമാണം തിരയുക:",
        "imgfile": "പ്രമാണം",
        "wantedpages-badtitle": "ഫലങ്ങളുടെ ഗണത്തിൽ അസാധുവായ തലക്കെട്ട്: $1",
        "wantedfiles": "ആവശ്യമുള്ള പ്രമാണങ്ങൾ",
        "wantedfiletext-cat": "താഴെക്കൊടുത്തിരിക്കുന്ന പ്രമാണങ്ങൾ ഉപയോഗിച്ചിട്ടുണ്ടെങ്കിലും നിലവിലില്ല. ബാഹ്യ റെപ്പോസിറ്ററികളിൽ നിന്നുള്ള പ്രമാണങ്ങൾ നിലവിലുണ്ടെങ്കിലും പട്ടികയിൽ ഉൾപ്പെട്ടിട്ടുണ്ടാവാം. അത്തരത്തിൽ തെറ്റായി ഉൾപ്പെടുത്തിയിരിക്കുന്നവ <del>വെട്ടിക്കളയുക</del>. കൂടുതലായി, നിലവിലില്ലാത്ത പ്രമാണങ്ങൾ ഉൾപ്പെടുത്തിയിട്ടുള്ള താളുകൾ കാണാൻ [[:$1]] സന്ദർശിക്കുക.",
+       "wantedfiletext-cat-noforeign": "താഴെക്കൊടുക്കുന്ന പ്രമാണങ്ങൾ നിലവിലില്ലെങ്കിലും ഉപയോഗിച്ചിട്ടുണ്ട്. കൂടുതലായി നിലവിലില്ലാത്ത എന്നാൽ ഉപയോഗിച്ചിട്ടുള്ള പ്രമാണങ്ങൾ [[:$1]] എന്ന താളിൽ കൊടുത്തിട്ടുണ്ട്.",
        "wantedfiletext-nocat": "താഴെക്കൊടുത്തിരിക്കുന്ന പ്രമാണങ്ങൾ ഉപയോഗിച്ചിട്ടുണ്ടെങ്കിലും നിലവിലില്ല. ബാഹ്യ റെപ്പോസിറ്ററികളിൽ നിന്നുള്ള പ്രമാണങ്ങൾ നിലവിലുണ്ടെങ്കിലും പട്ടികയിൽ ഉൾപ്പെട്ടിട്ടുണ്ടാവാം. അത്തരത്തിൽ തെറ്റായി ഉൾപ്പെടുത്തിയിരിക്കുന്നവ <del>വെട്ടിക്കളയുക</del>.",
+       "wantedfiletext-nocat-noforeign": "താഴെക്കൊടുത്തിരിക്കുന്ന പ്രമാണങ്ങൾ ഉപയോഗിച്ചിട്ടുണ്ടെങ്കിലും നിലവിലില്ലാത്തവയാണ്.",
        "wantedtemplates": "അവശ്യ ഫലകങ്ങൾ",
        "mostlinked": "ഏറ്റവുമധികം കണ്ണികളാൽ ചേർത്തിരിക്കുന്ന താളുകൾ",
        "mostlinkedcategories": "ഏറ്റവുമധികം താളുകൾ ചേർത്തിട്ടുള്ള വർഗ്ഗങ്ങൾ",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|സംവാദം]])",
        "unknown_extension_tag": "അജ്ഞാതമായ അനുബന്ധ റ്റാഗ് \"$1\"",
        "duplicate-defaultsort": "'''മുന്നറിയിപ്പ്:''' ക്രമപ്പെടുത്താനുള്ള ചാവിയായ \"$2\" മുമ്പ് ക്രമപ്പെടുത്താനുള്ള ചാവിയായിരുന്ന \"$1\" എന്നതിനെ അതിലംഘിക്കുന്നു.",
+       "duplicate-displaytitle": "<strong>മുന്നറിയിപ്പ്:</strong> പ്രദർശിപ്പിക്കുന്ന തലക്കെട്ട് \"$2\" മുമ്പ് പ്രദർശിപ്പിച്ചിരുന്ന തലക്കെട്ട് \"$1\" എന്നതിനെ അതിലംഘിക്കുന്നു.",
        "version": "പതിപ്പ്",
        "version-extensions": "ഇൻസ്റ്റോൾ ചെയ്തിട്ടുള്ള അനുബന്ധങ്ങൾ",
-       "version-skins": "ദൃശ്യരൂപങ്ങൾ",
+       "version-skins": "à´\87ൻസàµ\8dà´±àµ\8dà´±àµ\8bൾ à´\9aàµ\86à´¯àµ\8dതിà´\9fàµ\8dà´\9fàµ\81à´³àµ\8dà´³ à´¦àµ\83à´¶àµ\8dയരàµ\82à´ªà´\99àµ\8dà´\99ൾ",
        "version-specialpages": "പ്രത്യേക താളുകൾ",
        "version-parserhooks": "പാഴ്‌സർ കൊളുത്തുകൾ",
        "version-variables": "ചരങ്ങൾ",
        "version-license": "മീഡിയവിക്കി ഉപയോഗാനുമതി",
        "version-ext-license": "അനുമതി",
        "version-ext-colheader-name": "അനുബന്ധം",
+       "version-skin-colheader-name": "ദൃശ്യരൂപം",
        "version-ext-colheader-version": "പതിപ്പ്",
        "version-ext-colheader-license": "ഉപയോഗാനുമതി",
        "version-ext-colheader-description": "വിവരണം",
        "expand_templates_remove_nowiki": "ഫലങ്ങളിലെ <nowiki> റ്റാഗുകൾ ഒതുക്കുക",
        "expand_templates_generate_xml": "എക്സ്.എം.എൽ. പാഴ്‌സർ ട്രീ പ്രദർശിപ്പിക്കുക",
        "expand_templates_generate_rawhtml": "അസംസ്കൃത എച്ച്.റ്റി.എം.എൽ. പ്രദർശിപ്പിക്കുക",
-       "expand_templates_preview": "എങ്ങനെയുണ്ടെന്നു കാണുക"
+       "expand_templates_preview": "എങ്ങനെയുണ്ടെന്നു കാണുക",
+       "pagelanguage": "താളിന്റെ ഭാഷാ തിരഞ്ഞെടുപ്പ് സൗകര്യം",
+       "pagelang-name": "താൾ",
+       "pagelang-language": "ഭാഷ",
+       "pagelang-use-default": "സ്വതേയുള്ള ഭാഷ ഉപയോഗിക്കുക",
+       "pagelang-select-lang": "ഭാഷ തിരഞ്ഞെടുക്കുക",
+       "right-pagelang": "താളിന്റെ ഭാഷ മാറ്റുക",
+       "action-pagelang": "താളിന്റെ ഭാഷ മാറ്റുക",
+       "log-name-pagelang": "ഭാഷ മാറ്റലിന്റെ രേഖ",
+       "log-description-pagelang": "താളുകളുടെ ഭാഷകൾ മാറ്റിയതിന്റെ രേഖകൾ ഇവിടെക്കാണാം.",
+       "logentry-pagelang-pagelang": "$3 എന്ന താളിന്റെ ഭാഷയായിരുന്ന $4, $1 $5 ആയി {{GENDER:$2|മാറ്റി}}."
 }
index 4953184..0369fc7 100644 (file)
        "talkpagelinktext": "Perbincangan",
        "specialpage": "Laman khas",
        "personaltools": "Alatan peribadi",
-       "postcomment": "Bahagian baru",
        "articlepage": "Lihat laman kandungan",
        "talk": "Perbincangan",
        "views": "Rupa",
        "externaldberror": "Berlaku ralat pangkalan data bagi pengesahan luar atau anda tidak dibenarkan mengemaskinikan akaun luar anda.",
        "login": "Log masuk",
        "nav-login-createaccount": "Log masuk / buka akaun",
-       "loginprompt": "Anda mesti membenarkan kuki untuk log masuk ke dalam {{SITENAME}}.",
        "userlogin": "Log masuk / buka akaun",
        "userloginnocreate": "Log masuk",
        "logout": "Log keluar",
        "powersearch-togglelabel": "Pilih:",
        "powersearch-toggleall": "Semua",
        "powersearch-togglenone": "Tiada",
+       "powersearch-remember": "Ingatkan pilihan untuk carian pada masa depan",
        "search-external": "Carian luar",
        "searchdisabled": "Ciri pencarian dalam {{SITENAME}} dimatikan. Anda boleh mencari melalui Google. Sila ambil perhatian bahawa indeks dalam Google mungkin bukan yang terkini.",
        "search-error": "Berlakunya ralat ketika mencari: $1",
        "license-nopreview": "(Tiada pralihat)",
        "upload_source_url": " (URL yang boleh diakses oleh orang awam)",
        "upload_source_file": " (fail dalam komputer anda)",
+       "listfiles-delete": "hapus",
        "listfiles-summary": "Laman khas ini memaparkan semua fail yang telah dimuat naik.",
        "listfiles_search_for": "Cari nama imej:",
        "imgfile": "fail",
        "movenotallowedfile": "Anda tidak mempunyai keizinan untuk memindahkan fail.",
        "cant-move-user-page": "Anda tidak mempunyai keizinan untuk memindahkan laman pengguna (tidak termasuk sublaman-sublamannya).",
        "cant-move-to-user-page": "Anda tidak mempunyai keizinan untuk memindahkan sesebuah laman ke mana-mana laman pengguna (kecuali sebagai sublamannya sahaja).",
+       "cant-move-category-page": "Anda tidak mempunyai kebenaran untuk memindah laman-laman kategori.",
+       "cant-move-to-category-page": "Anda tidak mempunyai kebenaran untuk memindah sebuah laman ke sebuah laman kategori.",
        "newtitle": "Ke tajuk baru:",
        "move-watch": "Pantau laman ini",
        "movepagebtn": "Pindahkan laman",
        "duplicate-defaultsort": "'''Amaran''': Kunci susunan asali \"$2\" membatalkan kunci susunan asali \"$1\" yang sebelumnya.",
        "version": "Versi",
        "version-extensions": "Penyambung yang dipasang",
+       "version-skins": "Rupa",
        "version-specialpages": "Laman khas",
        "version-parserhooks": "Penyangkuk penghurai",
        "version-variables": "Pemboleh ubah",
        "version-antispam": "Pencegahan spam",
-       "version-skins": "Rupa",
        "version-other": "Lain-lain",
        "version-mediahandlers": "Pengelola media",
        "version-hooks": "Penyangkuk",
index c578188..edff6ba 100644 (file)
        "talkpagelinktext": "Diskussjoni",
        "specialpage": "Paġna speċjali",
        "personaltools": "Għodda personali",
-       "postcomment": "Sezzjoni ġdida",
        "articlepage": "Ara l-artiklu",
        "talk": "Diskussjoni",
        "views": "Veduti",
        "jumptonavigation": "navigazzjoni",
        "jumptosearch": "fittex",
        "view-pool-error": "Jiddispjaċina, imma fil-mument is-servers jinsabu mgħobbija ż-żejjed.\nĦafna utenti qegħdin jippruvaw jaraw din il-paġna.\nJekk jogħġbok stenna ftit qabel ma terġa' tipprova tuża' din il-paġna.\n\n$1",
+       "generic-pool-error": "Jiddispjaċina, imma bħalissa is-servers jinsabu mgħobbija ż-żejjed.\nĦafna utenti qegħdin jippruvaw jaraw din ir-riżorsa.\nJekk jogħġbok stenna ftit qabel ma terġa' tipprova ttella' din ir-riżorsa.",
+       "pool-timeout": "Il-ħin tal-iskadenza qiegħed jistenna l-iżblokk.",
        "pool-queuefull": "Il-kju tal-''pool'' hi mimlija",
        "pool-errorunknown": "Problema mhux magħrufa",
+       "pool-servererror": "Is-servizz kontra l-pool mhux disponibbli ($1).",
        "aboutsite": "Dwar {{SITENAME}}",
        "aboutpage": "Project:Dwar",
-       "copyright": "Kontenut aċċessibli taħt $1.",
+       "copyright": "Il-kontenut huwa disponibbli taħt il-liċenzja $1 sakemm mhux indikat mod ieħor.",
        "copyrightpage": "{{ns:project}}:Copyright",
        "currentevents": "Ġrajjiet kurrenti",
        "currentevents-url": "Project:Ġrajjiet kurrenti",
        "ok": "OK",
        "retrievedfrom": "Miġjub minn \"$1\"",
        "youhavenewmessages": "Għandek $1 ($2).",
+       "youhavenewmessagesfromusers": "Għandek $1 minn {{PLURAL:$3|utent ieħor|$3utenti oħra}} ($2).",
        "youhavenewmessagesmanyusers": "Għandek $1 mingħand ħafna utenti ($2).",
-       "newmessageslinkplural": "{{PLURAL:$1|messaġġ ġdid|messaġġi ġodda}}",
-       "newmessagesdifflinkplural": "l-aħħar {{PLURAL:$1|bidla|bidliet}}",
+       "newmessageslinkplural": "{{PLURAL:$1|messaġġ ġdid|999=messaġġi ġodda}}",
+       "newmessagesdifflinkplural": "l-aħħar {{PLURAL:$1|bidla|999=bidliet}}",
        "youhavenewmessagesmulti": "Għandek messaġġi ġodda fuq $1",
        "editsection": "editja",
        "editold": "editja",
        "nospecialpagetext": "<strong>Inti għamilt rikjesta għal paġna speċjali invalida.</strong>\n\nLista ta' paġni speċjali validi tinsab hawn [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "Problema",
        "databaseerror": "Problema fid-database",
+       "databaseerror-text": "Sar żball f'kunsltazzjoni tal-bażi tad-dejta. Dan jista' jindika difett fis-softwer.",
+       "databaseerror-textcl": "Sar żball f'kunsultazzjoni tal-bażi tad-dejta.",
+       "databaseerror-query": "Kunsultazzjoni $1",
+       "databaseerror-function": "Funzjoni:$1",
+       "databaseerror-error": "Żball:$1",
        "laggedslavemode": "Twissija: Il-Paġna jista' ma jkollhiex l-affarijiet aġġornati.",
        "readonly": "Database magħluq",
        "enterlockreason": "Daħħal raġuni għala qiegħed tagħlqu, inkludi l-istima ta' meta l-għeluq se tieħu effett",
        "badarticleerror": "Din l-azzjoni ma setgħetx isseħħ fuq din il-paġna.",
        "cannotdelete": "Il-paġna jew il-fajl \"$1\" ma jistax jiġi mħassar.\nJista' jkun li diġà ġie mħassar minn xi ħaddieħor.",
        "cannotdelete-title": "Il-paġna \"$1\" ma setgħetx titħassar",
+       "delete-hook-aborted": "Il-modifika ġiet abbandunata mill-''hook''.\nMa ngħatat l-ebda spjegazzjoni.",
+       "no-null-revision": "Ma setghitx tinħoloq reviżjoni nulla ġdida għall-paġna \"$1\"",
        "badtitle": "Titlu ħażin",
        "badtitletext": "It-titlu tal-paġna rikjesta huwa invalidu, vojt, jew ġej minn żball fil-ħolqa bejn siti wiki differenti jew verżjonijiet ta' lingwi differenti tal-istess sit. Jista' wkoll ikollu wieħed jew aktar karattri li ma jistgħux jintużaw għat-titli.",
        "perfcached": "L-informazzjoni li jmiss huwa kopja ''cache'' u jista' ma jkunx aġġornat. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.",
        "namespaceprotected": "Inti m'għandhekx il-permess li timodifika paġni fin-''namespace'' '''$1''.",
        "customcssprotected": "M'għandekx il-permessi neċessarji sabiex timmodifika din il-paġna tas-CSS, minħabba li għandha tqegħid personali ta' utent ieħor.",
        "customjsprotected": "M'għandekx il-permessi neċessarji sabiex timmodifika din il-paġna tal-JavaScript, minħabba li għandha tqegħid personali ta' utent ieħor.",
+       "mycustomjsprotected": "Ma għandekx permess li teditja din il-paġna JavaScript.",
+       "myprivateinfoprotected": "Ma għandekx permess li teditja l-informazzjoni privata tiegħek.",
+       "mypreferencesprotected": "Ma għandekx permess li teditja l-preferenzi tiegħek.",
        "ns-specialprotected": "Il-paġni speċjali ma jistgħux jiġu mmodifikati.",
        "titleprotected": "Dan it-titlu ġie protett mill-ħolqien minn [[User:$1|$1]].\nIr-raġuni li ġiet mogħtija kienet ''$2''.",
+       "filereadonlyerror": "L-amministratur li sakkar offra din l-ispjegazzjoni: \"$3\".",
+       "invalidtitle-knownnamespace": "Titolu validu bin-namespace \"$2\" u t-test\"$3\"",
+       "invalidtitle-unknownnamespace": "Titolu validu b'numru tan-namespace mhux magħruf  $1 u t-test \"$2\"",
+       "exception-nologin": "Mhux qiegħed fil-kont",
+       "exception-nologin-text": "Jekk jogħġbok [[Special:Userlogin|idħol fil-kont tiegħek]] biex tkun tista' taċċessa din il-paġna jew din l-azzjoni.",
+       "exception-nologin-text-manual": "Jekk jogħġbok $1 sabiex tkuu tista' taċċessa din il-paġna jew din l-azzjoni.",
        "virus-badscanner": "Problema fil-konfigurazzjoni: antivirus mhux magħruf: ''$1''",
        "virus-scanfailed": "Tfittxija falliet (kodiċi $1)",
        "virus-unknownscanner": "antivirus mhux magħruf:",
-       "logouttext": "'''Bħalissa tinsab barra mill-kont tiegħek.'''\n\nTista' tkompli tuża' {{SITENAME}} bħala utent anonimu, jew tista' terġa <span class='plainlinks'>[$1 tidħol]</span> bħala l-istess utent jew wieħed differenti.\nKun af li ċerti paġni jistgħu jkomplu jidhru bħallikieku l-illogjar 'l barra mill-kont qatt ma seħħ, sakemm ma tħassarx il-cache tal-browser.",
+       "logouttext": "<strong>Bħalissa mhux qiegħed fil-kont tiegħek</strong>\n\nJista' jkun li xi paġni jibqgħu jidhru bħalli kieku qiegħed fil-kont, sakemm ma tneddafx il-cache tan-navigatur tiegħek.",
+       "welcomeuser": "Merħba, $1!",
+       "welcomecreation-msg": "Il-kont tiegħek inħoloq.\nJekk trid tista' tibdel il- [[Special:Preferences|preferenzi tas-]]{{SITENAME}}.",
        "yourname": "Isem l-utent:",
        "userlogin-yourname": "Isem l-utent",
        "userlogin-yourname-ph": "Daħħal isem l-utent tiegħek",
+       "createacct-another-username-ph": "Daħħal l-isem tiegħek ta' utent",
        "yourpassword": "Password:",
        "userlogin-yourpassword": "Password",
        "userlogin-yourpassword-ph": "Daħħal il-password tiegħek",
        "userlogin-remembermypassword": "Żommni fil-kont",
        "userlogin-signwithsecure": "Uża konnessjoni sigura",
        "yourdomainname": "Id-dominju tiegħek:",
+       "password-change-forbidden": "Fuq din il-wiki ma tistax tibdel il-kliem tad-dħul (passwords).",
        "externaldberror": "Kien hemm problema esterna ta' awtentiċitá jew m'għandhekx permess neċċessarju sabiex tagħmel aġġornamenti fuq l-aċċess estern.",
        "login": "Idħol",
        "nav-login-createaccount": "Idħol / Oħloq kont",
-       "loginprompt": "Irid ikollok il-cookies mixgħula biex tkun tista' tidħol fuq {{SITENAME}}.",
        "userlogin": "Idħol jew oħloq kont ġdid",
        "userloginnocreate": "Idħol",
        "logout": "Oħroġ",
        "gotaccount": "Diġa għandhek kont? '''$1'''.",
        "gotaccountlink": "Idħol",
        "userlogin-resetlink": "Insejt kif tidħol fil-kont tiegħek?",
-       "userlogin-resetpassword-link": "Irrisettja l-password",
+       "userlogin-resetpassword-link": "Insejt il-kelma tad-dħul (password)?",
+       "userlogin-helplink2": "Għajnuna biex tidħol fil-kont",
+       "userlogin-loggedin": "Diġà dħalt fil-kont bħala {{GENDER:$1|$1}}.\nUża l-formola t'hawn taħt biex tidħol bħala utent ieħor",
+       "userlogin-createanother": "Oħloq kont ieħor",
        "createacct-emailrequired": "Indirizz elettroniku",
        "createacct-emailoptional": "Indirizz elettroniku (mhux obbligatorju)",
        "createacct-email-ph": "Daħħal l-indirizz elettroniku tiegħek",
-       "createaccountmail": "Uża password każwali temporanja u ibgħatha fuq l-indirizz elettroniku mniżżel hawn taħt",
+       "createacct-another-email-ph": "Daħħal l-indirizz elettroniku",
+       "createaccountmail": "Uża kelma tad-dħul temporanja li tkun u ibgħatha lill-indirizz elettroniku speċifikat",
        "createacct-realname": "Isem proprju (fakultattiv)",
        "createaccountreason": "Raġuni:",
        "createacct-reason": "Raġuni",
        "createacct-captcha": "Kontroll tas-sigurtà",
        "createacct-imgcaptcha-ph": "Daħħal it-test li qed tara hawn fuq",
        "createacct-submit": "Oħloq il-kont",
+       "createacct-another-submit": "Oħloq kont ieħor",
        "createacct-benefit-heading": "{{SITENAME}} hi magħmula minn persuni bħalek.",
        "createacct-benefit-body1": "{{PLURAL:$1|modifika|modifiki}}",
-       "createacct-benefit-body2": "paġna",
+       "createacct-benefit-body2": "{{PLURAL:$1|paġna|paġni}}",
        "createacct-benefit-body3": "{{PLURAL:$1|kontributur|kontributuri}} riċenti",
        "badretype": "Il-passwords li daħħalt ma jaqblux.",
        "userexists": "L-isem l-utent li daħħalt diġà meħud. Jekk jogħġbok, agħżel isem differenti.",
        "passwordtooshort": "Il-password trid tkun mill-inqas {{PLURAL:$1|karattru|$1 karattri}} twila u differenti mill-isem tal-utent.",
        "password-name-match": "Il-password trid tkun differenti mill-isem tal-utent tiegħek.",
        "password-login-forbidden": "L-użu ta' dan l-isem tal-utent u l-password huwa projbit.",
-       "mailmypassword": "Ibgħatli password ġdida",
+       "mailmypassword": "Erġa' waqqaf kelma tad-dħul",
        "passwordremindertitle": "Password temporanju ġdid għal {{SITENAME}}",
        "passwordremindertext": "Xi ħadd (probabbilment int, mill-indirizz IP $1) għamel rikjesta għal password ġdida għal {{SITENAME}} ($4). Password temporanja għall-utent \"$2\" ġiet maħluqa u din hi \"$3\".\nHuwa opportun li inti tidħol issa u tbiddel immedjatament il-password tiegħek. Din il-password il-ġdida se tiskadi fi żmien {{PLURAL:$5|ġurnata|$5 ijiem}}.\n\nJekk xi ħadd ieħor għamel din ir-rikjesta jew jekk int ftakart il-password tiegħek u issa ma tridx tbiddilha, int tista' ma tagħtix każ dan il-messaġġ u tkompli tuża' l-password l-antika.",
        "noemail": "M'hemm l-ebda indirizz ta' posta elettronika għall-utent \"$1\".",
        "noemailcreate": "Huwa neċessarju li tipprovdi indirizz elettroniku validu",
        "passwordsent": "Il-password il-ġdida ntbagħtet fl-indirizz tal-posta elettronika ta' \"$1\".\nJekk jogħġbok, għamel aċċess wara li tasallek.",
        "blocked-mailpassword": "L-indirizz tal-IP tiegħek huwa bblokkjat u miżmum milli jwettaq modifiki. Għaldaqstant, mhuwiex possibli għalik li tuża l-funzjoni sabiex iġġib lura l-password, u dan sabiex ma jkunx hemm abbużi.",
-       "eauthentsent": "Intbagħat messaġġ ta' konferma b'permezz tal-posta elettronika lejn l-indirizz indikat.<br />\nQabel xi posta elettronika oħra tiġi mibgħuta fuq il-kont, trid qabel xejn tesegwixxi l-istruzzjonijiet kif inhuma indikati, sabiex tikkonferma li l-kont huwa tassew tiegħek.",
+       "eauthentsent": "Intbagħtetlek konferma b'permezz ta' messaġġ elettroniku fl-indirizz speċifikat.\nQabel ma tinbagħat xi posta elettronika oħra fuq il-kont, trid issegwi l-istruzzjonijiet indikati fil-messaġġ, sabiex tikkonferma li l-kont huwa tassew tiegħek.",
        "throttled-mailpassword": "Posta elettronika sabiex tfakrek il-password ġiet postjata, fl-aħħar {{PLURAL:$1|siegħa|$1 siegħat}}.\nSabiex jitnaqqas l-abbuż, waħda biss tista' tiġi postjata f'kull {{PLURAL:$1|siegħa|$1 siegħat}}.",
        "mailerror": "Problema bil-postar tal-messaġġ: $1",
        "acct_creation_throttle_hit": "L-utenti ta' din il-wiki li jużaw l-indirizz IP tiegħek ħolqu {{PLURAL:$1|kont|$1 kontijiet}} fl-aħħar ġurnata, li hu n-numru massimu permess f'dan il-perjodu ta' żmien.\nBħala riżultat, il-viżitaturi li jużaw dan l-IP ma jistgħux għall-mument, joħoloqu aktar kontijiet.",
        "login-abort-generic": "Il-login ma kienx suċċess - Imħassar",
        "loginlanguagelabel": "Lingwa: $1",
        "suspicious-userlogout": "Ir-rikjesta tiegħek li toħroġ barra mill-kont tiegħek ġiet miċħuda minħabba li jidher li din intbagħtet minn browser li ma jaħdimx jew minn proxy ta' caching.",
+       "pt-login": "Idħol",
+       "pt-login-button": "Idħol",
+       "pt-createaccount": "Oħloq kont",
+       "pt-userlogout": "Oħroġ",
        "php-mail-error-unknown": "Żball mhux magħruf fil-funzjoni mail() tal-PHP.",
        "user-mail-no-addy": "Pruvajt tibgħat posta elettronika mingħajr indirizz.",
+       "user-mail-no-body": "Ippruvajt tibgħat ittra elettronika b'kontenut vojt jew qasir wisq.",
        "changepassword": "Ibdel il-password",
-       "resetpass_announce": "L-aċċess ġe effetwat permezz ta' kodiċi temporanju, li ntbagħat permezz tal-posta elettronika.\nBiex tkompli l-aċċess tal-kont tiegħek huwa neċessarju li toħloq password ġdida hawnhekk:",
+       "resetpass_announce": "Biex ittemm id-dħul fil-kont tiegħek, jeħtieġ li tissettja password ġdida.",
        "resetpass_text": "<!-- Żied il-kliem hawnhekk -->",
        "resetpass_header": "Biddel il-password tal-kont",
        "oldpassword": "Password antika:",
        "newpassword": "Password ġdida:",
        "retypenew": "Erġa' ikteb il-password il-ġdida:",
        "resetpass_submit": "Issettja l-password u idħol fis-sit",
-       "changepassword-success": "Il-password ġie modifikat. Aċċess fil-proċess...",
+       "changepassword-success": "Il-password inbidlet korrettament!",
+       "changepassword-throttled": "Ippruvajt tidħol wisq drabi.\nJekk jogħġbok stenna $1 qabel ma terġa' tipprova.",
        "resetpass_forbidden": "Mhuwiex possibbli li timmodifika l-passwords",
        "resetpass-no-info": "Trid tkun effetwajt il-login qabel ma taċċessa direttament din il-paġna.",
        "resetpass-submit-loggedin": "Biddel il-password",
        "resetpass-submit-cancel": "Annulla",
        "resetpass-wrong-oldpass": "Password temporanja jew kurrenti invalida.\nJista' jkun li int diġà biddilt il-password, jew għamilt rikjesta għal password temporanja ġdida.",
+       "resetpass-recycled": "Jekk jogħġbok erġa' ssettja l-password għal xi ħaġa oħra li mhijiex il-password li għandek bħalissa.",
+       "resetpass-temp-emailed": "Dħalt b'kodiċi temporanju mibgħut elettronikament.\nBiex ittem id-dħul, jeħtieġ li tissettja password ġdida hawn:",
        "resetpass-temp-password": "Password temporanja:",
+       "resetpass-abort-generic": "Estensjoni ħassret il-bidla tal-password",
+       "resetpass-expired": "Il-password skadiet. Jekk jogħġbok issettja password ġdida biex tidħol.",
+       "resetpass-expired-soft": "Il-password skadiet u jeħtieġ li terġa' tissettjaha. Agħżel password ġdida issa, jew ikklikkja \"{{int:resetpass-tissottometti-tikkanċella}}\" biex tissettjaha aktar tard.",
+       "resetpass-validity-soft": "Il-password tiegħek mhijiex valida $1 \n\nAgħżel password ġdida issa, jew ikklikkja \"{{int:resetpass-submit-cancel}}\" biex tibdilha dan aktar.",
        "passwordreset": "Irrisettja l-password",
        "passwordreset-text-one": "Imla din il-formola sabiex tirrisettja l-password.",
+       "passwordreset-text-many": "{{PLURAL:$1|Imla wieħed mill-oqsma biex tirċievi password temporanja permezz ta' ittra elettronika.}}",
        "passwordreset-legend": "Irrisettja l-password",
        "passwordreset-disabled": "L-irrisettjar tal-password fuq din il-wiki ġie diżattivat.",
+       "passwordreset-emaildisabled": "Karatteristiċi tal-posta elettronika ġew diżattivati fuq din il-wiki.",
        "passwordreset-username": "Isem l-utent:",
        "passwordreset-domain": "Dominju:",
        "passwordreset-capture": "Ara l-kontenut tal-messaġġ?",
        "passwordreset-email": "Indirizz elettroniku:",
        "passwordreset-emailtitle": "Dettalji tal-kont fuq {{SITENAME}}",
        "passwordreset-emailtext-ip": "Xi ħadd (probabbilment int, mill-indirizz IP $1) għamel rikjesta sabiex jingħata password ġdida sabiex jaċċessa l-{{SITENAME}} ($4). L-{{PLURAL:$3|utent assoċjat|utenti assoċjati}} ma' dan l-indirizz elettroniku {{PLURAL:$3|huwa|huma}}:\n\n$2\n\n{{PLURAL:$3|Din il-password temporanja se tiskadi|Dawn il-passwords temporanji se jiskadu}} fi żmien {{PLURAL:$5|ġurnata|$5 jum}}. Inti għadek tidħol fil-kont tiegħek u tagħżel password ġdida issa. Jekk xi ħadd ieħor għamel din ir-rikjesta, jew jekk ftakart il-password oriġinali, u m'għadekx trid tbiddilha, inti tista' tinjora dan il-messaġġ u tibqa' tuża' l-password il-qadima.",
-       "passwordreset-emailtext-user": "L-utent $1 fuq {{SITENAME}} għamel rikjesta sabiex jingħata password ġdida sabiex jaċċessa l-{{SITENAME}} ($4). {{PLURAL:$3|L-utent assoċjat|L-utenti assoċjati}} ma' dan l-indirizz elettroniku huma:\n\n$2\n\n{{PLURAL:$3|Din il-password temporanja se tiskadi|Dawn il-passwords temporanji se jiskadu}} fi żmien {{PLURAL:$5|ġurnata|$5 jum}}. Inti għadek tidħol fil-kont tiegħek u tagħżel password ġdida issa. Jekk xi ħadd ieħor għamel din ir-rikjesta, jew jekk ftakart il-password oriġinali, u m'għadikx trid tbiddilha, inti tista' tinjora dan il-messaġġ u tibqa' tuża' l-password il-qadima.",
+       "passwordreset-emailtext-user": "{{PLURAL:$3|Din il-password temporanja se tiskadi|Dawn il-passwords temporanji se jiskadu}} fi żmien {{PLURAL:$5|ġurnata|$5 jum}}. Inti għadek tidħol fil-kont tiegħek u tagħżel password ġdida issa. Jekk xi ħadd ieħor għamel din ir-rikjesta, jew jekk ftakart il-password oriġinali, u m'għadikx trid tbiddilha, inti tista' tinjora dan il-messaġġ u tibqa' tuża' l-password il-qadima.",
        "passwordreset-emailelement": "Isem tal-utent: $1\nPassword temporanja: $2",
-       "passwordreset-emailsent": "Intbagħtet ittra-e bħala tfakkira.",
-       "passwordreset-emailsent-capture": "Intbagħtet ittra-e bħala tfakkira, bil-kontenut jidher hawn taħt.",
+       "passwordreset-emailsent": "Intbagħtet ittra-e għall-issettjar mill-ġdid tal-password.",
+       "passwordreset-emailsent-capture": "Intbagħtet ittra-e għall-ssettjar mill-ġdid tal-password u l-kontenut jidher hawn taħt.",
        "passwordreset-emailerror-capture": "Ġiet ġenerata ittra-e ta' tfakkira, li l-kontenut tagħha jidher hawn taħt. Madanakollu, il-posta ma ntbagħtitx lill-utent: $1",
        "changeemail": "Biddel l-indirizz elettroniku",
        "changeemail-header": "Biddel l-indirizz elettroniku tal-kont",
        "changeemail-oldemail": "Indirizz elettroniku attwali:",
        "changeemail-newemail": "Indirizz elettroniku ġdid:",
        "changeemail-none": "(xejn)",
+       "changeemail-password": "Il-password tiegħek fuq {{SITENAME}}:",
        "changeemail-submit": "Biddel l-indirizz elettroniku",
        "changeemail-cancel": "Annulla",
+       "changeemail-throttled": "Ippruvajt tidħol wisq drabi.\nJekk jogħġbok stenna $1 qabel ma terġa' tipprova.",
+       "resettokens": "Irrisettja t-tokens",
        "bold_sample": "Tipa ħoxna",
        "bold_tip": "Tipa ħoxna",
        "italic_sample": "Tipa korsiva",
        "powersearch-togglelabel": "Agħżel:",
        "powersearch-toggleall": "Kollha",
        "powersearch-togglenone": "Ebda",
+       "powersearch-remember": "Ftakar l-għażla għal tfittxijiet oħra",
        "search-external": "Tfittxija esterna",
        "searchdisabled": "It-Tfittxija fil-{{SITENAME}} mhux attiva.\nSadanittant, tista' tipprova tfittex bil-Google.\nInnota però li l-werreja tal-kontenut ta' {{SITENAME}} f'dawn is-siti, jistgħu ma jkunux aġġornati.",
        "preferences": "Preferenzi",
        "action-writeapi": "tuża' l-API fil-ktiba",
        "action-delete": "ħassar din il-paġna",
        "action-deleterevision": "ħassar din ir-reviżjoni",
-       "action-deletedhistory": "ara l-kronoloġija mħassar ta' din il-paġna",
+       "action-deletedhistory": "ara l-kronoloġija mħassra ta' din il-paġna",
        "action-browsearchive": "fittex paġni mħassra",
        "action-undelete": "irkupra din il-paġna",
        "action-suppressrevision": "tirrevedi u treġġa' din ir-reviżjoni moħbija",
        "filehist-comment": "Kumment",
        "imagelinks": "Użu tal-fajl",
        "linkstoimage": "{{PLURAL:$1|Il-Paġna segwenti għandha|Il-$1 paġni segwenti għandhom}} links għal-fajl:",
-       "linkstoimage-more": "Iktar minn {{PLURAL:$1|paġna torbot|$1paġni jorbtu}} lejn dan il-fajl.\nIl-lista segwenti turi {{PLURAL:$1|l-ewwel paġna li tipponta|l-ewwel $1 paġni li jippuntaw}} lejn dan il-fajl.\n[[Special:WhatLinksHere/$2|Lista sħiħa]] hija disponibbli.",
+       "linkstoimage-more": "Aktar minn {{PLURAL:$1|paġna torbot|$1paġni jorbtu}} lejn dan il-fajl.\nIl-lista segwenti turi {{PLURAL:$1|l-ewwel paġna li tipponta|l-ewwel $1 paġni li jippuntaw}} lejn dan il-fajl.\n[[Special:WhatLinksHere/$2|Lista sħiħa]] hija disponibbli.",
        "nolinkstoimage": "M'hemmx paġni li huma relatati ma' dan il-fajl.",
        "morelinkstoimage": "Uri [[Special:WhatLinksHere/$1|aktar links]] għal dan il-fajl.",
        "linkstoimage-redirect": "$1 (rindirizz tal-fajl) $2",
        "duplicate-defaultsort": "'''Twissija:''' iċ-ċavetta tal-issortjar oriġinali \"$2\" tissostitwixxi dik preċedenti \"$1\".",
        "version": "Verżjoni",
        "version-extensions": "Estensjonijiet installati",
+       "version-skins": "Aspetti",
        "version-specialpages": "Paġni speċjali",
        "version-parserhooks": "Hook tal-parser",
        "version-variables": "Varjabili",
        "version-antispam": "Prevenzjoni tal-ispam",
-       "version-skins": "Aspetti",
        "version-other": "Oħrajn",
        "version-mediahandlers": "Imradd tal-medja",
        "version-hooks": "Hook",
index ed2cb7a..e2999cb 100644 (file)
        "talkpagelinktext": "گپ",
        "specialpage": "شا صفحه",
        "personaltools": "مه‌شه ابزار",
-       "postcomment": "نو تیکه",
        "articlepage": "نمایش صفحه",
        "talk": "گپ",
        "views": "هارشی‌ئون",
        "editlink": "دچی‌ین",
        "viewsourcelink": "منبع بدی‌ین",
        "editsectionhint": "تیکه: $1 ره دچی‌ین",
-       "toc": "دله",
+       "toc": "فهرست",
        "showtoc": "سِراق هاده",
        "hidetoc": "فرو بور",
        "collapsible-collapse": "دوستن",
        "yourdomainname": "شمه کاروری نوم",
        "login": "دله بوردن",
        "nav-login-createaccount": "دله بوردن / عضو بیّن",
-       "loginprompt": "{{SITENAME}} ره ده‌لـه بیـه‌موئـه‌ن وه‌سه، وه‌نـه cookieئون  کـارسأر بـوئـه‌ن.",
        "userlogin": "دله بموئن / عضو بیّن",
        "userloginnocreate": "دله بموئن",
        "logout": "دربوردن",
index 0a2d3ab..f29574c 100644 (file)
        "editinginterface": "'''Sè-jī:''' Lí tng teh siu-kái 1 bīn thê-kiong nńg-thé kài-bīn bûn-jī ê ia̍h. Jīn-hô kái-piàn to ē éng-hióng tio̍h kî-thaⁿ iōng-chiá ê sú-iōng kài-bīn. Nā beh kái hoan-e̍k, chhiaⁿ khì Ûi-ki Mûi-thé chāi-tē-hoà sū-kang [//translatewiki.net/ translatewiki.net] hiâ.",
        "cascadeprotected": "Chit-ê ia̍h í-keng hông pó-hō͘ bē kái tit. In-ūi i tī ē-bīn {{PLURAL:$1|ê|ê}} liân-só pó-hō͘ lāi-té:\n$2",
        "namespaceprotected": "Lí bô khoân-lī kái '''$1'''  miâ-khong-kan ê ia̍h",
+       "exception-nologin": "Bô teng-ji̍p",
+       "exception-nologin-text": "請先[[Special:Userlogin|登入]]了才有法度看這頁抑對這頁做動作。",
+       "exception-nologin-text-manual": "請先$1,才有法度看這頁抑對這頁做動作。",
+       "virus-badscanner": "設定毋著:你的病毒掃描程式阮毋知:<em>$1</em>",
+       "virus-scanfailed": "掃病毒無成功(代碼$1)",
        "virus-unknownscanner": "M̄-chai siáⁿ pēⁿ-to̍k:",
        "logouttext": "'''Lí í-keng teng-chhut.'''\nChhiaⁿ chù-ì: ū-kóa ia̍h ū khó-lêng khoàⁿ-tio̍h bē-su lí iáu teng-ji̍p tī leh; che chi-iàu piàⁿ tiāu liû-lám-khì ê khoài-chhú-khu, tiō ē chèng-siông.",
        "welcomeuser": "Hoan-gêng, $1!",
+       "welcomecreation-msg": "你的口座以經開好矣,\n你若有需要,會使去改你佇{{SITENAME}}的設定。",
        "yourname": "Lí ê iōng-chiá miâ-chheng:",
        "userlogin-yourname": "Iōng-chiá miâ-chheng",
+       "userlogin-yourname-ph": "拍你的用者名稱",
+       "createacct-another-username-ph": "拍你的用者名稱",
        "yourpassword": "Lí ê bi̍t-bé:",
        "userlogin-yourpassword": "Bi̍t-bé",
+       "userlogin-yourpassword-ph": "拍密碼",
        "createacct-yourpassword-ph": "拍密碼",
        "yourpasswordagain": "Têng phah bi̍t-bé:",
        "createacct-yourpasswordagain": "確認密碼",
        "userlogin-loggedin": "你已經用{{GENDER:$1|$1}}登入,用下跤的表,登入別个名。",
        "userlogin-createanother": "開另外一个口座",
        "createacct-emailrequired": "電子批地址",
+       "createacct-emailoptional": "電子批地址(無一定愛寫)",
        "createacct-email-ph": "拍你的電子批地址",
        "createacct-another-email-ph": "拍你的電子批地址",
        "createaccountmail": "Iōng chi̍t-ê lîm-sî loān-sò͘ sán-seng ê bi̍t-bé , kià khì goá chí-tēng ê tiān-chú-phoe tē-chí.",
        "loginerror": "Teng-ji̍p chhò-gō·",
        "createacct-error": "開口座無成功",
        "createaccounterror": "Bô hoat-tō͘ khui kháu-chō: $1",
+       "nocookiesnew": "你的用者口座已經開好矣,毋過你猶未登入,{{SITENAME}}有用Cookies做記錄登入的用者,你無允准用Cookies,請先共阻擋提掉,才閣用你的用者名稱佮密碼登入。",
+       "nocookieslogin": "{{SITENAME}}有用cookies做記錄用者,毋過你無允準用cookies,等你改做會當了後,才閣試。",
        "loginsuccesstitle": "Teng-ji̍p sêng-kong",
        "loginsuccess": "Lí hiān-chhú-sî í-keng teng-ji̍p {{SITENAME}} chò \"$1\".",
        "nosuchuser": "Chia bô iōng-chiá hō-chò \"$1\".\nIiōng-chiá hō-chò ū hun toā-jī sè-jī.\nChhiáⁿ kiám-cha lí ê phèng-im, a̍h-sī  [[Special:UserLogin/signup|khui sin iōng-chiá ê kháu-chō.]]",
index 0d09d74..17a3128 100644 (file)
        "talkpagelinktext": "Chiàcchiera",
        "specialpage": "Paggena speciàle",
        "personaltools": "Strumiente perzonale",
-       "postcomment": "Nova sezzione",
        "articlepage": "Vere a paggena e contenuto",
        "talk": "Chiàcchiera",
        "views": "Visite",
        "uploadedimage": "ha carecato \"[[$1]]\"",
        "license": "Licenze:",
        "license-header": "Licenza",
+       "licenses-edit": "Càgna opzziune 'e licenza",
        "listfiles_name": "Nomme",
        "file-anchor-link": "Fiùra",
        "filehist": "Cronologgia d\"o file",
index 2aea667..e6ad0f0 100644 (file)
        "talkpagelinktext": "diskusjon",
        "specialpage": "Spesialside",
        "personaltools": "Personlige verktøy",
-       "postcomment": "Ny seksjon",
        "articlepage": "Vis innholdsside",
        "talk": "Diskusjon",
        "views": "Visninger",
        "externaldberror": "Det var en ekstern autentifiseringsfeil, eller du kan ikke oppdatere din eksterne konto.",
        "login": "Logg inn",
        "nav-login-createaccount": "Logg inn eller opprett en konto",
-       "loginprompt": "Du må ha slått på informasjonskapsler for å logge in på {{SITENAME}}.",
        "userlogin": "Logg inn eller opprett en konto",
        "userloginnocreate": "Logg inn",
        "logout": "Logg ut",
        "mergehistory-empty": "Ingen revisjoner kan flettes.",
        "mergehistory-success": "{{PLURAL:$3|Én revisjon|$3 revisjoner}} av [[:$1]] ble flettet til [[:$2]].",
        "mergehistory-fail": "Klarte ikke å utføre historikkfletting; sjekk siden og tidsparameterne igjen.",
+       "mergehistory-fail-toobig": "Det er ikke mulig å utføre historikk-fletting fordi flere enn tillatte $1 {{PLURAL:$1|revisjon|revisjoner}} ville blitt flyttet.",
        "mergehistory-no-source": "Kildesiden $1 finnes ikke.",
        "mergehistory-no-destination": "Målsiden $1 finnes ikke.",
        "mergehistory-invalid-source": "Kildesiden må ha en gyldig tittel.",
        "license-nopreview": "(Forhåndsvisning ikke tilgjengelig)",
        "upload_source_url": " (en gyldig, offentlig tilgjengelig adresse)",
        "upload_source_file": " (en fil på din datamaskin)",
+       "listfiles-delete": "slett",
        "listfiles-summary": "Denne spesialsiden viser alle opplastede filer.",
        "listfiles_search_for": "Søk etter filnavn:",
        "imgfile": "fil",
        "mailnologin": "Ingen avsenderadresse",
        "mailnologintext": "Du må være [[Special:UserLogin|logget inn]] og ha en gyldig e-postadresse satt i [[Special:Preferences|brukerinnstillingene]] for å sende e-post til andre brukere.",
        "emailuser": "E-post til denne brukeren",
-       "emailuser-title-target": "Send epost til denne {{GENDER:$1|brukeren}}",
+       "emailuser-title-target": "Send e-post til denne {{GENDER:$1|brukeren}}",
        "emailuser-title-notarget": "E-post til bruker",
        "emailpage": "E-post til bruker",
        "emailpagetext": "Du kan bruke skjemaet under for å sende en e-post til denne {{GENDER:$1|brukeren}}.\nE-postadressen du har satt i [[Special:Preferences|innstillingene dine]] vil vises i «Fra»-feltet i e-posten, slik at mottakeren kan svare deg direkte.",
        "duplicate-defaultsort": "Advarsel: Standardsorteringen «$2» tar over for den tidligere sorteringen «$1».",
        "version": "Versjon",
        "version-extensions": "Installerte utvidelser",
-       "version-skins": "Drakter",
+       "version-skins": "Installerte drakter",
        "version-specialpages": "Spesialsider",
        "version-parserhooks": "Parsertillegg",
        "version-variables": "Variabler",
        "version-hook-name": "Navn",
        "version-hook-subscribedby": "Brukes av",
        "version-version": "(versjon $1)",
+       "version-no-ext-name": "[uten navn]",
        "version-license": "Lisens",
        "version-ext-license": "Lisens",
        "version-ext-colheader-name": "Utvidelse",
+       "version-skin-colheader-name": "Drakt",
        "version-ext-colheader-version": "Versjon",
        "version-ext-colheader-license": "Lisens",
        "version-ext-colheader-description": "Beskrivelse",
        "expand_templates_remove_nowiki": "Ikke vis <nowiki>-merkelapper i resultatet",
        "expand_templates_generate_xml": "Vis parsetre som XML",
        "expand_templates_generate_rawhtml": "Vis ubehandlet HTML",
-       "expand_templates_preview": "Forhåndsvisning"
+       "expand_templates_preview": "Forhåndsvisning",
+       "pagelanguage": "Valg av sidespråk",
+       "pagelang-name": "Side",
+       "pagelang-language": "Språk",
+       "pagelang-use-default": "Bruk standardspråk",
+       "pagelang-select-lang": "Velg språk",
+       "right-pagelang": "Endre sidespråk",
+       "action-pagelang": "endre sidespråket",
+       "log-name-pagelang": "Endre språklogg",
+       "log-description-pagelang": "Dette er en logg som viser endringer i sidespråk",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|endret}} sidespråk for $3 fra $4 til $5."
 }
index b5d554d..0ba4a58 100644 (file)
        "talkpagelinktext": "Overleg",
        "specialpage": "Spesiale zied",
        "personaltools": "Persoonlike instellingen",
-       "postcomment": "Niej onderwarp",
        "articlepage": "Artikel",
        "talk": "Overleg",
        "views": "Weergaven",
        "externaldberror": "Der gung iets fout bie de externe authentisering, of je maggen je gebrukersprofiel niet bewarken.",
        "login": "Anmelden",
        "nav-login-createaccount": "Anmelden",
-       "loginprompt": "Je mutten scheumbestaanden (cookies) an hebben staon um an te kunnen melden bie {{SITENAME}}.",
        "userlogin": "Anmelden / inschrieven",
        "userloginnocreate": "Anmelden",
        "logout": "Aofmelden",
        "rcnotefrom": "Dit bin de wiezigingen sinds <strong>$2</strong> (maximum van <strong>$1</strong> wiezigingen).",
        "rclistfrom": "Bekiek wiezigingen vanaof $3 $2",
        "rcshowhideminor": "$1 kleine wiezigingen",
-       "rcshowhideminor-show": "Bekieken",
-       "rcshowhideminor-hide": "Verbargen",
+       "rcshowhideminor-show": "Bekiek",
+       "rcshowhideminor-hide": "Verbarg",
        "rcshowhidebots": "$1 botgebrukers",
-       "rcshowhidebots-show": "Bekieken",
-       "rcshowhidebots-hide": "Verbargen",
+       "rcshowhidebots-show": "Bekiek",
+       "rcshowhidebots-hide": "Verbarg",
        "rcshowhideliu": "$1 eregistreerden gebrukers",
-       "rcshowhideliu-show": "Bekieken",
-       "rcshowhideliu-hide": "Verbargen",
+       "rcshowhideliu-show": "Bekiek",
+       "rcshowhideliu-hide": "Verbarg",
        "rcshowhideanons": "$1 anonieme gebrukers",
-       "rcshowhideanons-show": "Bekieken",
-       "rcshowhideanons-hide": "Verbargen",
+       "rcshowhideanons-show": "Bekiek",
+       "rcshowhideanons-hide": "Verbarg",
        "rcshowhidepatr": "$1 nao-ekeken bewarkingen",
-       "rcshowhidepatr-show": "Bekieken",
-       "rcshowhidepatr-hide": "Verbargen",
+       "rcshowhidepatr-show": "Bekiek",
+       "rcshowhidepatr-hide": "Verbarg",
        "rcshowhidemine": "$1 mien bewarkingen",
-       "rcshowhidemine-show": "Bekieken",
-       "rcshowhidemine-hide": "Verbargen",
+       "rcshowhidemine-show": "Bekiek",
+       "rcshowhidemine-hide": "Verbarg",
        "rclinks": "Bekiek de leste $1 wiezigingen van de aofgeleupen $2 dagen<br />$3",
        "diff": "wiezig",
        "hist": "gesch",
        "download": "binnenhaolen",
        "unwatchedpages": "Ziejen die niet evolgd wörden",
        "listredirects": "Lieste van deurverwiezingen",
+       "listduplicatedfiles": "Lieste mit bestaanden mit duplikaoten",
        "unusedtemplates": "Ongebruukten mallen",
        "unusedtemplatestext": "Hieronder staon alle ziejen in de naamruumte \"{{ns:template}}\" die nargens gebruukt wörden.\nVergeet niet de verwiezingen nao te kieken veurda'j de mal vortdoon.",
        "unusedtemplateswlh": "aandere verwiezingen",
        "listgrouprights-removegroup-self": "Kan {{PLURAL:$2|groep|groepen}} vortdoon van eigen gebruker: $1",
        "listgrouprights-addgroup-self-all": "Kan alle groepen bie de eigen gebruker doon",
        "listgrouprights-removegroup-self-all": "Kan alle groepen vortdoon van eigen gebruker",
+       "trackingcategories": "Volgkategorieën",
        "mailnologin": "Niet an-emeld.",
        "mailnologintext": "Je mutten [[Special:UserLogin|an-emeld]] ween en n geldig e-mailadres in \"[[Special:Preferences|mien veurkeuren]]\" invoeren um disse funksie te kunnen gebruken.",
        "emailuser": "n Bericht sturen",
index 9631879..2b794c1 100644 (file)
@@ -57,7 +57,8 @@
                        "לערי ריינהארט",
                        "아라",
                        "Mar(c)",
-                       "Calak"
+                       "Calak",
+                       "Arg"
                ]
        },
        "tog-underline": "Koppelingen onderstrepen:",
        "talkpagelinktext": "Overleg",
        "specialpage": "Speciale pagina",
        "personaltools": "Persoonlijke instellingen",
-       "postcomment": "Nieuw kopje",
        "articlepage": "Pagina bekijken",
        "talk": "Overleg",
        "views": "Weergaven",
        "externaldberror": "Er is een fout opgetreden bij het aanmelden bij de database of u hebt geen toestemming uw externe account bij te werken.",
        "login": "Aanmelden",
        "nav-login-createaccount": "Aanmelden / registreren",
-       "loginprompt": "U moet cookies ingeschakeld hebben om u te kunnen aanmelden bij {{SITENAME}}.",
        "userlogin": "Aanmelden / registreren",
        "userloginnocreate": "Aanmelden",
        "logout": "Afmelden",
        "revdelete-text-text": "Verwijderde versies zijn nog zichtbaar in de geschiedenis, maar delen van de inhoud zijn niet openbaar.",
        "revdelete-text-file": "Verwijderde versies zijn nog zichtbaar in de bestandsgeschiedenis, maar delen van de inhoud zijn niet openbaar.",
        "logdelete-text": "Verwijderde logboekregels zijn nog zichtbaar in de logboeken, maar delen van de inhoud zijn niet openbaar.",
-       "revdelete-text-others": "Andere beheerders van {{SITENAME}} kunnen de verborgen inhoud nog steeds inzien en weer zichtbaar maken via deze interface, tenzij er aanvullende beperkingen zijn ingesteld.",
+       "revdelete-text-others": "Andere beheerders kunnen de verborgen inhoud nog steeds inzien en weer zichtbaar maken, tenzij er aanvullende beperkingen zijn ingesteld.",
        "revdelete-confirm": "Bevestig dat u dit wilde doen, dat u de consequenties begrijpt en dat u dit doet in overeenstemming met het geldende [[{{MediaWiki:Policy-url}}|beleid]].",
        "revdelete-suppress-text": "Gebruik versies verbergen '''alleen''' in de volgende gevallen:\n* Mogelijk smadelijke informatie;\n* Ongepaste persoonlijke gegevens, zoals:\n*: ''adres, telefoonnummers, identificatienummer, enzovoort.''",
        "revdelete-legend": "Zichtbaarheidsbeperkingen instellen",
        "right-deletedtext": "Verwijderde tekst en wijzigingen tussen verwijderde versies bekijken",
        "right-browsearchive": "Verwijderde pagina's zoeken",
        "right-undelete": "Verwijderde pagina's terugplaatsen",
-       "right-suppressrevision": "Verborgen versies bekijken en terugplaatsen",
+       "right-suppressrevision": "Specifieke versies bekijken, verbergen en weer zichtbaar maken op pagina's van elke gebruiker",
+       "right-viewsuppressed": "Bekijk versies verborgen door elke gebruiker",
        "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",
        "license": "Licentie:",
        "license-header": "Licentie",
        "nolicense": "Maak een keuze",
+       "licenses-edit": "Licentieopties bewerken",
        "license-nopreview": "(Voorvertoning niet beschikbaar)",
        "upload_source_url": " (een geldige, publiek toegankelijke URL)",
        "upload_source_file": " (een bestand op uw computer)",
+       "listfiles-delete": "verwijderen",
        "listfiles-summary": "Op deze speciale pagina zijn alle toegevoegde bestanden te bekijken.",
        "listfiles_search_for": "Zoeken naar bestand:",
        "imgfile": "bestand",
        "wantedfiles": "Niet-bestaande bestanden met koppelingen",
        "wantedfiletext-cat": "De volgende bestanden worden gebruikt maar bestaan niet. Bestanden van externe repositories kunnen zijn opgenomen in de lijst, ondanks dat ze bestaan. Dergelijke vals positieven worden <del>doorgehaald weergegeven</del>. Pagina's die niet-bestaande bestanden insluiten staan op de pagina [[:$1]].",
        "wantedfiletext-nocat": "De volgende bestanden worden gebruikt maar bestaan niet. Bestanden van externe repositories kunnen zijn opgenomen in de lijst, ondanks dat ze bestaan. Dergelijke vals positieven worden <del>doorgehaald weergegeven</del>.",
+       "wantedfiletext-nocat-noforeign": "De volgende bestanden zijn in gebruik maar bestaan niet.",
        "wantedtemplates": "Niet-bestaande sjablonen met koppelingen",
        "mostlinked": "Pagina's waar het meest naar verwezen wordt",
        "mostlinkedcategories": "Categorieën waar het meest naar verwezen wordt",
        "duplicate-defaultsort": "'''Waarschuwing:''' de standaardsortering \"$2\" krijgt voorrang voor de sortering \"$1\".",
        "version": "Versie",
        "version-extensions": "Geïnstalleerde uitbreidingen",
-       "version-skins": "Vormgevingen",
+       "version-skins": "Geïnstalleerde vormgevingen",
        "version-specialpages": "Speciale pagina's",
        "version-parserhooks": "Parserhooks",
        "version-variables": "Variabelen",
        "version-hook-name": "Hooknaam",
        "version-hook-subscribedby": "Geabonneerd door",
        "version-version": "($1)",
+       "version-no-ext-name": "[geen naam]",
        "version-license": "Licentie voor MediaWiki",
        "version-ext-license": "Licentie",
        "version-ext-colheader-name": "Uitbreiding",
+       "version-skin-colheader-name": "Vormgeving",
        "version-ext-colheader-version": "Versie",
        "version-ext-colheader-license": "Licentie",
        "version-ext-colheader-description": "Beschrijving",
        "expand_templates_remove_nowiki": "Tags <nowiki> in resultaat onderdrukken",
        "expand_templates_generate_xml": "XML-parserboom bekijken",
        "expand_templates_generate_rawhtml": "Ruwe HTML weergeven",
-       "expand_templates_preview": "Voorvertoning"
+       "expand_templates_preview": "Voorvertoning",
+       "pagelang-name": "Pagina",
+       "pagelang-language": "Taal",
+       "pagelang-select-lang": "Taal selecteren"
 }
index 40d1bee..b2e931e 100644 (file)
        "talkpagelinktext": "Diskusjon",
        "specialpage": "Spesialside",
        "personaltools": "Personlege verktøy",
-       "postcomment": "Ny bolk",
        "articlepage": "Vis innhaldsside",
        "talk": "Diskusjon",
        "views": "Visningar",
        "externaldberror": "Det var anten ein ekstern databasefeil i tilgjengekontrollen, eller du har ikkje løyve til å oppdatere den eksterne kontoen din.",
        "login": "Logg inn",
        "nav-login-createaccount": "Lag brukarkonto / logg inn",
-       "loginprompt": "Nettlesaren din må godta informasjonskapslar for at du skal kunna logge inn.",
        "userlogin": "Lag brukarkonto / logg inn",
        "userloginnocreate": "Logg inn",
        "logout": "Logg ut",
        "powersearch-togglelabel": "Hak av:",
        "powersearch-toggleall": "Alle",
        "powersearch-togglenone": "Ingen",
+       "powersearch-remember": "Hugs utvalet for framtidige søk",
        "search-external": "Eksternt søk",
        "searchdisabled": "Søkjefunksjonen på {{SITENAME}} er slått av akkurat no.\nI mellomtida kan du søkje gjennom Google.\nVer merksam på at registra deira kan vera utdaterte.",
        "search-error": "Det oppstod ein feil under søket: $1",
index 1d2cd01..800f321 100644 (file)
        "talkpagelinktext": "Discussion",
        "specialpage": "Pagina especiala",
        "personaltools": "Aisinas personalas",
-       "postcomment": "Seccion novèla",
        "articlepage": "Vejatz l'article",
        "talk": "Discussion",
        "views": "Afichatges",
        "externaldberror": "Siá una error s’es producha amb la banca de donadas d’autentificacion extèrna, siá sètz pas autorizat a metre a jorn vòstre compte extèrne.",
        "login": "Identificacion",
        "nav-login-createaccount": "Crear un compte o se connectar",
-       "loginprompt": "Vos cal activar los cookies per vos connectar a {{SITENAME}}.",
        "userlogin": "Crear un compte o se connectar",
        "userloginnocreate": "Connexion",
        "logout": "Se desconnectar",
        "currentrev": "Version actuala",
        "currentrev-asof": "Version actuala en data del $1",
        "revisionasof": "Version del $1",
-       "revision-info": "Version del $1 per $2",
+       "revision-info": "Version del $1 per {{GENDER:$6|$2}}$7",
        "previousrevision": "← Version precedenta",
        "nextrevision": "Version seguenta →",
        "currentrevisionlink": "vejatz la version correnta",
        "largefileserver": "La talha d'aqueste fichièr es superiora al maximum autorizat.",
        "emptyfile": "Lo fichièr que volètz importar sembla void. Aquò pòt èsser degut a una error dins lo nom del fichièr. Verificatz que desiratz vertadièrament copiar aqueste fichièr.",
        "windows-nonascii-filename": "Aqueste wiki supòrta pas los noms de fichièrs amb de caractèrs especials.",
-       "fileexists": "Un fichièr amb aqueste nom existís ja.\nMercé de verificar <strong>[[:$1]]</strong>.\nSètz segur de voler modificar aqueste fichièr ? [[$1|thumb]]",
+       "fileexists": "Un fichièr amb aqueste nom existís ja.\nMercé de verificar <strong>[[:$1]]</strong>\nse sètz pas segur{{GENDER:||a|}} que o volètz remplaçar. [[$1|thumb]]",
        "filepageexists": "La pagina de descripcion per aqueste fichièr ja es estada creada aicí <strong>[[:$1]]</strong>, mas cap de fichièr existís pas actualament jos aqueste nom.\nLo resumit qu'anatz especificar apareisserà pas sus la pagina de descripcion.\nPer o far, vos caldrà modificar la pagina manualament. [[$1|vinheta]]",
-       "fileexists-extension": "Un fichièr amb un nom pròchi existís ja : [[$2|thumb]]\n* Nom del fichièr d'importar : <strong>[[:$1]]</strong>\n* Nom del fichièr existent : <strong>[[:$2]]</strong>\nCausissètz-ne un autre.",
+       "fileexists-extension": "Un fichièr amb un nom pròchi existís ja : [[$2|thumb]]\n* Nom del fichièr d'importar : <strong>[[:$1]]</strong>\n* Nom del fichièr existent : <strong>[[:$2]]</strong>\nBenlèu que podètz utilizar un nom mai explicit ?",
        "fileexists-thumbnail-yes": "Lo fichièr sembla èsser un imatge en talha reducha ''(thumbnail)''. [[$1|thumb]]\nVerificatz lo fichièr <strong>[[:$1]]</strong>.\nSe lo fichièr verificat es lo meteis imatge (dins una resolucion melhora), es pas de besonh d’importar una version reducha.",
        "file-thumbnail-no": "Lo nom del fichièr comença per <strong>$1</strong>.\nEs possible que s’agisca d’una version reducha ''(miniatura)''.\nSe dispausatz del fichièr en resolucion nauta, importatz-lo, si que non cambiatz lo nom del fichièr.",
        "fileexists-forbidden": "Un fichièr amb aqueste nom existís ja e pòt pas èsser espotit.\nSe volètz totjorn importar aquel fichièr, mercé de tornar en arrièr e d'utilizar un nom novèl. [[File:$1|thumb|center|$1]]",
        "filedelete-maintenance": "La supression e lo restabliment de fichièrs es temporàriament desactivada pendent la mantenença.",
        "filedelete-maintenance-title": "Impossible de suprimir lo fichièr",
        "mimesearch": "Recèrca per tipe MIME",
-       "mimesearch-summary": "Aquesta pagina especiala permet de cercar de fichièrs en foncion de lor tipe MIME. Entrada : tipe/sostipe, per exemple <code>image/jpeg</code>.",
+       "mimesearch-summary": "Aquesta pagina vos permet de filtrar los fichièrs en foncion de lor tipe MIME. Entrada : tipe_de_contengut/sostipe o tipe_de_contengut/*, per exemple <code>image/jpeg</code>.",
        "mimetype": "Tipe MIME :",
        "download": "telecargament",
        "unwatchedpages": "Paginas pas seguidas",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|membre|membres}}",
        "nrevisions": "$1 {{PLURAL:$1|revision|revisions}}",
        "nviews": "$1 {{PLURAL:$1|consultacion|consultacions}}",
-       "nimagelinks": "Utilisat sus $1 {{PLURAL:$1|pagina|paginas}}",
-       "ntransclusions": "Utilisat sus $1 {{PLURAL:$1|pagina|paginas}}",
+       "nimagelinks": "Utilizat sus $1 {{PLURAL:$1|pagina|paginas}}",
+       "ntransclusions": "Utilizat sus $1 {{PLURAL:$1|pagina|paginas}}",
        "specialpage-empty": "Aquesta pagina es voida.",
        "lonelypages": "Paginas orfanèlas",
        "lonelypagestext": "Las paginas seguentas son pas ligadas o enclusas a partir d’autras paginas de {{SITENAME}}.",
        "wantedtemplates": "Modèls demandats",
        "mostlinked": "Paginas mai ligadas",
        "mostlinkedcategories": "Categorias mai utilizadas",
-       "mostlinkedtemplates": "Modèls mai utilizats",
+       "mostlinkedtemplates": "Paginas las mai inclusas",
        "mostcategories": "Articles utilizant mai de categorias",
        "mostimages": "Fichièrs mai utilizats",
        "mostinterwikis": "Paginas amb lo mai d'interwikis",
        "nowatchlist": "Vòstra lista de seguiment conten pas cap d'article.",
        "watchlistanontext": "Per poder afichar o editar los elements de vòstra lista de seguiment, vos cal vos $1.",
        "watchnologin": "Vos sètz pas identificat(ada)",
-       "addwatch": "Ajustar a la lista de seguiment",
+       "addwatch": "Apondre a la lista de seguiment",
        "addedwatchtext": "La pagina « [[:$1]] » es estada aponduda a vòstra [[Special:Watchlist|lista de seguiment]]. Las modificacions venentas d'aquesta pagina e de la pagina de discussion associada i seràn repertoriadas.",
        "removewatch": "Suprimir de la lista de seguiment",
        "removedwatchtext": "La pagina « [[:$1]] » es estada levada de vòstra [[Special:Watchlist|lista de seguiment]].",
        "revertpage": "Anullacion de las modificacions de [[Special:Contributions/$2|$2]] ([[User talk:$2|Discussion]]) cap a la darrièra version de [[User:$1|$1]]",
        "revertpage-nouser": "Revocacion de las modificacions per un utilizaire amagat a la darrièra version per {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Anullacion de las modificacions de $1 ; retorn a la version de $2.",
-       "sessionfailure-title": "La session capitèt mal",
+       "sessionfailure-title": "La sesilha a fracassat",
        "sessionfailure": "Vòstra sesilha de connexion sembla aver de problèmas ;\naquesta accion es estada anullada en prevencion d’un piratatge de sesilha.\nClicatz sus « Precedent » e tornatz cargar la pagina d’ont venètz, puèi ensajatz tornarmai.",
        "protectlogpage": "Istoric de las proteccions",
        "protectlogtext": "Aquí una lista de las modificacions de las proteccions de paginas.\nConsultatz la [[Special:ProtectedPages|lista de las paginas protegidas]] per la lista de las proteccions actualament operacionalas.",
        "duplicate-defaultsort": "Atencion : La clau de triada per defaut « $2 » espotís la mai recenta « $1 ».",
        "version": "Version",
        "version-extensions": "Extensions installadas",
+       "version-skins": "Abilhatges installats",
        "version-specialpages": "Paginas especialas",
        "version-parserhooks": "Extensions del parser",
        "version-variables": "Variablas",
        "version-antispam": "Prevencion del spam",
-       "version-skins": "Abilhatges",
        "version-other": "Divèrs",
        "version-mediahandlers": "Supòrts mèdia",
        "version-hooks": "Croquets",
index 82754c4..ec41ac6 100644 (file)
@@ -28,7 +28,7 @@
        "tog-hidepatrolled": "ਤਾਜ਼ਾ ਤਬਦੀਲੀਆਂ ਵਿੱਚੋਂ ਜਾਂਚੀਆਂ ਸੋਧਾਂ ਲੁਕਾਓ",
        "tog-newpageshidepatrolled": "ਨਵੀਂ ਸਫ਼ਾ ਸੂਚੀ ਵਿੱਚੋਂ ਜਾਂਚੇ ਸਫ਼ੇ ਲੁਕਾਓ",
        "tog-extendwatchlist": "ਸਿਰਫ਼ ਤਾਜ਼ਾ ਹੀ ਨਹੀਂ, ਸਗੋਂ ਸਾਰੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਵਖਾਉਣ ਲਈ ਨਿਗਰਾਨੀ-ਲਿਸਟ ਨੂੰ ਵਧਾਓ",
-       "tog-usenewrc": "ਤਾà¨\9c਼ਾ à¨¤à¨¬à¨¦à©\80ਲà©\80à¨\86à¨\82 à¨\85ਤà©\87 à¨¨à¨¿à¨\97ਰਾਨà©\80-ਲਿਸà¨\9f à¨µà¨¿à©±à¨\9a à¨¸à¨«à¨¼à©\87 à¨®à©\81ਤਾਬà¨\95 à¨¤à¨¬à¨¦à©\80ਲà©\80à¨\86à¨\82 à¨¦à©\87 à¨\97ਰà©\81ੱà¨\95 ਬਣਾਓ (ਜਾਵਾਸਕਰਿਪਟ ਲੋੜੀਂਦੀ ਹੈ)",
+       "tog-usenewrc": "ਹਾਲà©\80à¨\86 à¨¤à¨¬à¨¦à©\80ਲà©\80à¨\86à¨\82 à¨\85ਤà©\87 à¨¨à¨¿à¨\97ਰਾਨà©\80-ਲਿਸà¨\9f à¨µà¨¿à©±à¨\9a à¨¸à¨«à¨¼à©\87 à¨®à©\81ਤਾਬà¨\95 à¨¤à¨¬à¨¦à©\80ਲà©\80à¨\86à¨\82 à¨¦à©\87 à¨\97ਰà©\81ੱਪ ਬਣਾਓ (ਜਾਵਾਸਕਰਿਪਟ ਲੋੜੀਂਦੀ ਹੈ)",
        "tog-numberheadings": "ਆਟੋ-ਨੰਬਰ ਸਿਰਨਾਵੇਂ",
        "tog-showtoolbar": "ਸੋਧ ਸੰਦਬਕਸਾ ਵੇਖੋ",
        "tog-editondblclick": "ਦੋ ਵਾਰ ਕਲਿੱਕ ਕਰਨ 'ਤੇ ਸਫ਼ੇ ਸੋਧੋ",
        "talkpagelinktext": "ਗੱਲ-ਬਾਤ",
        "specialpage": "ਖ਼ਾਸ ਸਫ਼ਾ",
        "personaltools": "ਨਿੱਜੀ ਸੰਦ",
-       "postcomment": "ਨਵਾਂ ਭਾਗ",
        "articlepage": "ਸਮੱਗਰੀ ਸਫ਼ਾ ਵੇਖੋ",
        "talk": "ਚਰਚਾ",
        "views": "ਵਿਊ",
        "mypreferencesprotected": "ਤੁਹਾਨੂੰ ਆਪਣੀਆਂ ਪਸੰਦਾਂ ਵਿੱਚ ਸੋਧ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।",
        "ns-specialprotected": "ਖ਼ਾਸ ਸਫ਼ਿਆਂ ’ਚ ਫੇਰ-ਬਦਲ ਨਹੀਂ ਹੋ ਸਕਦੇ।",
        "titleprotected": "ਇਹ ਸਿਰਲੇਖ [[User:$1|$1]] ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ ਹੈ ਅਤੇ ਵਰਤਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦਿੱਤਾ ਹੋਇਆ ਕਾਰਨ ਹੈ, \"''$2''\"।",
-       "filereadonlyerror": "\"$1\" à¨«à¨¼à¨¾à¨\88ਲ à¨µà¨¿à©±à¨\9a à¨¤à¨¬à¨¦à©\80ਲà©\80 à¨¨à¨¹à©\80à¨\82 à¨¹à©\8b à¨°à¨¹à©\80 à¨\95ਿà¨\89à¨\82à¨\95ਿ à¨«à¨¼à¨¾à¨\88ਲ à¨­à©°à¨¡à¨¾à¨° \"$2\" à¨¸à¨¿à¨°à¨«à¨¼ à¨ªà©\9cà©\8dਹਨਯà©\8bà¨\97 à¨°à©\82ਪ à¨µà¨¿à¨\9a à¨¹à©\88।\n\nà¨\89ਹ à¨ªà©\8dਰਸ਼ਾਸà¨\95, à¨\9cਿਹਨà©\87 à¨\87ਹ à¨°à©\8bà¨\95 à¨²à¨¾à¨\88 à¨¹à©\88, à¨¦à¨¾ à¨\95ਹਿਣਾ à¨¹à©\88:",
+       "filereadonlyerror": "\"$1\" à¨«à¨¼à¨¾à¨\88ਲ à¨µà¨¿à©±à¨\9a à¨¤à¨¬à¨¦à©\80ਲà©\80 à¨¨à¨¹à©\80à¨\82 à¨¹à©\8b à¨¸à¨\95ਦà©\80 à¨\95ਿà¨\89à¨\82à¨\95ਿ à¨«à¨¼à¨¾à¨\88ਲ à¨­à©°à¨¡à¨¾à¨° \"$2\" à¨¸à¨¿à¨°à¨«à¨¼ à¨µà©\87à¨\96ਣਯà©\8bà¨\97 à¨°à©\82ਪ à¨µà¨¿à¨\9a à¨¹à©\88।\n\nà¨\89ਹ à¨ªà©\8dਰਬੰਧà¨\95, à¨\9cਿਹਨà©\87 à¨\87ਹ à¨°à©\8bà¨\95 à¨²à¨¾à¨\88 à¨¹à©\88, à¨¦à¨¾ à¨\95ਹਿਣਾ à¨¹à©\88: ''$3''",
        "invalidtitle-knownnamespace": "ਥਾਂ-ਨਾਮ \"$2\" ਅਤੇ ਲਿਖਤ \"$3\" ਵਾਲ਼ਾ ਗ਼ਲਤ ਸਿਰਲੇਖ",
        "invalidtitle-unknownnamespace": "ਅਣਜਾਣ ਨਾਂ-ਸਥਾਨ ਗਿਣਤੀ $1 ਅਤੇ ਲਿਖਤ $2 ਵਾਲ਼ਾ ਗ਼ਲਤ ਸਿਰਲੇਖ",
        "exception-nologin": "ਲਾਗਇਨ ਨਹੀਂ ਕੀਤਾ",
        "virus-badscanner": "ਮੰਦਾ ਪ੍ਰਬੰਧ: ਅਣਜਾਣ ਵਾਇਰਸ ਸਕੈਨਰ: ''$1''",
        "virus-scanfailed": "ਸਕੈਨ ਫੇਲ੍ਹ ਹੈ (ਕੋਡ $1)",
        "virus-unknownscanner": "ਅਣਪਛਾਤਾ ਐਂਟੀਵਾਇਰਸ:",
-       "logouttext": "'''ਹੁਣ ਤੁਸੀਂ ਵਿਦਾਈ ਲੈ ਚੁੱਕੇ ਹੋ।'''\n\nਤੁਸੀਂ {{SITENAME}} ਦੀ ਵਰਤੋਂ ਗੁਮਨਾਮ ਰਹਿ ਕੇ ਕਰ ਸਕਦੇ ਹੋ ਜਾਂ ਦੁਬਾਰਾ ਇਹੋ ਜਾਂ ਵੱਖਰੇ ਵਰਤੋਂਕਾਰ ਵਜੋਂ ਦਾਖ਼ਲਾ ਲੈ ਸਕਦੇ ਹੋ।\nਧਿਆਨ ਦਿਉ ਕਿ ਜਿੰਨੀ ਦੇਰ ਤੱਕ ਤੁਸੀਂ ਆਪਣੇ ਬਰਾਊਜ਼ਰ ਦਾ ਕੈਸ਼ ਸਾਫ਼ ਨਹੀਂ ਕਰਦੇ, ਕੁਝ ਸਫ਼ੇ ਇੱਦਾਂ ਵਿਖਣਗੇ ਜਿਵੇਂ ਤੁਸੀਂ ਅਜੇ ਵੀ ਦਾਖ਼ਲ ਹੀ ਹੋ।",
+       "logouttext": "<strong>ਹੁਣ ਤੁਸੀਂ ਵਿਦਾਈ ਲੈ ਚੁੱਕੇ ਹੋ।</strong> ਧਿਆਨ ਦਿਉ ਕਿ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਆਪਣੇ ਬਰਾਊਜ਼ਰ ਦਾ ਕੈਸ਼ ਸਾਫ਼ ਨਹੀਂ ਕਰਦੇ, ਕੁਝ ਸਫ਼ੇ ਏਦਾਂ ਵਿਖਾਈ ਦੇ ਸਕਦੇ ਹਨ ਕਿ ਜਿਵੇਂ ਤੁਸੀਂ ਅਜੇ ਵੀ ਲਾਗਇਨ ਹੀ ਹੋ।",
        "welcomeuser": "$1 ਜੀ ਆਇਆਂ ਨੂੰ!",
        "welcomecreation-msg": "ਤੁਹਾਡਾ ਖਾਤਾ ਬਣ ਚੁੱਕਾ ਹੈ। ਆਪਣੀਆਂ [[Special:Preferences|{{SITENAME}} ਪਸੰਦ]] ਬਦਲਣੀ ਨਾ ਭੁੱਲੋ।",
        "yourname": "ਵਰਤੋਂਕਾਰ-ਨਾਂ:",
        "externaldberror": "ਜਾਂ ਤਾਂ ਪ੍ਰਮਾਣਕੀ ਡਾਟਾਬੇਸ ਦੋਸ਼ ਆਇਆ ਹੈ ਜਾਂ ਤੁਹਾਨੂੰ ਆਪਣੇ ਬਾਹਰੀ ਖਾਤੇ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।",
        "login": "ਲਾਗਇਨ",
        "nav-login-createaccount": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
-       "loginprompt": "ਤੁਹਾਨੂੰ {{SITENAME}} ’ਤੇ ਲਾਗਇਨ ਕਰਨ ਲਈ ਕੂਕੀਸ ਯੋਗ ਕਰਨੇ ਜ਼ਰੂਰੀ ਹਨ।",
        "userlogin": "ਲਾਗਇਨ/ਖਾਤਾ ਬਣਾਓ",
        "userloginnocreate": "ਲਾਗਇਨ",
        "logout": "ਲਾਗ ਆਉਟ",
        "createacct-benefit-body3": "ਹਾਲੀਆ {{PLURAL:$1|ਯੋਗਦਾਨੀ}}",
        "badretype": "ਤੁਹਾਡੇ ਵਲੋਂ ਦਿੱਤੇ ਪਾਸਵਰਡ ਮਿਲਦੇ ਨਹੀਂ ਹਨ।",
        "userexists": "ਯੂਜ਼ਰ-ਨਾਂ ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੈ। ਵੱਖਰਾ ਨਾਂ ਚੁਣੋ ਜੀ।",
-       "loginerror": "ਲਾਗਇਨ ਗਲਤੀ",
+       "loginerror": "ਲਾà¨\97à¨\87ਨ à¨\97਼ਲਤà©\80",
        "createacct-error": "ਖਾਤਾ ਬਣਾਉਣ ਵਿਚ ਗਲਤੀ",
        "createaccounterror": "ਖਾਤਾ ਬਣਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ: $1",
        "nocookiesnew": "ਯੂਜ਼ਰ ਅਕਾਊਂਟ ਬਣਾਇਆ ਗਿਆ ਹੈ, ਪਰ ਤੁਸੀਂ ਲਾਗਇਨ ਨਹੀਂ ਕੀਤਾ ਹੈ।{{SITENAME}} uses cookies to log in users. You have cookies disabled. Please enable them, then log in with your new username and password.",
        "user-mail-no-addy": "ਬਿਨਾਂ ਈ-ਮੇਲ ਪਤਾ ਦਿੱਤੇ ਈ-ਮੇਲ ਭੇਜਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ।",
        "user-mail-no-body": "ਖ਼ਾਲੀ ਜਾਂ ਬਹੁਤੀ ਛੋਟੀ ਸਮੱਗਰੀ ਨਾਲ਼ ਈਮੇਲ ਭੇਜਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਗਈ",
        "changepassword": "ਪਾਸਵਰਡ ਬਦਲੋ",
-       "resetpass_announce": "ਤà©\81ਸà©\80à¨\82 à¨\87ੱà¨\95 à¨\86ਰà¨\9c਼à©\80 à¨\88-ਮà©\87ਲ à¨\95à©\80ਤà©\87 à¨\95à©\8bਡ à¨¨à¨¾à¨² à¨²à¨¾à¨\97à¨\87ਨ à¨\95à©\80ਤਾ à¨¹à©\88। à¨²à¨¾à¨\97à¨\87ਨ à¨ªà©\82ਰਾ à¨\95ਰਨ à¨²à¨\88, à¨¤à©\81ਹਾਨà©\82à©° à¨\87ੱਥà©\87 à¨¨à¨µà¨¾à¨\82 à¨ªà¨¾à¨¸à¨µà¨°à¨¡ à¨¦à©\87ਣਾ à¨ªà¨µà©\87à¨\97ਾ:",
+       "resetpass_announce": "ਲਾà¨\97à¨\87ਨ à¨ªà©\82ਰਾ à¨\95ਰਨ à¨²à¨\88 à¨¤à©\81ਹਾਨà©\82à©° à¨¨à¨µà¨¾à¨\82 à¨ªà¨¾à¨¸à¨µà¨°à¨¡ à¨¬à¨£à¨¾à¨\89ਣਾ à¨ªà¨µà©\87à¨\97ਾ।",
        "resetpass_header": "ਅਕਾਊਂਟ ਪਾਸਵਰਡ ਬਦਲੋ",
        "oldpassword": "ਪੁਰਾਣਾ ਪਾਸਵਰਡ:",
        "newpassword": "ਨਵਾਂ ਪਾਸਵਰਡ:",
        "resetpass-abort-generic": "ਇੱਕ ਐਕਸਟੈਂਸ਼ਨ ਵੱਲੋਂ ਪਾਸਵਰਡ ਦੀ ਤਬਦੀਲੀ ਰੱਦ ਕੀਤੀ ਗਈ",
        "passwordreset": "ਪਾਸਵਰਡ ਮੁੜ-ਸੈੱਟ ਕਰੋ",
        "passwordreset-text-one": "ਪਾਸਵਰਡ ਦੁਬਾਰਾ ਬਣਾਉਣ ਲਈ ਇਹ ਫ਼ਾਰਮ ਭਰੋ।",
-       "passwordreset-text-many": "{{PLURAL:$1|à¨\86ਪਣਾ à¨ªà¨¾à¨¸à¨µà¨°à¨¡ à¨®à©\81à©\9c à¨¬à¨£à¨¾à¨\89ਣ ਲਈ ਕੋਈ ਇੱਕ ਥਾਂ ਭਰੋ।}}",
+       "passwordreset-text-many": "{{PLURAL:$1|à¨\88-ਮà©\87ਲ à¨\9c਼ਰà©\80à¨\8f à¨\86ਪਣਾ à¨\86ਰà¨\9c਼à©\80 à¨ªà¨¾à¨¸à¨µà¨°à¨¡ à¨¹à¨¾à¨¸à¨² à¨\95ਰਨ ਲਈ ਕੋਈ ਇੱਕ ਥਾਂ ਭਰੋ।}}",
        "passwordreset-legend": "ਪਾਸਵਰਡ ਮੁੜ-ਸੈੱਟ ਕਰੋ",
        "passwordreset-disabled": "ਇਸ ਵਿਕੀ ਤੇ ਪਾਸਵਰਡ ਰੀਸੈੱਟ ਬੰਦ ਕੀਤੇ ਗਏ ਹਨ।",
        "passwordreset-emaildisabled": "ਇਹ ਵਿਕਿ ਉੱਤੇ ਈਮੇਲ ਫੀਚਰ ਬੰਦ ਕੀਤਾ ਹੋਇਆ ਹੈ।",
        "currentrev": "ਮੌਜੂਦਾ ਰੀਵਿਜ਼ਨ",
        "currentrev-asof": "$1 ਮੁਤਾਬਕ ਸਭ ਤੋਂ ਨਵਾਂ ਰੀਵਿਜਨ",
        "revisionasof": "$1 ਦਾ ਰੀਵਿਜਨ",
-       "revision-info": "$2 ਦਾ ਬਣਾਇਆ $1 ਦਾ ਰੀਵਿਜਨ",
+       "revision-info": "{{GENDER:$6|$2}}$7 ਦਾ ਬਣਾਇਆ $1 ਦਾ ਰੀਵਿਜ੍ਹਨ",
        "previousrevision": "←ਪੁਰਾਣਾ ਰੀਵਿਜਨ",
        "nextrevision": "ਨਵਾਂ ਰੀਵਿਜਨ →",
        "currentrevisionlink": "ਸਭ ਤੋ ਨਵਾਂ ਰੀਵਿਜਨ",
        "searchprofile-images": "ਮਲਟੀਮੀਡੀਆ",
        "searchprofile-everything": "ਸਭ ਕੁਝ",
        "searchprofile-advanced": "ਉੱਨਤ",
-       "searchprofile-articles-tooltip": "$1 ਵਿੱਚ ਖੋਜ",
+       "searchprofile-articles-tooltip": "$1 ਵਿੱਚ ਖੋਜ",
        "searchprofile-images-tooltip": "ਫ਼ਾਈਲਾਂ ਖੋਜੋ",
        "searchprofile-everything-tooltip": "ਸਾਰੀ ਸਮੱਗਰੀ ਵਿੱਚੋਂ ਖੋਜੋ (ਗੱਲ-ਬਾਤ ਸਫ਼ਿਆਂ ਸਮੇਤ)",
        "searchprofile-advanced-tooltip": "ਆਪਣੀਆਂ ਬਣਾਈਆਂ ਨਾਂ-ਥਾਂਵਾਂ ਵਿੱਚ ਖੋਜੋ",
        "watchlisttools-raw": "ਕੱਚੀ ਨਿਗਰਾਨ-ਸੂਚੀ ਸੋਧੋ",
        "duplicate-defaultsort": "ਪੁਰਾਣੀ ਮੂਲ ਕਰਮਾਂਕਨ ਕੁੰਜੀ $1 ਦੇ ਬਜਾਏ ਹੁਣ ਮੂਲ ਕਰਮਾਂਕਨ ਕੁੰਜੀ $2 ਹੋਵੇਗੀ।",
        "version": "ਵਰਜਨ",
-       "version-specialpages": "ਖ਼ਾਸ ਸਫ਼ੇ",
        "version-skins": "ਸਕਿਨਾਂ",
+       "version-specialpages": "ਖ਼ਾਸ ਸਫ਼ੇ",
        "version-other": "ਹੋਰ",
        "version-hooks": "ਹੁੱਕਾਂ",
        "version-hook-name": "ਹੁੱਕ ਦਾ ਨਾਂ",
index c6b9987..3803f4a 100644 (file)
        "go": "Przejdź",
        "searcharticle": "Przejdź",
        "history": "Historia strony",
-       "history_short": "Historia",
+       "history_short": "historia",
        "updatedmarker": "zmienione od ostatniej wizyty",
        "printableversion": "Wersja do druku",
        "permalink": "Link do tej wersji",
        "talkpagelinktext": "dyskusja",
        "specialpage": "Strona specjalna",
        "personaltools": "Osobiste",
-       "postcomment": "Nowa sekcja",
        "articlepage": "Artykuł",
        "talk": "Dyskusja",
        "views": "Widok",
        "externaldberror": "Wystąpił błąd zewnętrznej bazy autentyfikacyjnej lub nie posiadasz uprawnień koniecznych do aktualizacji zewnętrznego konta.",
        "login": "Zaloguj się",
        "nav-login-createaccount": "Logowanie i rejestracja",
-       "loginprompt": "Musisz mieć włączoną w przeglądarce obsługę ciasteczek, by móc się zalogować do {{GRAMMAR:D.lp|{{SITENAME}}}}.",
        "userlogin": "Logowanie i rejestracja",
        "userloginnocreate": "Zaloguj się",
        "logout": "Wyloguj",
        "revdelete-text-text": "Usunięte wersje będą nadal widoczne w historii strony, ale niektóre fragmenty ich treści nie będą dostępne dla wszystkich.",
        "revdelete-text-file": "Usunięte wersje pliku będą nadal widoczne w historii pliku, ale niektóre fragmenty ich treści nie będą dostępne dla wszystkich.",
        "logdelete-text": "Usunięte wpisy rejestru nadal będą widoczne w rejestrze, ale niektóre fragmenty ich treści nie będą dostępne dla wszystkich.",
-       "revdelete-text-others": "Pozostali administratorzy {{grammar:genitive|{{SITENAME}}}} nadal będą posiadali dostęp do ukrytej treści i będą w stanie odtworzyć ją ponownie za pomocą tego samego interfejsu, jeśli nie zostaną ustawione dodatkowe ograniczenia.",
+       "revdelete-text-others": "Pozostali administratorzy nadal będą posiadali dostęp do ukrytej treści i będą w stanie odtworzyć ją ponownie za pomocą tego samego interfejsu, jeśli nie zostaną ustawione dodatkowe ograniczenia.",
        "revdelete-confirm": "Potwierdź, że chcesz to zrobić zgodnie z [[{{MediaWiki:Policy-url}}|zasadami]] i że rozumiesz konsekwencje.",
        "revdelete-suppress-text": "Ukrywanie powinno być używane '''wyłącznie''' w sytuacji:\n* Informacji, która może być zniesławieniem\n* Ujawnienie danych osobowych\n*: ''adres domowy, numer telefonu, numer PESEL itp''",
        "revdelete-legend": "Ustaw ograniczenia widoczności",
        "mergehistory-empty": "Brak historii zmian do scalenia.",
        "mergehistory-success": "$3 {{PLURAL:$3|zmiana|zmiany|zmian}} w [[:$1]] zostało scalonych z [[:$2]].",
        "mergehistory-fail": "Scalenie historii zmian jest niewykonalne. Zmień ustawienia parametrów.",
+       "mergehistory-fail-toobig": "Nie można połączyć historii, gdyż wymagałoby to przeniesienia więcej niż maksymalnej dopuszczalnej liczby $1 {{PLURAL:$1|wersji}}.",
        "mergehistory-no-source": "Strona źródłowa $1 nie istnieje.",
        "mergehistory-no-destination": "Strona docelowa $1 nie istnieje.",
        "mergehistory-invalid-source": "Strona źródłowa musi mieć poprawną nazwę.",
        "right-passwordreset": "Sprawdzanie treści e‐maila o resetowaniu hasła",
        "newuserlogpage": "Nowi użytkownicy",
        "newuserlogpagetext": "To jest rejestr ostatnio utworzonych kont użytkowników",
-       "rightslog": "Rejestr uprawnień",
+       "rightslog": "Uprawnienia",
        "rightslogtext": "Rejestr zmian uprawnień użytkowników.",
        "action-read": "przeglądania tej strony",
        "action-edit": "edytowania tej strony",
        "license": "Licencja",
        "license-header": "Licencja",
        "nolicense": "Nie wybrano",
+       "licenses-edit": "Edytuj opcje licencji",
        "license-nopreview": "(Podgląd niedostępny)",
        "upload_source_url": " (poprawny, publicznie dostępny adres URL)",
        "upload_source_file": " (plik na twoim komputerze)",
+       "listfiles-delete": "usuń",
        "listfiles-summary": "Na tej stronie specjalnej prezentowane są wszystkie przesłane pliki.",
        "listfiles_search_for": "Szukaj pliku o nazwie",
        "imgfile": "plik",
        "wantedpages-badtitle": "Nieprawidłowy tytuł wśród wyników – $1",
        "wantedfiles": "Potrzebne pliki",
        "wantedfiletext-cat": "Następujące pliki są używane, ale nie istnieją. Pliki z obcych repozytoriów mogą być wymienione pomimo istnienia. Takie fałszywe wyniki zostaną <del>przekreślone</del>. Ponadto strony, które osadzają pliki, które nie istnieją, są wymienione w [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Następujące pliki są używane, ale nie istnieją. Dodatkowo strony, które zawierają nieistniejące pliki, są wymienione w [[:$1]].",
        "wantedfiletext-nocat": "Następujące pliki są używane, ale nie istnieją. Pliki z obcych repozytoriów mogą być wymienione pomimo istnienia. Takie fałszywe wyniki zostaną <del>przekreślone</del>.",
+       "wantedfiletext-nocat-noforeign": "Następujące pliki są używane, ale nie istnieją.",
        "wantedtemplates": "Potrzebne szablony",
        "mostlinked": "Najczęściej linkowane strony",
        "mostlinkedcategories": "Kategorie o największej liczbie stron",
        "pageinfo-not-current": "Niestety, te informacje nie są dostępne dla starych wersji stron.",
        "pageinfo-header-basic": "Podstawowe informacje",
        "pageinfo-header-edits": "Historia edycji",
-       "pageinfo-header-restrictions": "Zabezpieczenie strony",
+       "pageinfo-header-restrictions": "Zabezpieczenie",
        "pageinfo-header-properties": "Właściwości strony",
        "pageinfo-display-title": "Wyświetlany tytuł",
        "pageinfo-default-sort": "Domyślny klucz sortowania",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|dyskusja]])",
        "unknown_extension_tag": "Nieznany znacznik rozszerzenia „$1”",
        "duplicate-defaultsort": "Uwaga: Domyślnym kluczem sortowania będzie „$2” i zastąpi on wcześniej wykorzystywany klucz „$1”.",
+       "duplicate-displaytitle": "<strong>Uwaga:</strong> Wyświetlenie tytułu „$2” powoduje nadpisanie wcześniej wyświetlanego tytułu „$1”.",
        "version": "Wersja oprogramowania",
        "version-extensions": "Zainstalowane rozszerzenia",
        "version-skins": "Zainstalowane skórki",
        "specialpages-note": "* Normalne strony specjalne.\n* <span class=\"mw-specialpagerestricted\">Zastrzeżone strony specjalne.</span>",
        "specialpages-group-maintenance": "Raporty konserwacyjne",
        "specialpages-group-other": "Inne strony specjalne",
-       "specialpages-group-login": "Zaloguj się / utwórz konto",
+       "specialpages-group-login": "Logowanie / rejestracja",
        "specialpages-group-changes": "Ostatnie zmiany i rejestry",
        "specialpages-group-media": "Pliki",
        "specialpages-group-users": "Użytkownicy i uprawnienia",
        "expand_templates_remove_nowiki": "Ukrywaj w wyniku znaczniki <nowiki>",
        "expand_templates_generate_xml": "Pokaż drzewo analizatora składni w formacie XML",
        "expand_templates_generate_rawhtml": "Pokaż surowy HTML",
-       "expand_templates_preview": "Podgląd"
+       "expand_templates_preview": "Podgląd",
+       "pagelanguage": "Wybór języka strony",
+       "pagelang-name": "Strona",
+       "pagelang-language": "Język",
+       "pagelang-use-default": "Użyj domyślnego języka",
+       "pagelang-select-lang": "Wybierz język",
+       "right-pagelang": "Zmiana języka strony",
+       "action-pagelang": "zmiany języka strony",
+       "log-name-pagelang": "Rejestr zmian języka",
+       "log-description-pagelang": "Rejestr zmian języków przypisanych do poszczególnych stron",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|zmienił|zmieniła}} język strony $3 z „$4” na „$5”."
 }
index 38a7b14..c20deed 100644 (file)
        "talkpagelinktext": "discussion",
        "specialpage": "Pàgina special",
        "personaltools": "Utiss përsonaj",
-       "postcomment": "Session neuva",
        "articlepage": "Vëdde la pàgina ëd contnù",
        "talk": "Discussion",
        "views": "Vìsite",
        "jumptonavigation": "navigassion",
        "jumptosearch": "arserché",
        "view-pool-error": "An dëspias, ij servent a son motobin carià al moment.\nTròpi utent a son an camin ch'a preuvo a lese sta pàgina-sì.\nPër piasì, ch'a speta un pòch prima ëd prové torna a lese costa pàgina.\n\n$1",
+       "generic-pool-error": "An dëspias, ij servent a son motobin carià al moment.\nTròpi utent a son an camin ch'a preuvo a lese costa arsorsa.\nPër piasì, ch'a speta un pò prima ëd prové torna a acede a costa arsorsa.",
        "pool-timeout": "Ël temp a l'é finì antramentre ch'a së spetava la saradura",
        "pool-queuefull": "La coa ëd travaj a l'é pien-a",
        "pool-errorunknown": "Eror pa conossù",
        "externaldberror": "Ò che a l'é rivaje n'eror con la base ëd dàit d'autenticassion esterna, ò pura a l'é chiel che a l'é nen autorisà a agiornesse sò cont estern.",
        "login": "Conession",
        "nav-login-createaccount": "Creé un cont o rintré ant ël sistema",
-       "loginprompt": "Che a varda mach che a venta avèj ij bëscotin abilità për podèj rintré an {{SITENAME}}.",
        "userlogin": "Creé un cont o rintré ant ël sistema",
        "userloginnocreate": "Conession",
        "logout": "Seurte da 'nt ël sistema",
        "edit-gone-missing": "As peul nen agiornesse la pàgina.\nA smija che a sia stàita scancelà.",
        "edit-conflict": "Conflit ëd modìfiche.",
        "edit-no-change": "Soa modìfica a l'é stàita ignorà, përchè gnun cambiament a l'é stàit fàit al test.",
+       "postedit-confirmation-created": "La pàgina a l'é stàita creà.",
+       "postedit-confirmation-restored": "La pàgina a l'é stàita ripristinà.",
        "postedit-confirmation-saved": "Soa modìfica a l'é stàita salvà.",
        "edit-already-exists": "La neuva pàgina a l'ha nen podù creesse.\nA esist già.",
        "defaultmessagetext": "Test che a-i sarìa se a-i fusso pa 'd modìfiche",
        "parser-template-recursion-depth-warning": "Passà ël lìmit ëd ricorsion dlë stamp ($1)",
        "language-converter-depth-warning": "Lìmit ëd profondità dël convertidor ëd lenga sorpassà ($1)",
        "node-count-exceeded-category": "Pàgine anté che ël nùmer ëd neu a l'é sorpassà",
+       "node-count-exceeded-category-desc": "Na categorìa për le pàgine andoa ël nùmer dij neud a l'é tròp grand.",
        "node-count-exceeded-warning": "La pàgina a l'ha sorpassà ël nùmer ëd neu",
        "expansion-depth-exceeded-category": "Pàgine anté che la profondeur d'espansion a l'é sorpassà",
+       "expansion-depth-exceeded-category-desc": "Costa-sì a l'é na categorìa për le pàgine andoa la profondità d'espansion a l'é tròpa.",
        "expansion-depth-exceeded-warning": "La pàgina a l'ha sorpassà la profondità d'espansion",
        "parser-unstrip-loop-warning": "Trovà un sicl nen dësmontàbil",
        "parser-unstrip-recursion-limit": "Sorpassà ël lìmit d'arcorensa nen dësmontàbil: $1",
        "currentrev": "Version dël dì d'ancheuj",
        "currentrev-asof": "Version corenta dij $1",
        "revisionasof": "Revision $1",
-       "revision-info": "Revision al $1; $2",
+       "revision-info": "Revision al $1 ëd {{GENDER:$6|$2}}$7",
        "previousrevision": "←Version pì veja",
        "nextrevision": "Revision pì neuva →",
        "currentrevisionlink": "Vardé la version corenta",
        "revdelete-text-text": "Le revision ëscancelà a compariran ancora ant la stòria dla pàgina, ma na part ëd sò contnù a sarà inacessìbil al pùblich.",
        "revdelete-text-file": "Le version d'archivi scancelà a compariran ancora ant la stòria dj'archivi, ma na part ëd sò contnù a sarà inacessìbil al pùblich.",
        "logdelete-text": "J'eveniment dl'argistr ëscancelà a compariran ancora ant j'argistr, ma na part ëd sò contnù a sarà inacessìbil al pùblich.",
-       "revdelete-text-others": "J'àutri aministrator ëd {{SITENAME}} a podran sempe acede al contù stërmà e a peulo ripristinelo torna con costa antërfassa, gavà ch'a sio definìe ëd restrission adissionaj.",
+       "revdelete-text-others": "J'àutri aministrator ëd a podran sempe acede al contù stërmà e a peulo ripristinelo torna, gavà ch'a sio definìe ëd restrission adissionaj.",
        "revdelete-confirm": "Për piasì, ch'a confema ch'a veul fé sòn, ch'as rend cont dle conseguense, e ch'a lo fa an acòrd con [[{{MediaWiki:Policy-url}}|le régole]].",
        "revdelete-suppress-text": "La scancelassion a dovrìa '''mach''' esse dovrà an costi cas:\n* Anformassion ch'a podrìo esse difamatòrie\n* Anformassion përsonaj inapropià\n*: ''adrësse ëd ca e nùmer ëd teléfon, còdes fiscaj, e via fòrt''",
        "revdelete-legend": "But-je coste limitassion-sì a le version scancelà:",
        "mergehistory-empty": "Pa gnun-a revision ch'as peula butesse ansema.",
        "mergehistory-success": "$3 {{PLURAL:$3|revision|revision}} ëd [[:$1]] a son ëstàite butà ansema a [[:$2]] sensa problema.",
        "mergehistory-fail": "A l'é nen riessusse a buté ansema le revision, për piasì, ch'as contròla la pàgina e ij temp.",
+       "mergehistory-fail-toobig": "Impossìbil fé la fusion ëd la stòria përchè un nùmer ëd {{PLURAL:$1|revision}} pi grand che $1 a sarìa spostà.",
        "mergehistory-no-source": "La pàgina sorgiss $1 a-i é pa.",
        "mergehistory-no-destination": "La pàgina ëd destinassion $1 a-i é pa.",
        "mergehistory-invalid-source": "La pàgina sorgiss a l'ha d'avèj un tìtol bon.",
index 93a3514..3d0f725 100644 (file)
        "unprotectthispage": "Alterar a proteção desta página",
        "newpage": "Página nova",
        "talkpage": "Dialogar sobre esta página",
-       "talkpagelinktext": "Discussão",
+       "talkpagelinktext": "discussão",
        "specialpage": "Página especial",
        "personaltools": "Ferramentas pessoais",
-       "postcomment": "Nova seção",
        "articlepage": "Ver página de conteúdo",
        "talk": "Discussão",
        "views": "Visualizações",
        "externaldberror": "Ocorreu ou um erro no banco de dados durante a autenticação ou não lhe é permitido atualizar a sua conta externa.",
        "login": "Autenticar-se",
        "nav-login-createaccount": "Entrar / criar conta",
-       "loginprompt": "É necessário estar com cookies ativados para poder autenticar-se no wiki {{SITENAME}}.",
        "userlogin": "Entrar / criar conta",
        "userloginnocreate": "Entrar",
        "logout": "Sair",
        "revdelete-offender": "Autor da revisão:",
        "suppressionlog": "Registro de supressões",
        "suppressionlogtext": "Abaixo está uma lista das eliminações e bloqueios envolvendo conteúdo ocultado por administradores.\nVeja a [[Special:BlockList|lista de bloqueios]] para uma lista de banimentos e bloqueios em efeito neste momento.",
-       "mergehistory": "Fundir histórico de páginas",
+       "mergehistory": "Fundir históricos das páginas",
        "mergehistory-header": "A partir desta página é possível fundir históricos de edições de uma página em outra.\nCertifique-se de que tal alteração manterá a continuidade das ações.",
        "mergehistory-box": "Fundir revisões de duas páginas:",
        "mergehistory-from": "Página de origem:",
        "mergehistory-list": "Histórico de edições habilitadas para fusão",
        "mergehistory-merge": "As edições de [[:$1]] a seguir poderão ser fundidas em [[:$2]]. Utilize a coluna de botões de opção para fundir apenas as edições feitas entre o intervalo de tempo especificado. Note que ao utilizar os links de navegação esta coluna será retornada a seus valores padrão.",
        "mergehistory-go": "Exibir edições habilitadas a serem fundidas",
-       "mergehistory-submit": "Fundir edições",
+       "mergehistory-submit": "Fundir revisões",
        "mergehistory-empty": "Não existem edições habilitadas a serem fundidas.",
        "mergehistory-success": "$3 {{PLURAL:$3|revisão|revisões}} de [[:$1]] fundidas em [[:$2]] com sucesso.",
        "mergehistory-fail": "Não foi possível fundir os históricos; por gentileza, verifique a página e os parâmetros de tempo.",
        "action-patrol": "marcar as edições de outros usuários como patrulhadas",
        "action-autopatrol": "ter suas edições marcadas como patrulhadas",
        "action-unwatchedpages": "ver a lista de páginas não-vigiadas",
-       "action-mergehistory": "fundir o histórico de edições desta página",
+       "action-mergehistory": "fundir o histórico desta página",
        "action-userrights": "editar todos os privilégios de usuário",
        "action-userrights-interwiki": "editar privilégios de usuários de outros wikis",
        "action-siteadmin": "bloquear ou desbloquear o banco de dados",
        "listgrouprights-namespaceprotection-header": "Restrições de namespace",
        "listgrouprights-namespaceprotection-namespace": "Namespace",
        "listgrouprights-namespaceprotection-restrictedto": "Direito(s) permitindo edições do usuário",
-       "trackingcategories": "Monitorando categorias",
+       "trackingcategories": "Categorias de rastreamento",
        "trackingcategories-summary": "Esta página lista categorias de monitoramento que são preenchidas automaticamente pelo software MediaWiki. Seus nomes podem ser alterados através da alteração das mensagens de sistema relevantes no namespace {{ns: 8}}.",
        "trackingcategories-msg": "Categoria de monitoramento",
        "trackingcategories-desc": "Critérios de inclusão de categoria",
        "duplicate-defaultsort": "Aviso: A chave de ordenação padrão \"$2\" sobrepõe-se à anterior chave de ordenação padrão \"$1\".",
        "version": "Versão",
        "version-extensions": "Extensões instaladas",
-       "version-skins": "Temas",
+       "version-skins": "Temas instalados",
        "version-specialpages": "Páginas especiais",
        "version-parserhooks": "Hooks do analisador (parser)",
        "version-variables": "Variáveis",
        "expand_templates_remove_nowiki": "Suprima marcações <nowiki> no resultado",
        "expand_templates_generate_xml": "Mostrar árvore de análise (parse) do XML",
        "expand_templates_generate_rawhtml": "Mostrar HTML puro",
-       "expand_templates_preview": "Pré-visualização"
+       "expand_templates_preview": "Pré-visualização",
+       "pagelang-select-lang": "Selecionar idioma",
+       "right-pagelang": "Mudar idioma da página",
+       "action-pagelang": "mudar idioma da página",
+       "log-name-pagelang": "Mudar idioma do log"
 }
index e1fd399..21846c9 100644 (file)
        "edit": "Editar",
        "edit-local": "Editar descrição local",
        "create": "Criar",
-       "create-local": "Adicionar descrição do local",
+       "create-local": "Adicionar descrição local",
        "editthispage": "Editar esta página",
        "create-this-page": "Criar esta página",
        "delete": "Eliminar",
        "talkpagelinktext": "Discussão",
        "specialpage": "Página especial",
        "personaltools": "Ferramentas pessoais",
-       "postcomment": "Seção nova",
        "articlepage": "Ver página de conteúdo",
        "talk": "Discussão",
        "views": "Vistas",
        "externaldberror": "Ocorreu um erro externo à base de dados durante a autenticação ou não lhe é permitido atualizar a sua conta externa.",
        "login": "Entrar",
        "nav-login-createaccount": "Entrar / criar conta",
-       "loginprompt": "É necessário ter os ''cookies'' ativados no seu navegador para poder autenticar-se em {{SITENAME}}.",
        "userlogin": "Criar uma conta ou entrar",
        "userloginnocreate": "Entrar",
        "logout": "Sair",
        "revdelete-text-text": "Revisões eliminadas ainda aparecerão no histórico da página, mas parte do seu conteúdo estará inacessível para o público.",
        "revdelete-text-file": "Versões eliminadas do ficheiro ainda aparecerão no histórico da página, mas parte do seu conteúdo estará inacessível para o público.",
        "logdelete-text": "Os eventos eliminados ainda aparecerão no histórico da página, mas pare de seu conteúdo será inacessível ao público.",
-       "revdelete-text-others": "Outros administradores em {{SITENAME}} podem aceder ao conteúdo oculto e torná-lo visível novamente através desta mesma interface, a menos que sejam definidas restrições adicionais.",
+       "revdelete-text-others": "Outros administradores serão ainda capazes de aceder ao conteúdo oculto e torná-lo visível novamente, a menos que sejam definidas restrições adicionais.",
        "revdelete-confirm": "Por favor, confirme que pretende executar esta operação, que compreende as suas consequências e que o faz em concordância com as [[{{MediaWiki:Policy-url}}|políticas e recomendações]].",
        "revdelete-suppress-text": "A supressão '''só''' deverá ser usada nos seguintes casos:\n* Informação potencialmente caluniosa, difamatória ou injuriosa\n* Informação pessoal imprópria\n*: ''endereços de domicílio e números de telefone, números de identificação nacional, etc''",
        "revdelete-legend": "Definir restrições de visibilidade",
        "right-deletedtext": "Ver texto eliminado e mudanças entre revisões eliminadas",
        "right-browsearchive": "Pesquisar páginas eliminadas",
        "right-undelete": "Restaurar uma página",
-       "right-suppressrevision": "Rever e restaurar revisões ocultas dos administradores",
+       "right-suppressrevision": "Ver, ocultar e restaurar revisões de páginas específicas para qualquer utilizador",
+       "right-viewsuppressed": "Ver revisões ocultas para qualquer utilizador",
        "right-suppressionlog": "Ver registos privados",
        "right-block": "Impedir outros utilizadores de editarem",
        "right-blockemail": "Impedir um utilizador de enviar correio eletrónico",
        "license": "Licença:",
        "license-header": "Licenciamento",
        "nolicense": "Nenhuma selecionada",
+       "licenses-edit": "Editar opções de licença",
        "license-nopreview": "(Antevisão indisponível)",
        "upload_source_url": " (uma URL válida, publicamente acessível)",
        "upload_source_file": " (um ficheiro no seu computador)",
+       "listfiles-delete": "eliminar",
        "listfiles-summary": "Esta página especial mostra todos os ficheiros carregados.",
        "listfiles_search_for": "Pesquisar por nome de imagem:",
        "imgfile": "ficheiro",
        "delete-edit-reasonlist": "Editar motivos de eliminação",
        "delete-toobig": "Esta página tem um histórico longo, com mais de $1 {{PLURAL:$1|edição|edições}}.\nA eliminação de páginas como esta foi restringida na {{SITENAME}}, para evitar problemas acidentais.",
        "delete-warning-toobig": "Esta página tem um histórico de edições longo, com mais de $1 {{PLURAL:$1|edição|edições}}.\nEliminá-la poderá causar problemas na base de dados da {{SITENAME}};\nprossiga com precaução.",
-       "deleting-backlinks-warning": "'''Aviso:'''  [[Special:WhatLinksHere/{{FULLPAGENAME}}|páginas]] que contêm ligações para a página que está prestes a eliminar ou que a transcluem.",
+       "deleting-backlinks-warning": "'''Aviso:''' Existem [[Special:WhatLinksHere/{{FULLPAGENAME}}|páginas]] que contêm ligações para a página que está prestes a eliminar ou que a transcluem.",
        "rollback": "Reverter edições",
-       "rollback_short": "Desfazer",
-       "rollbacklink": "desfazer",
-       "rollbacklinkcount": "desfazer $1 {{PLURAL:$1|edição|edições}}",
-       "rollbacklinkcount-morethan": "desfazer mais do que $1 {{PLURAL:$1|edição|edições}}",
+       "rollback_short": "Reverter",
+       "rollbacklink": "reverter",
+       "rollbacklinkcount": "reverter $1 {{PLURAL:$1|edição|edições}}",
+       "rollbacklinkcount-morethan": "reverter mais do que $1 {{PLURAL:$1|edição|edições}}",
        "rollbackfailed": "A reversão falhou",
        "cantrollback": "Não foi possível reverter a edição; o último contribuidor é o único autor desta página",
        "alreadyrolled": "Não foi possível reverter as edições de [[:$1]] por [[User:$2|$2]] ([[User talk:$2|discussão]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nalguém editou ou já reverteu a página.\n\nA última edição foi de [[User:$3|$3]] ([[User talk:$3|discussão]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "uctop": "(atual)",
        "month": "Até o mês:",
        "year": "Até o ano:",
-       "sp-contributions-newbies": "Mostrar só as contribuições das contas recentes",
+       "sp-contributions-newbies": "Mostrar só as contribuições de contas recentes",
        "sp-contributions-newbies-sub": "Para contas novas",
        "sp-contributions-newbies-title": "Contribuições de contas novas",
        "sp-contributions-blocklog": "registo de bloqueios",
        "expand_templates_remove_nowiki": "Suprimir marcações <nowiki> no resultado",
        "expand_templates_generate_xml": "Mostrar a árvore de análise sintáctica do XML",
        "expand_templates_generate_rawhtml": "Mostrar o HTML puro",
-       "expand_templates_preview": "Antevisão do resultado"
+       "expand_templates_preview": "Antevisão do resultado",
+       "pagelanguage": "Seletor de idioma da página",
+       "pagelang-name": "Página",
+       "pagelang-language": "Idioma",
+       "pagelang-use-default": "Usar idioma pré-definido",
+       "pagelang-select-lang": "Escolher o idioma",
+       "right-pagelang": "Alterar o idioma da página",
+       "action-pagelang": "alterar o idioma da página",
+       "log-name-pagelang": "Alterar registo de idioma",
+       "log-description-pagelang": "Este é um registo de alterações aos idiomas das páginas.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|alterou}} o idioma da página $3 de $4 para $5."
 }
index a10ad5a..ad5b288 100644 (file)
        "talkpagelinktext": "Used as name of links going to talk page in some places, like in [[Special:RecentChanges]], [[Special:Allmessages]], [[Special:Logs]], and [[Special:Watchlist/edit]].\n\n{{Identical|Talk}}",
        "specialpage": "{{Identical|Special page}}",
        "personaltools": "Heading for a group of links to your user page, talk page, preferences, watchlist, and contributions. This heading is visible in the sidebar in some skins. For an example, see [{{canonicalurl:Main_Page|useskin=simple}} Main Page using simple skin].",
-       "postcomment": "Used as link text.\n\nThe link points to the talk page and has the parameters \"action=edit&section=new\".",
        "addsection": "{{notranslate}}\nText of the new section tab (the one next to the \"edit\" tab on non-Vector skins).\n\nSee also:\n* {{msg-mw|Addsection}}\n* {{msg-mw|Accesskey-ca-addsection}}\n* {{msg-mw|Tooltip-ca-addsection}}",
        "articlepage": "'Content page' is used for NS_MAIN and any other non-standard namespaces. Only used in the Cologne Blue skin in the bottomLinks part.\n\n{{Identical|Content page}}",
        "talk": "Used as display name for the tab to all {{msg-mw|Talk}} pages. These pages accompany all content pages and can be used for discussing the content page. Example: [[Talk:Example]].\n\nSee also:\n* {{msg-mw|Talk}}\n* {{msg-mw|Accesskey-ca-talk}}\n* {{msg-mw|Tooltip-ca-talk}}\n{{Identical|Discussion}}",
        "externaldberror": "This message is thrown when a valid attempt to change the wiki password for a user fails because of a database error or an error from an external system.",
        "login": "{{Doc-special|UserLogin|unlisted=1}}\n{{Identical|Log in}}",
        "nav-login-createaccount": "Shown to anonymous users in the upper right corner of the page. When you can't create an account, the message {{msg-mw|login}} is shown.\n{{Identical|Log in / create account}}",
-       "loginprompt": "A small notice in the log in form.",
+       "loginprompt": "{{ignored}}",
        "userlogin": "Since 1.22 no longer used in core, but may still be used by extensions. DEPRECATED\n\n{{Identical|Log in / create account}}",
        "userloginnocreate": "Since 1.22 no longer used in core, but may still be used by some extensions. A variant of {{msg-mw|Userlogin}} when the user is not allowed to create a new account. DEPRECATED\n\n{{Identical|Log in}}",
        "logout": "Used as link text in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Logout}}\n* {{msg-mw|Accesskey-pt-logout}}\n* {{msg-mw|Tooltip-pt-logout}}\n{{Identical|Log out}}",
        "right-deletedtext": "{{doc-right|deletedtext}}",
        "right-browsearchive": "{{doc-right|browsearchive}}",
        "right-undelete": "{{doc-right|undelete}}",
-       "right-suppressrevision": "{{doc-right|suppressrevision}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to the group {{msg-mw|group-suppress}}, although that group is disabled by default.\n\nSee also:\n* {{msg-mw|right-suppressionlog}}\n* {{msg-mw|right-hideuser}}\n* {{msg-mw|right-deletelogentry}}\n* {{msg-mw|right-deleterevision}}",
+       "right-suppressrevision": "{{doc-right|suppressrevision}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to the group {{msg-mw|group-suppress}}, although that group is disabled by default.\n\nSee also:\n* {{msg-mw|right-suppressionlog}}\n* {{msg-mw|right-viewsuppressed}}\n* {{msg-mw|right-hideuser}}\n* {{msg-mw|right-deletelogentry}}\n* {{msg-mw|right-deleterevision}}",
+       "right-viewsuppressed": "{{doc-right|viewsuppressed}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to any group for observation of suppression activities.\n\nSee also:\n* {{msg-mw|right-suppressrevision}}",
        "right-suppressionlog": "{{doc-right|suppressionlog}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to the group {{msg-mw|group-suppress}}, although that group is disabled by default.\n\nSee also\n* {{msg-mw|right-suppressrevision}}\n* {{msg-mw|right-hideuser}}\n* {{msg-mw|right-deletelogentry}}\n* {{msg-mw|right-deleterevision}}",
        "right-block": "{{doc-right|block}}",
        "right-blockemail": "{{doc-right|blockemail}}",
        "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}}",
        "nolicense": "{{Identical|None selected}}",
        "licenses": "{{notranslate}}",
+       "licenses-edit": "Label text for a link on Special:Upload to edit MediaWiki:Licenses",
        "license-nopreview": "Error message when a certain license does not exist",
        "upload_source_url": "Used in [[Special:Upload]].\n\nSee also:\n* {{msg-mw|Sourcefilename|label}}\n* {{msg-mw|Sourceurl|label}}\n* {{msg-mw|Upload source file}}\n* {{msg-mw|Upload-maxfilesize}}",
        "upload_source_file": "Used in [[Special:Upload]].\n\nSee also:\n* {{msg-mw|Sourcefilename|label}}\n* {{msg-mw|Sourceurl|label}}\n* {{msg-mw|Upload source url}}\n* {{msg-mw|Upload-maxfilesize}}",
+       "listfiles-delete": "Text of the delete links next to the entries on [[Special:ListFiles]], surrounded by parentheses.\n{{Identical|Delete}}",
        "listfiles-summary": "This message is displayed at the top of [[Special:ImageList]] to explain how to use that special page.",
        "listfiles_search_for": "Input label for the form displayed on [[Special:ListFiles]].",
        "imgfile": "{{Identical|File}}",
        "popularpages-summary": "{{doc-specialpagesummary|popularpages}}",
        "wantedcategories": "{{doc-special|WantedCategories}}",
        "wantedcategories-summary": "{{doc-specialpagesummary|wantedcategories}}",
-       "wantedpages": "{{doc-special|WantedPages}}",
+       "wantedpages": "{{doc-special|WantedPages}}\n{{Identical|Wanted page}}",
        "wantedpages-summary": "{{doc-specialpagesummary|wantedpages}}",
        "wantedpages-badtitle": "Error message shown when [[Special:WantedPages]] is listing a page with a title that shouldn't exist.\n\nParameters:\n* $1 - a page title",
        "wantedfiles": "{{doc-special|WantedFiles}}",
        "wantedfiles-summary": "{{doc-specialpagesummary|wantedfiles}}",
-       "wantedfiletext-cat": "Message displayed at top of [[special:WantedFiles]]. $1 contains the name of the tracking category for broken files (Including Category prefix). {{msg-mw|wantedfiletext-nocat}} is used if the tracking category is disabled.",
-       "wantedfiletext-nocat": "Message displayed at top of [[special:WantedFiles]] when broken file tracking category is disabled. See {{msg-mw|wantedfiletext-cat}}.",
+       "wantedfiletext-cat": "Message displayed at top of [[special:WantedFiles]] when false positives from foreign file repositories (like commons) are likely. $1 contains the name of the tracking category for broken files (Including Category prefix). {{msg-mw|wantedfiletext-nocat}} is used if the tracking category is disabled.\n\nSee also: {{msg-mw|wantedfiletext-cat-noforeign}}, {{msg-mw|wantedfiletext-nocat}}",
+       "wantedfiletext-cat-noforeign": "Message displayed at top of [[Special:WantedFiles]] when the wiki has no foreign repositories. See also {{msg-mw|wantedfilestext-cat}}. $1 contains the name of the tracking category for broken files (Including Category prefix). {{msg-mw|wantedfiletext-nocat}} is used if the tracking category is disabled.",
+       "wantedfiletext-nocat": "Message displayed at top of [[special:WantedFiles]] when broken file tracking category is disabled and false positives from foreign file repositories (like commons) are likely. See {{msg-mw|wantedfiletext-cat}}.",
+       "wantedfiletext-nocat-noforeign": "Message displayed at top of [[special:WantedFiles]] when broken file tracking category is disabled and their are no foreign file repositories enabled on the wiki. See {{msg-mw|wantedfiletext-cat}}, {{msg-mw|wantedfiletext-nocat}}.",
        "wantedtemplates": "{{doc-special|WantedTemplates}}",
        "wantedtemplates-summary": "{{doc-specialpagesummary|wantedtemplates}}",
        "mostlinked": "{{doc-special|MostLinked}}",
        "timezone-utc": "{{optional}}",
        "unknown_extension_tag": "This is an error shown when you use an unknown extension tag name.\n\nThis feature allows tags like <code><nowiki><pre></nowiki></code> to be called with a parser like <code><nowiki>{{#tag:pre}}</nowiki></code>.\n\nParameters:\n* $1 - the unknown extension tag name",
        "duplicate-defaultsort": "See definition of [[w:Sorting|sort key]] on Wikipedia. Parameters:\n* $1 - old default sort key\n* $2 - new default sort key",
+       "duplicate-displaytitle": "Warning shown when a page has its display title set multiple times. Parameters:\n* $1 - old display title\n* $2 - new display title",
        "version": "{{doc-special|Version}}\n{{Identical|Version}}",
        "version-summary": "{{doc-specialpagesummary|version}}",
        "version-extensions": "Header on [[Special:Version]].",
index b82a39d..e219034 100644 (file)
        "talkpagelinktext": "rimanakuy",
        "specialpage": "Sapaq p'anqa",
        "personaltools": "Kikin ruraqpa llamk'anankuna",
-       "postcomment": "Musuq raki",
        "articlepage": "Qillqata qhaway",
        "talk": "Rimachina",
        "views": "Rikunakuna",
        "externaldberror": "Hawa yaykuna pantasqam karqan, ichataq manam saqillasunkichu hawa rakiqunaykita musuqchayta.",
        "login": "Yaykuy",
        "nav-login-createaccount": "Yaykuy / rakiqunata kamariy",
-       "loginprompt": "{{SITENAME}}man yaykunaykipaqqa wamp'unaykipi <i>cookies</i> nisqakunaman ari ninaykim tiyan.",
        "userlogin": "Yaykuy / rakiqunata kamariy",
        "userloginnocreate": "Yaykuy",
        "logout": "Lluqsiy",
        "largefileserver": "Kay willañiqiqa sirwiqpi allinkachisqakama saqillasqa chhikanmanta aswan hatunmi.",
        "emptyfile": "Churkusqayki willañiqiqa ch'usaqmi rikch'akun. Pantasqa sutinchá. Ama hina kaspa, llanchiy, churkuyman munasqayki willañiqichu.",
        "windows-nonascii-filename": "Kay wikiqa sapaq sananchayuq willañiqi sutikunata manam q'iminchu.",
-       "fileexists": "Kachkanñam kay sutiyuq willañiqi.\nAma hina kaspa, <strong>[[:$1]]</strong> nisqata llanchiy, huknachanaykimanta mana allin yachaspaykiqa.\n[[$1|thumb]]",
+       "fileexists": "Kachkanñam kay sutiyuq willañiqi.\nAma hina kaspa, <strong>[[:$1]]</strong> nisqata llanchiy, {{GENDER:|}}huknachanaykimanta mana allin yachaspaykiqa.\n[[$1|thumb]]",
        "filepageexists": "Kay willañiqipaq sut'ichana p'anqaqa kamarisqañam <strong>[[:$1]]</strong> nisqapi, ichataq kay sutiyuq willañiqi manaraqmi kanchu. Willanayki pisichayqa manam rikch'akunqachu sut'ichana p'anqapi. Rikch'akunanpaqqa, kikiykip makiykiwanmi llamk'apunayki tiyan.\n[[$1|thumb]]",
        "fileexists-extension": "Kay willañiqip sutinman yaqa kaqlla sutiyuq willañiqim kachkanña: [[$2|thumb]]\n* Churkunayasqayki willañiqip sutin: <strong>[[:$1]]</strong>\n* Kachkaqña willañiqip sutin: <strong>[[:$2]]</strong>\nAma hina kaspa, huk sutita akllay.",
        "fileexists-thumbnail-yes": "Willañiqiqa ancha uchuylla rikchamanmi rikch'akun ''(thumbnail)''. [[$1|thumb]]\nAma hina kaspa, <strong>[[:$1]]</strong> nisqa willañiqita llanchiy.\nLlanchisqa willañiqi qallariy chhikan kikin rikchaman kaqlla kaptinqa, huk rikchachata churkunaykiqa manam tiyanchu.",
        "duplicate-defaultsort": "Paqtataq: Kikinmanta allinchana llawi «$2» ñawpaq kikinmanta allinchana llawitam «$1» huknachan.",
        "version": "Musuqchasqa",
        "version-extensions": "Tiyachisqa mast'arinakuna",
+       "version-skins": "Churasqa qarakuna",
        "version-specialpages": "Sapaq p'anqakuna",
        "version-parserhooks": "T'ikrana ch'iwinakuna",
        "version-variables": "Hukchakuqkuna",
        "version-antispam": "Spam hark'ay",
-       "version-skins": "Qarakuna",
        "version-other": "Wakin",
        "version-mediahandlers": "Midya llamk'apuq",
        "version-hooks": "Ch'iwinakuna",
index 4271f79..07288f6 100644 (file)
        "talkpagelinktext": "Discuție",
        "specialpage": "Pagină specială",
        "personaltools": "Unelte personale",
-       "postcomment": "Secțiune nouă",
        "articlepage": "Vedeți articolul",
        "talk": "Discuție",
        "views": "Vizualizări",
        "externaldberror": "A fost fie o eroare de bază de date pentru o autentificare extenă sau nu aveți permisiunea să actualizați contul extern.",
        "login": "Autentificare",
        "nav-login-createaccount": "Creare cont / Autentificare",
-       "loginprompt": "Trebuie să ai modulele cookie activate pentru a te autentifica la {{SITENAME}}.",
        "userlogin": "Creare cont / Autentificare",
        "userloginnocreate": "Autentificare",
        "logout": "Închidere sesiune",
        "revdelete-text-text": "Versiunile șterse vor continua să fie vizibile în istoricul paginii, însă anumite părți ale conținutului acestora vor fi inaccesibile publicului.",
        "revdelete-text-file": "Versiunile șterse ale fișierului vor continua să fie vizibile în istoricul fișierului, însă anumite părți ale conținutului acestora vor fi inaccesibile publicului.",
        "logdelete-text": "Evenimentele șterse ale jurnalului vor continua să fie vizibile în jurnale, însă anumite părți ale conținutului acestora vor fi inaccesibile publicului.",
-       "revdelete-text-others": "Alți administratori de la {{SITENAME}} vor avea acces în continuare la conținutul ascuns și îl vor putea restaura prin intermediul acestei interfețe, cu excepția cazurilor în care nu sunt activate și restricții suplimentare.",
+       "revdelete-text-others": "Alți administratori vor avea acces în continuare la conținutul ascuns și îl vor restaurarea acestuia, cu excepția cazurilor în care nu sunt activate și restricții suplimentare.",
        "revdelete-confirm": "Vă rugăm să confirmați că intenționați să faceți acest lucru, că înțelegeți consecințele și că faceți asta în conformitate cu [[{{MediaWiki:Policy-url}}|politica]].",
        "revdelete-suppress-text": "Suprimarea trebuie folosită '''doar''' în următoarele cazuri:\n* Informații potențial calomnioase\n* Informații personale inadecvate\n*: ''adrese și numere de telefon personale, CNP, numere de securitate socială etc.''",
        "revdelete-legend": "Restricții de afișare",
        "right-deletedtext": "Vizualizează textul șters și modificările dintre versiunile șterse",
        "right-browsearchive": "Caută pagini șterse",
        "right-undelete": "Recuperează pagini",
-       "right-suppressrevision": "Examinează și restaurează reviziile ascunse față de administratori",
+       "right-suppressrevision": "Vizualizează, ascunde și restaurează versiuni specifice ale paginilor față de orice utilizator",
+       "right-viewsuppressed": "Vizualizează versiuni ascunse față de orice utilizator",
        "right-suppressionlog": "Vizualizează jurnale private",
        "right-block": "Blochează alți utilizatori la modificare",
        "right-blockemail": "Blochează alți utilizatori la trimiterea e-mailurilor",
        "license": "Licențiere:",
        "license-header": "Licențiere",
        "nolicense": "Nici una selectată",
+       "licenses-edit": "Modifică opțiunile pentru licență",
        "license-nopreview": "(Previzualizare indisponibilă)",
        "upload_source_url": " (un URL valid, accesibil public)",
        "upload_source_file": " (un fișier de pe computerul dv.)",
+       "listfiles-delete": "șterge",
        "listfiles-summary": "Această pagină specială listează toate fișierele încărcate.",
        "listfiles_search_for": "Căutare fișiere după nume:",
        "imgfile": "fișier",
        "wantedpages-badtitle": "Titlu invalid în rezultatele : $1",
        "wantedfiles": "Fișiere dorite",
        "wantedfiletext-cat": "Următoarele fișiere sunt utilizate, dar nu există. Fișierele provenind din depozite externe pot apărea listate, în ciuda faptului că ele nu există. Orice astfel de pozitive false vor fi <del>tăiate</del>. În plus, paginile care încorporează astfel de fișiere inexistente sunt listate la [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Următoarele fișiere sunt utilizate, dar nu există. În plus, paginile care încorporează astfel de fișiere inexistente sunt listate la [[:$1]].",
        "wantedfiletext-nocat": "Următoarele fișiere sunt utilizate, dar nu există. Fișierele provenind din depozite externe pot apărea listate, în ciuda faptului că ele nu există. Orice astfel de pozitive false vor fi <del>tăiate</del>.",
+       "wantedfiletext-nocat-noforeign": "Următoarele fișiere sunt utilizate, dar nu există.",
        "wantedtemplates": "Formate dorite",
        "mostlinked": "Cele mai căutate articole",
        "mostlinkedcategories": "Cele mai căutate categorii",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discuție]])",
        "unknown_extension_tag": "Extensie etichetă necunoscută „$1”",
        "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”.",
        "version": "Versiune",
        "version-extensions": "Extensii instalate",
        "version-skins": "Aspecte instalate",
index fce8dbb..402be56 100644 (file)
@@ -67,7 +67,8 @@
                        "아라",
                        "Eroha",
                        "Niklem",
-                       "Agilight"
+                       "Agilight",
+                       "Oleg3280"
                ]
        },
        "tog-underline": "Подчёркивание ссылок:",
        "talkpagelinktext": "обсуждение",
        "specialpage": "Служебная страница",
        "personaltools": "Персональные инструменты",
-       "postcomment": "Новый раздел",
        "articlepage": "Просмотреть статью",
        "talk": "Обсуждение",
        "views": "Просмотры",
        "externaldberror": "Произошла ошибка при аутентификации с помощью внешней базы данных или у вас недостаточно прав для внесения изменений в свою внешнюю учётную запись.",
        "login": "Представиться системе",
        "nav-login-createaccount": "Представиться / зарегистрироваться",
-       "loginprompt": "Вы должны разрешить «cookies», чтобы представиться системе.",
        "userlogin": "Представиться или зарегистрироваться",
        "userloginnocreate": "Представиться",
        "logout": "Завершение сеанса",
        "revdelete-text-text": "Удалённые версии будут по-прежнему видны в истории страницы, но части их содержимого будут недоступны для участников.",
        "revdelete-text-file": "Удалённые версии файла будут по-прежнему видны в истории страницы, но части их содержимого будут недоступны для участников.",
        "logdelete-text": "Удалённые события в журнале будут по-прежнему видны в журналах, но части их содержимого будут недоступны для участников.",
-       "revdelete-text-others": "Ð\94Ñ\80Ñ\83гие Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\8b Ð½Ð° {{grammar:genitive|{{SITENAME}}}} Ð¿Ð¾-пÑ\80ежнемÑ\83 Ð±Ñ\83деÑ\82 Ð¸Ð¼ÐµÑ\82Ñ\8c Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñ\81Ñ\82Ñ\8c Ð´Ð¾Ñ\81Ñ\82Ñ\83па Ðº Ñ\81кÑ\80Ñ\8bÑ\82омÑ\83 Ñ\81одеÑ\80жимомÑ\83 Ð¸ Ñ\81могÑ\83Ñ\82 Ð²Ð¾Ñ\81Ñ\81Ñ\82ановиÑ\82Ñ\8c ÐµÐ³Ð¾ Ñ\81нова Ñ\87еÑ\80ез Ñ\8dÑ\82оÑ\82 Ð¶Ðµ Ð¸Ð½Ñ\82еÑ\80Ñ\84ейÑ\81, если не установлены дополнительные ограничения.",
+       "revdelete-text-others": "Ð\94Ñ\80Ñ\83гие Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\8b Ð¿Ð¾-пÑ\80ежнемÑ\83 Ð±Ñ\83дÑ\83Ñ\82 Ð¸Ð¼ÐµÑ\82Ñ\8c Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñ\81Ñ\82Ñ\8c Ð´Ð¾Ñ\81Ñ\82Ñ\83па Ðº Ñ\81кÑ\80Ñ\8bÑ\82омÑ\83 Ñ\81одеÑ\80жимомÑ\83 Ð¸ Ñ\81могÑ\83Ñ\82 Ð²Ð¾Ñ\81Ñ\81Ñ\82ановиÑ\82Ñ\8c ÐµÐ³Ð¾, если не установлены дополнительные ограничения.",
        "revdelete-confirm": "Пожалуйста, подтвердите, что вы действительно желаете совершить это действие, осознаёте последствия, делаете это в соответствии с [[{{MediaWiki:Policy-url}}|правилами]].",
        "revdelete-suppress-text": "Сокрытие может производиться '''только''' в следующих случаях:\n* Потенциально клеветническая информация\n* Неуместная личная информация\n*: ''домашний адрес, номера телефонов, номер паспорта и т. д.''",
        "revdelete-legend": "Установить ограничения:",
        "right-deletedtext": "просмотр удалённого текста и изменений между удалёнными версиями страниц",
        "right-browsearchive": "поиск удалённых страниц",
        "right-undelete": "восстановление страниц",
-       "right-suppressrevision": "просмотр и восстановление скрытых от администраторов версий страниц",
+       "right-suppressrevision": "Просмотр, скрытие и восстановление скрытых версий страниц",
+       "right-viewsuppressed": "Просмотр версий, скрытых от всех участников",
        "right-suppressionlog": "просмотр частных журналов",
        "right-block": "установка ограничений на редактирование для других участников",
        "right-blockemail": "установка запрета на отправку электронной почты",
        "upload-preferred": "Предпочтительные типы файлов: $1.",
        "upload-prohibited": "Запрещённые типы файлов: $1.",
        "uploadlogpage": "Журнал загрузок",
-       "uploadlogpagetext": "Ниже представлен список последних загрузок файлов.\nСм. также [[Special:NewFiles|галерею новых файлов]], где сведения о новых загрузках представлены в более наглядном виде.",
+       "uploadlogpagetext": "Ниже представлен список последних загрузок файлов.\nСм. также [[Special:NewFiles|галерею новых файлов]], где сведения о новых загрузках представлены в более наглядном виде, и [[Special:ListFiles|все загруженные файлы]].",
        "filename": "Имя файла",
        "filedesc": "Краткое описание",
        "fileuploadsummary": "Краткое описание:",
        "license": "Лицензирование:",
        "license-header": "Лицензирование",
        "nolicense": "Отсутствует",
+       "licenses-edit": "Изменить параметры лицензии",
        "license-nopreview": "(Предпросмотр недоступен)",
        "upload_source_url": " (правильный, публично доступный интернет-адрес)",
        "upload_source_file": " (файл на вашем компьютере)",
+       "listfiles-delete": "удалить",
        "listfiles-summary": "Эта служебная страница показывает все загруженные файлы.",
        "listfiles_search_for": "Поиск по имени файла:",
        "imgfile": "файл",
        "wantedpages-badtitle": "Ошибочный заголовок в результатах запроса: $1",
        "wantedfiles": "Требуемые файлы",
        "wantedfiletext-cat": "Следующие файлы пытаются использовать, хотя их не существует. В этот список могут ошибочно попасть файлы, находящиеся во внешних хранилищах. Подобные ложные срабатывания будут отмечены <del>зачёркиванием</del>. Кроме того, страницы, содержащие несуществующие файлы, перечислены в [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Следующие файлы используются, но не существуют. Кроме того, страницы, которые ссылаются на эти файлы, не существуют и перечислены на странице [[:$1]].",
        "wantedfiletext-nocat": "Следующие файлы пытаются использовать, хотя их не существует. В этот список могут ошибочно попасть файлы, находящиеся во внешних хранилищах. Подобные ложные срабатывания будут отмечены <del>зачёркиванием</del>.",
+       "wantedfiletext-nocat-noforeign": "Следующие файлы используются, но не существуют.",
        "wantedtemplates": "Требуемые шаблоны",
        "mostlinked": "Страницы, на которые больше всего ссылок",
        "mostlinkedcategories": "Категории, на которые больше всего ссылок",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|обсуждение]])",
        "unknown_extension_tag": "Неизвестный тег расширения «$1»",
        "duplicate-defaultsort": "Внимание. Ключ сортировки по умолчанию «$2» переопределяет прежний ключ сортировки по умолчанию «$1».",
+       "duplicate-displaytitle": "<strong>Внимание:</strong> Отображаемое название «$2» переопределяет ранее заданное отображаемое название «$1».",
        "version": "Версия",
        "version-extensions": "Установленные расширения",
        "version-skins": "Установленные темы оформления",
index b9ea08d..62f3650 100644 (file)
        "tog-hidepatrolled": "Ammuccia li mudìfichi fatti ntâ l'ùrtimi canciamenti",
        "tog-newpageshidepatrolled": "Ammuccia li pàggini virificati di l'alencu dî pàgging cchiù novi",
        "tog-extendwatchlist": "Attiva tutti li funzioni avanzati pi l'ossirvati spiciali, nun sulu l'ultima",
-       "tog-usenewrc": "Utilizza Ùrtimi canciamenti avanzati (richiedi JavaScript)",
+       "tog-usenewrc": "Raggruppa li canci pi pàggina ntê canciamenti ricenti e ntâ lista dî taliati spiciali",
        "tog-numberheadings": "Nummirazzioni automàtica dî tìtuli di paràgrafu",
        "tog-showtoolbar": "Ammustra la barra dî strumenta pi lu canciamentu",
-       "tog-editondblclick": "Duppiu click pi canciari l'artìculu (richiedi Javascript)",
-       "tog-editsectiononrightclick": "Abbìlita lu canciamentu dî sezzioni tràmiti duppiu click supra lu tìtulu dâ sezzioni (richiedi Javascript)",
-       "tog-watchcreations": "Agghiunci li pàggini criati a l'ossirvati spiciali",
+       "tog-editondblclick": "Duppiu click pi canciari l'artìculu",
+       "tog-editsectiononrightclick": "Abbìlita lu canciamentu dî sizzioni tràmiti duppiu click a manu dritta supra lu tìtulu dâ sezzioni",
+       "tog-watchcreations": "Agghiunci li pàggini criati e li files â lista dî taliati",
        "tog-watchdefault": "Agghiunci li pàggini canciati a l'ossirvati spiciali",
        "tog-watchmoves": "Agghiunci li pàggini spustati a l'ossirvati spiciali",
        "tog-watchdeletion": "Agghiunci li pàggini di mìa cancillati a l'ossirvati spiciali",
index 040772c..83a0252 100644 (file)
        "talkpagelinktext": "Pogovor",
        "specialpage": "Posebna stran",
        "personaltools": "Osebna orodja",
-       "postcomment": "Nov razdelek",
        "articlepage": "Prikaže članek",
        "talk": "Pogovor",
        "views": "Pogled",
        "externaldberror": "Pri potrjevanju istovetnosti je prišlo do notranje napake ali pa za osveževanje zunanjega računa nimate dovoljenja.",
        "login": "Prijava",
        "nav-login-createaccount": "Prijavite se / registrirajte se",
-       "loginprompt": "Za prijavo v {{GRAMMAR:tožilnik|{{SITENAME}}}} morate imeti omogočene piškotke.",
        "userlogin": "Prijavite se / registrirajte se",
        "userloginnocreate": "Prijava",
        "logout": "Odjava",
        "revdelete-text-text": "Izbrisane redakcije bodo še vedno prikazane v zgodovini strani, vendar bodo deli njihovih vsebin nedostopni javnosti.",
        "revdelete-text-file": "Izbrisane različice datoteke bodo še vedno prikazane v zgodovini datoteke, vendar bodo deli njihovih vsebin nedostopni javnosti.",
        "logdelete-text": "Izbrisani dnevniški vnosi bodo še vedno prikazani v dnevnikih, vendar bodo deli njihovih vsebin nedostopni javnosti.",
-       "revdelete-text-others": "Drugi administratorji na strani {{SITENAME}} bodo še vedno lahko dostopali do skrite vsebine in jo obnovili z enakim vmesnikom, razen če so nastavljene dodatne omejitve.",
+       "revdelete-text-others": "Drugi administratorji bodo še vedno lahko dostopali do skrite vsebine in jo obnovili, razen če so nastavljene dodatne omejitve.",
        "revdelete-confirm": "Prosim potrdite da nameravate to storiti, da se zavedate posledic in da to počnete v skladu s [[{{MediaWiki:Policy-url}}|politiko]].",
        "revdelete-suppress-text": "Zadrževanje naj bi bilo uporabljeno '''le''' v sledečih primerih:\n* Morebitni klevetniški podatki\n* Neprimerni osebni podatki\n*: ''domači naslovi in telefonske številke, narodne številke istovetnosti itn.''",
        "revdelete-legend": "Nastavi omejitve vidnosti",
        "right-deletedtext": "Ogled izbrisanega besedila in primerjava med izbrisanimi redakcijami",
        "right-browsearchive": "Iskanje izbrisanih strani",
        "right-undelete": "Obnavljanje strani",
-       "right-suppressrevision": "Pregled in obnova pred administratorjem skritih redakcij",
+       "right-suppressrevision": "Ogled, skrivanje in obnavljanje določenih redakcij strani katerega koli uporabnika",
+       "right-viewsuppressed": "Ogled redakcij skritih pred vsemi uporabniki",
        "right-suppressionlog": "Ogled zasebnih dnevniških zapisov",
        "right-block": "Preprečitev (blokada) urejanja drugih uporabnikov",
        "right-blockemail": "Drugemu uporabniku lahko prepreči pošiljanje e-pošte",
        "license": "Licenca:",
        "license-header": "Licenca",
        "nolicense": "Nobeno",
+       "licenses-edit": "Urejanje možnosti dovoljenja",
        "license-nopreview": "(Predogled ni na voljo)",
        "upload_source_url": " (veljaven, javnosti dostopen URL)",
        "upload_source_file": " (datoteka na vašem računalniku)",
+       "listfiles-delete": "izbriši",
        "listfiles-summary": "Ta posebna stran prikazuje vse naložene datoteke.",
        "listfiles_search_for": "Išči po imenu datoteke:",
        "imgfile": "dat.",
        "wantedpages-badtitle": "Neveljaven naslov v končnem nizu: $1",
        "wantedfiles": "Želene datoteke",
        "wantedfiletext-cat": "Naslednje datoteke so uporabljene, vendar ne obstajajo. Navedene so morda tudi datoteke iz zunanjih hramb, čeprav obstajajo. Vsi takšni lažni pozitivi bodo <del>prečrtani</del>. Poleg tega so strani, ki vključujejo neobstoječe datoteke, navedene na [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Spodnje datoteke so nekje uporabljene, vendar ne obstajajo. Dodatno lahko strani, ki vključujejo neobstoječe datoteke, najdete na [[:$1]].",
        "wantedfiletext-nocat": "Naslednje datoteke so uporabljene, vendar ne obstajajo. Navedene so morda tudi datoteke iz zunanjih hramb, čeprav obstajajo. Vsi takšni lažni pozitivi bodo <del>prečrtani</del>.",
+       "wantedfiletext-nocat-noforeign": "Spodnje datoteke so nekje uporabljene, vendar ne obstajajo.",
        "wantedtemplates": "Želene predloge",
        "mostlinked": "Strani, na katere se največ povezuje",
        "mostlinkedcategories": "Kategorije z največ elementi",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|pogovor]])",
        "unknown_extension_tag": "Neznana razširitvena etiketa »$1«",
        "duplicate-defaultsort": "'''Opozorilo:''' Privzeti ključ razvrščanja »$2« prepiše prejšnji privzeti ključ razvrščanja »$1«.",
+       "duplicate-displaytitle": "<strong>Opozorilo:</strong> Prikazni naslov »$2« prepiše prejšnji prikazni naslov »$1«.",
        "version": "Različica",
        "version-extensions": "Nameščene razširitve",
        "version-skins": "Nameščene kože",
index c52a32c..31a2dba 100644 (file)
@@ -24,7 +24,9 @@
                        "Urhixidur",
                        "Vinie007",
                        "לערי ריינהארט",
-                       "아라"
+                       "아라",
+                       "Gertakapllani",
+                       "OrvenBregu"
                ]
        },
        "tog-underline": "Nënvizo lidhjet:",
@@ -44,7 +46,7 @@
        "tog-minordefault": "Shëno të gjitha redaktimet si të vogla automatikisht",
        "tog-previewontop": "Vendose kutinë e bocetit sipër kutisë së redaktimeve",
        "tog-previewonfirst": "Tregoje bocetin në redaktimin e parë",
-       "tog-enotifwatchlistpages": "Më njofto me e-mail kur ndryshohet një faqe apo skedaë nga lista ime e faqeve nën mbikqyrje",
+       "tog-enotifwatchlistpages": "Më njofto me e-mail kur ndryshohet një faqe apo skedarë nga lista ime e faqeve nën mbikqyrje",
        "tog-enotifusertalkpages": "Më njofto me e-mail kur faqja ime e dikutimeve të përdoruesit ndryshohet",
        "tog-enotifminoredits": "Më njofto me e-mail edhe kur ka redaktime të vogla në faqe dhe skedave",
        "tog-enotifrevealaddr": "Tregoje adresën time të e-mail-it në e-mail-et njoftuese",
        "thu": "Enj",
        "fri": "Pr",
        "sat": "Sht",
-       "january": "janar",
-       "february": "shkurt",
-       "march": "mars",
-       "april": "prill",
-       "may_long": "maj",
-       "june": "qershor",
-       "july": "korrik",
-       "august": "gusht",
-       "september": "shtator",
-       "october": "tetor",
-       "november": "nëntor",
-       "december": "dhjetor",
-       "january-gen": "janar",
-       "february-gen": "shkurt",
-       "march-gen": "mars",
-       "april-gen": "prill",
-       "may-gen": "maj",
-       "june-gen": "qershor",
+       "january": "Janar",
+       "february": "Shkurt",
+       "march": "Mars",
+       "april": "Prill",
+       "may_long": "Maj",
+       "june": "Qershor",
+       "july": "Korrik",
+       "august": "Gusht",
+       "september": "Shtator",
+       "october": "Tetor",
+       "november": "Nëntor",
+       "december": "Dhjetor",
+       "january-gen": "Janar",
+       "february-gen": "Shkurt",
+       "march-gen": "Mars",
+       "april-gen": "Prill",
+       "may-gen": "Maj",
+       "june-gen": "Qershor",
        "july-gen": "korrik",
-       "august-gen": "gusht",
-       "september-gen": "shtator",
-       "october-gen": "tetor",
-       "november-gen": "nëntor",
-       "december-gen": "dhjetor",
+       "august-gen": "Gusht",
+       "september-gen": "Shtator",
+       "october-gen": "Tetor",
+       "november-gen": "Nëntor",
+       "december-gen": "Dhjetor",
        "jan": "Jan",
        "feb": "Shku",
        "mar": "Mar",
        "oct": "Tet",
        "nov": "Nën",
        "dec": "Dhje",
-       "january-date": "$1 janar",
-       "february-date": "$1 shkurt",
-       "march-date": "$1 mars",
-       "april-date": "$1 prill",
-       "may-date": "$1 maj",
-       "june-date": "$1 qershor",
-       "july-date": "$1 korrik",
-       "august-date": "$1 gusht",
-       "september-date": "$1 shtator",
-       "october-date": "$1 tetor",
-       "november-date": "$1 nëntor",
-       "december-date": "$1 dhjetor",
+       "january-date": "$1 Janar",
+       "february-date": "Shkurt, <span class=\"notranslate\" translate=\"asnjë\">$1</span>",
+       "march-date": "Mars <span class=\"notranslate\" translate=\"asnjë\">$1</span>",
+       "april-date": "Prill <span class=\"notranslate\" translate=\"asnjë\">$1</span>",
+       "may-date": "$1 Maj",
+       "june-date": "$1 Qershor",
+       "july-date": "$1 Korrik",
+       "august-date": "$1 Gusht",
+       "september-date": "$1 Shtator",
+       "october-date": "$1 Tetor",
+       "november-date": "$1 Nëntor",
+       "december-date": "$1 Dhjetor",
        "pagecategories": "{{PLURAL:$1|Kategoria|Kategoritë}}",
        "category_header": "Artikuj në kategorinë \"$1\"",
        "subcategories": "Nën-kategori",
        "anontalk": "Diskutimet për këtë IP",
        "navigation": "Shfleto",
        "and": "&#32;dhe",
-       "qbfind": "Kërko",
+       "qbfind": "Gjeni",
        "qbbrowse": "Shfletoni",
        "qbedit": "Redaktoni",
        "qbpageoptions": "Kjo faqe",
        "qbmyoptions": "Faqet e mia",
        "faq": "Pyetje që bëhen shpesh",
-       "faqpage": "Project: Pyetje që bëhen shpesh",
+       "faqpage": "Projekt: Pyetje që bëhen shpesh",
        "actions": "Veprimet",
        "namespaces": "Hapsirat e emrit",
        "variants": "Variante",
        "talkpagelinktext": "Diskuto",
        "specialpage": "Faqe speciale",
        "personaltools": "Mjetet e mia",
-       "postcomment": "Seksion i ri",
        "articlepage": "Shiko faqen me përmbajtje",
        "talk": "Diskutimet",
        "views": "Shikime",
        "invalidtitle-knownnamespace": "Titull jo i vlefshëm me hapësirën \"$2\" dhe teksti \"$3\"",
        "invalidtitle-unknownnamespace": "Titull jo i vlefshëm me numrin e panjohur të hapësirës së emrit $1 dhe tekstit \"$2\"",
        "exception-nologin": "I paqasur",
-       "exception-nologin-text": "Kjo faqe ose ky veprim ju kërkon që të qaseni në këtë wiki.",
+       "exception-nologin-text": "Ju lutem [[Special:Userlogin|hyni brënda]] për të qenë  në gjendje të hyni në këtë faqe ose veprim.",
        "exception-nologin-text-manual": "Ju lutem <span class=\"notranslate\" translate=\"asnjë\">$1</span> që të jeni në gjendje për të hyrë në këtë faqe ose të veproni.",
        "virus-badscanner": "Konfiguracion i parregullt: Skaner i panjohur virusesh: ''$1''",
        "virus-scanfailed": "skani dështoi (code $1)",
        "externaldberror": "Ose kishte një gabim tek regjistri i identifikimit të jashtëm, ose nuk ju lejohet të përtërini llogarinë tuaje të jashtme.",
        "login": "Hyni",
        "nav-login-createaccount": "Hyni ose hapni një llogari",
-       "loginprompt": "Ju duhet të mundësoni lejimin e \"cookies\" për të hyrë brënda në {{SITENAME}}.",
        "userlogin": "Hyni / hapni llogari",
        "userloginnocreate": "Hyni",
        "logout": "Dalje",
        "createacct-benefit-heading": "{{SITENAME}} është bërë nga njerëz si ju.",
        "createacct-benefit-body1": "$1 {{PLURAL:$1|redaktim|redaktime}}",
        "createacct-benefit-body2": "\n{{Plural: $ 1 | faqe | faqe}}",
+       "createacct-benefit-body3": "kohët e fundit <span class=\"notranslate\" translate=\"asnjë\">{{PLURAL:$1|</span>kontribues|kontribuesit}}",
        "badretype": "Fjalëkalimet nuk janë njësoj.",
        "userexists": "Emri i përdoruesit që kërkuat është në përdorim. \nZgjidhni një emër tjetër.",
        "loginerror": "Gabim gjatë identifikimit",
+       "createacct-error": "krijim gabim llogarie",
        "createaccounterror": "I pamundur krijimi i llogarisë: $1",
        "nocookiesnew": "Llogaria e përdoruesit u krijua por ju nuk jeni identifikuar ende.\n{{SITENAME}} shfrytëzon \"cookies\" për të identifikuar përdoruesit.\nJu nuk mundësoni lejimin e \"cookies\".\nJu lutemi, mundësojini ato, pastaj identifikohuni me anë të të dhënave tuaja të reja: emri i përdoruesit dhe fjalëkalimi.",
        "nocookieslogin": "{{SITENAME}} shfrytëzon \"cookies\" për identifikimin e përdoruesve.\nYou nuk lejoni shfrytëzimin e \"cookies\".\nJu lutemi, lejoni shfrytëzimin e \"cookies\" dhe provojeni përsëri.",
        "passwordtooshort": "Fjalëkalimi juaj është i pavlefshëm ose tepër i shkurtër. Ai duhet të ketë së paku {{PLURAL:$1|1 shkronjë|$1 shkronja}} dhe duhet të jetë i ndryshëm nga emri i përdoruesit.",
        "password-name-match": "Fjalëkalimi juaj duhet të jetë i ndryshëm nga emri juaj.",
        "password-login-forbidden": "Përdorimi i kësaj nofke dhe fjalëkalimi është i ndaluar.",
-       "mailmypassword": "Më dërgo një fjalëkalim të ri tek adresa ime",
+       "mailmypassword": "Ridergo fjalekalimin",
        "passwordremindertitle": "Kërkesë për fjalëkalim të ri tek {{SITENAME}}",
        "passwordremindertext": "Dikush (sigurisht ju, nga adresa IP adresa $1) kërkoi një fjalëkalim të ri për hyrje tek {{SITENAME}} ($4). U krijua fjalëkalimi i përkohshëm për përdoruesin \"$2\" dhe u dërgua tek \"$3\". Nëse ky ishte tentimi juaj duhet që të kyçeni dhe ndërroni fjalëkalimin tani. Fjalëkalimi juaj i përkohshëm do të skadojë {{PLURAL:$5|një dite|$5 ditësh}}.\n\nNëse ndokush tjetër ka bërë këtë kërkesë, ose nëse ju kujtohet fjalëkalimin dhe nuk doni që ta ndërroni, mund të e injoroni këtë porosi dhe të vazhdoni të përdorni  fjalëkalimin e vjetër.",
        "noemail": "Regjistri nuk ka adresë për përdoruesin \"$1\".",
        "noemailcreate": "Ju duhet të sigurojë një adresë e e-mailit të saktë.",
        "passwordsent": "Një fjalëkalim i ri është dërguar tek adresa e regjistruar për \"$1\". Provojeni përsëri hyrjen mbasi ta keni marrë fjalëkalimin.",
        "blocked-mailpassword": "IP adresa juaj është bllokuar , si e tillë nuk lejohet të përdor funksionin pë rikthim të fjalkalimit , në mënyrë që të parandalohet abuzimi.",
-       "eauthentsent": "Një eMail konfirmues u dërgua te adresa e dhënë.\nPara se të pranohen eMail nga përdoruesit e tjerë, duhet që adressa e juaj të vërtetohet.\nJu lutemi ndiqni këshillat në eMailin e pranuar.",
+       "eauthentsent": "Një email konfirmimi është dërguar në adresën e caktuar  të e-mailit.\nParase te dergohen emaile të tjerë  në llogarinë tuaj, duhet të ndiqni udhëzimet në email, për të konfirmuar se llogaria është  vërtetë e juaja.",
        "throttled-mailpassword": "Një kujtesë e fjalëkalimit është dërguar gjatë {{PLURAL:$1|orës|$1 orëve}} të kaluara. Për t'u mbrojtur nga abuzime vetëm një kujtesë dërgohet çdo {{PLURAL:$1|orë|$1 orë}}.",
        "mailerror": "Gabim duke dërguar postën: $1",
        "acct_creation_throttle_hit": "Nuk lejoheni të krijoni më llogari pasi keni krijuar {{PLURAL:$1|1|$1}}.",
        "accountcreatedtext": "Llogarija e Përdoruesit për $1 u krijua",
        "createaccount-title": "Hapja e llogarive për {{SITENAME}}",
        "createaccount-text": "Dikush ka përdorur adresën tuaj për të hapur një llogari tek {{SITENAME}} ($4) të quajtur \"$2\" me fjalëkalimin \"$3\".\nDuhet të hyni brenda dhe të ndërroni fjalëkalimin tani nëse ky person jeni ju. Përndryshe shpërfilleni këtë mesazh.",
-       "login-throttled": "Keni bërë shumë tentime të njëpasnjëshme në fjalëkalimin e kësaj llogarie. Ju lutemi prisni para tentimit përsëri.",
+       "login-throttled": "Keni bërë shumë tentime të njëpasnjëshme në fjalëkalimin e kësaj llogarie. Ju lutemi prisni para se te tentoni përsëri.",
        "login-abort-generic": "login juaj ishte i pasuksesshëm - Ndërpre",
        "loginlanguagelabel": "Gjuha: $1",
        "suspicious-userlogout": "Kërkesa juaj për të shkëputet u mohua sepse duket sikur është dërguar nga një shfletues të thyer ose caching proxy.",
+       "createacct-another-realname-tip": "* Emri i vërtetë nuk është i domosdoshëm: Nëse e jepni do të përmendeni si kontribues për punën që ke bërë.",
+       "pt-login": "Hyni",
+       "pt-login-button": "Hyni",
+       "pt-createaccount": "Krijo llogari",
+       "pt-userlogout": "Dil",
        "php-mail-error-unknown": "Gabim i panjohur në funksionin e postës PHP ()",
        "user-mail-no-addy": "Provuat të dërgoni një korrespondencë pa adresë elektronike",
+       "user-mail-no-body": "U përpoqët të dërgonio email me një përmbajtje të shkurtër dhe të paarsyeshme.",
        "changepassword": "Ndërroni fjalëkalimin",
-       "resetpass_announce": "Ju keni hyrë me një kod të përkohshëm.\nPër të hyrë tërësisht duhet të vendosni një fjalëkalim të ri këtu:",
+       "resetpass_announce": "Për të përfunduar regjistrimin, ju duhet të vendosni një fjalëkalim të ri.",
        "resetpass_header": "Ndrysho fjalëkalimin e llogarisë",
        "oldpassword": "I vjetri",
        "newpassword": "I riu",
        "retypenew": "I riu përsëri",
        "resetpass_submit": "Ndrysho fjalëkalimin dhe hyni brenda",
-       "changepassword-success": "Fjalëkalimi juaj është ndryshuar me sukses! Mund të hyni brenda...",
+       "changepassword-success": "Fjalëkalimin juaj ka ndryshuar me sukses!",
+       "changepassword-throttled": "Keni bërë shumë tentime të njëpasnjëshme në fjalëkalimin e kësaj llogarie. Ju lutemi prisni para se te tentoni përsëri.",
        "resetpass_forbidden": "Fjalëkalimet nuk mund të ndryshohen",
        "resetpass-no-info": "Duhet të jeni i kyçur që të keni qasje direkte në këtë faqe.",
        "resetpass-submit-loggedin": "Ndrysho fjalëkalimin",
        "resetpass-submit-cancel": "Anulo",
        "resetpass-wrong-oldpass": "Fjalëkalimi momental ose i përkohshëm nuk është i vlefshëm. Ndoshta tanimë me sukses keni ndërruar fjalëkalimin, ose keni kërkuar fjalëkalim të përkohshëm.",
+       "resetpass-recycled": "Ju lutemi rivendosni fjalëkalimin tuaj për diçka tjetër përveç fjalëkalimin tuaj të tanishme.",
+       "resetpass-temp-emailed": "Ju keni hyrë në me një koditë përkohshme të dërguar me email .\nPër të përfundojë logging in, ju duhet të vendosni një fjalëkalim të ri këtu:",
        "resetpass-temp-password": "Fjalëkalimi i përkohshëm:",
+       "resetpass-abort-generic": "Ndryshimi i fjalëkalimi  dështoi nga një zgjerim.",
        "resetpass-expired": "Fjalëkalimin tuaj ka skaduar. Ju lutem vendosni një fjalëkalim të ri për të hyr.",
        "resetpass-expired-soft": "Fjalëkalimi juaj ka skaduar dhe duhet të rivendoset. Ju lutem zgjidhni një fjalëkalim të ri tani, ose klikoni \"{{int:resetpass-submit-cancel}}\" për ta rivendosur më vonë.",
+       "resetpass-validity-soft": "Fjalëkalimi juaj ka skaduar dhe duhet të rivendoset. Ju lutem zgjidhni një fjalëkalim të ri tani, ose klikoni \"{{int:resetpass-submit-cancel}}\" për ta rivendosur më vonë.",
        "passwordreset": "Ndrysho fjalkalimin",
+       "passwordreset-text-one": "Plotësoni këtë formular për të marrë një fjalëkalim të përkohshëm nëpërmjet postës elektronike.",
+       "passwordreset-text-many": "<span class=\"notranslate\" translate=\"asnjë\">{{PLURAL:$1|</span>Mbush një nga fushat për të marrë një fjalëkalim të përkohshëm nëpërmjet postës elektronike.}}",
        "passwordreset-legend": "Ndrysho fjalkalimin",
        "passwordreset-disabled": "Rivendosja e fjalëkalimit është deaktivizuar në këtë wiki.",
+       "passwordreset-emaildisabled": "Karakteristikat e  Email janë të paaftë në këtë wiki.",
        "passwordreset-username": "Nofka:",
        "passwordreset-domain": "Domain:",
        "passwordreset-capture": "Dëshiron të shikosh e-mail-in që rezulton?",
        "edit-gone-missing": "Faqja nuk mund t freskohet.\nDuket se është grisur.",
        "edit-conflict": "Konflikt në redaktim.",
        "edit-no-change": "Redaktimi juaj është anashkaluar pasi që asnjë ndryshim nuk u bë në tekst.",
+       "postedit-confirmation-created": "Faqja eshte krijuar",
+       "postedit-confirmation-restored": "Faqja eshte kthyer",
+       "postedit-confirmation-saved": "Redaktimi juaj eshte ruajtur.",
        "edit-already-exists": "Faqja nuk mundej të hapet.\nAjo tanimë ekziston.",
        "defaultmessagetext": "Teksti i porosisë së parazgjedhur",
-       "editwarning-warning": "Lënia e kësaj faqeje mund t'ju shkaktojë humbjen e çdo ndryshimi që keni bërë.\nNëse keni hyrë brenda, ju mund ta hiqni këtë paralajmërim në seksionin \"Redaktimi\" tek preferencat tuaja.",
+       "invalid-content-data": "Të pavlefshme të dhënave e përmbajtjes",
+       "editwarning-warning": "Duke e lënë këtë faqe mund të shkaktojë ju për të humbur të gjitha ndryshimet që keni bërë ju.\nNëse ju jeni regjistruar, ju mund të çaktivizoni këtë paralajmërim në \"{{int:prefs-editing}}\" seksionin e preferencave tuaja.",
        "content-model-text": "tekst i thejshtë",
        "expensive-parserfunction-warning": "Kujdes: Kjo faqe ka shumë kërkesa që kërkojnë analizë gramatikore të kushtueshme për sistemin.\n\nDuhet të ketë më pakë se $2, {{PLURAL:$2|kërkesë|kërkesa}}, kurse tani {{PLURAL:$1|është $1 kërkesë|janë $1 kërkesa}}.",
        "expensive-parserfunction-category": "Faqe me shumë shprehje të kushtueshmë për analizë gramatikore",
        "license-nopreview": "(Nuk ka parapamje)",
        "upload_source_url": " (URL e vlefshme, publikisht e përdorshme)",
        "upload_source_file": " (skeda në kompjuterin tuaj)",
+       "listfiles-delete": "fshije",
        "listfiles-summary": "Kjo faqe speciale tregon tërë skedat e ngarkuara.\nFillimisht skedat e ngarkuara së fundmi jepen më sipër.\nShtypni kolonat e tjera për të ndryshuar radhitjen.",
        "listfiles_search_for": "Kërko për emrin e figurës:",
        "imgfile": "skeda",
index 5b155d5..ccfaf09 100644 (file)
@@ -24,7 +24,8 @@
                        "Милан Јелисавчић",
                        "Михајло Анђелковић",
                        "לערי ריינהארט",
-                       "아라"
+                       "아라",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Подвлачење веза:",
        "talkpagelinktext": "разговор",
        "specialpage": "Посебна страница",
        "personaltools": "Личне алатке",
-       "postcomment": "Нови одељак",
        "articlepage": "Погледај страницу са садржајем",
        "talk": "Разговор",
        "views": "Прегледи",
        "externaldberror": "Дошло је до грешке при препознавању базе података или немате овлашћења да ажурирате свој спољни налог.",
        "login": "Пријави ме",
        "nav-login-createaccount": "Пријава/регистрација",
-       "loginprompt": "Омогућите колачиће да бисте се пријавили на овај вики.",
        "userlogin": "Пријава/регистрација",
        "userloginnocreate": "Пријава",
        "logout": "Одјава",
        "loginerror": "Грешка при пријављивању",
        "createacct-error": "Дошло је до грешке при креирању налога",
        "createaccounterror": "Не могу да отворим налог: $1",
-       "nocookiesnew": "Кориснички налог је отворен, али нисте пријављени.\nОвај вики користи колачиће за пријаву. Вама су колачићи онемогућени.\nОмогућите их, па се онда пријавите са својим корисничким именом и лозинком.",
-       "nocookieslogin": "Овај вики користи колачиће за пријављивање корисника.\nВама су колачићи онемогућени. Омогућите их и покушајте поново.",
+       "nocookiesnew": "Кориснички налог је отворен, али нисте пријављени.\n{{SITENAME}} користи колачиће за пријаву. Вама су колачићи онемогућени.\nОмогућите их, па се онда пријавите са својим корисничким именом и лозинком.",
+       "nocookieslogin": "{{SITENAME}} користи колачиће за пријављивање корисника.\nВама су колачићи онемогућени. Омогућите их и покушајте поново.",
        "nocookiesfornew": "Кориснички налог није отворен јер његов извор није потврђен.\nОмогућите колачиће на прегледачу и поново учитајте страницу.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "noname": "Унели сте неисправно корисничко име.",
        "mergehistory-empty": "Нема измена за спајање.",
        "mergehistory-success": "$3 {{PLURAL:$3|измена странице [[:$1]] је спојена|измене странице [[:$1]] су спојене|измена странице [[:$1]] је спојено}} у [[:$2]].",
        "mergehistory-fail": "Не могу да спојим историје. Проверите страницу и временске параметре.",
-       "mergehistory-fail-toobig": "Није могуће спојити историје јер више од $1 {{PLURAL:$1|измене|измена}} ће бити премештено.",
+       "mergehistory-fail-toobig": "Није могуће спојити историје јер више од $1 {{PLURAL:$1|измене ће бити премештене|измена ће бити премештено}}.",
        "mergehistory-no-source": "Изворна страница $1 не постоји.",
        "mergehistory-no-destination": "Одредишна страница $1 не постоји.",
        "mergehistory-invalid-source": "Изворна страница мора имати исправан наслов.",
        "showhideselectedversions": "Прикажи/сакриј изабране измене",
        "editundo": "поништи",
        "diff-empty": "(Нема разлике)",
-       "diff-multi-sameuser": "({{PLURAL:$1|Једна међуизмена истог корисника није приказана|$1 међуизмена истог корисника није приказано}})",
-       "diff-multi-otherusers": "({{PLURAL:$1|Једна међуизмена|$1 међуизмена}} од стране {{PLURAL:$2|још једног корисника није приказана|$2 корисника није приказано}})",
+       "diff-multi-sameuser": "({{PLURAL:$1|Ð\88една Ð¼ÐµÑ\92Ñ\83измена Ð¸Ñ\81Ñ\82ог ÐºÐ¾Ñ\80иÑ\81ника Ð½Ð¸Ñ\98е Ð¿Ñ\80иказана|$1 Ð¼ÐµÑ\92Ñ\83измене Ð¸Ñ\81Ñ\82ог ÐºÐ¾Ñ\80иÑ\81ника Ð½Ð¸Ñ\98е Ð¿Ñ\80иказано|$1 Ð¼ÐµÑ\92Ñ\83измена Ð¸Ñ\81Ñ\82ог ÐºÐ¾Ñ\80иÑ\81ника Ð½Ð¸Ñ\98е Ð¿Ñ\80иказано}})",
+       "diff-multi-otherusers": "({{PLURAL:$1|Ð\88една Ð¼ÐµÑ\92Ñ\83измена|$1 Ð¼ÐµÑ\92Ñ\83измене|$1 Ð¼ÐµÑ\92Ñ\83измена}} Ð¾Ð´ Ñ\81Ñ\82Ñ\80ане {{PLURAL:$2|Ñ\98оÑ\88 Ñ\98едног ÐºÐ¾Ñ\80иÑ\81ника Ð½Ð¸Ñ\98е Ð¿Ñ\80иказана|$2 ÐºÐ¾Ñ\80иÑ\81ника Ð½Ð¸Ñ\98е Ð¿Ñ\80иказано}})",
        "diff-multi-manyusers": "({{PLURAL:$1|Није приказана међуизмена|Нису приказане $1 међуизмене|Није приказано $1 међуизмена}} од више од $2 корисника)",
        "difference-missing-revision": "Не могу да пронађем {{PLURAL:$2|једну измену|$2 измене|$2 измена}} од ове разлике ($1).\n\nОво се обично дешава када пратите застарелу везу до странице која је обрисана.\nВише информација можете пронаћи у [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} дневнику брисања].",
        "searchresults": "Резултати претраге",
        "license-nopreview": "(преглед није доступан)",
        "upload_source_url": " (исправна и јавно доступна адреса)",
        "upload_source_file": "(датотека на вашем рачунару)",
+       "listfiles-delete": "обриши",
        "listfiles-summary": "Ова посебна страница приказује све послате датотеке.",
        "listfiles_search_for": "Назив датотеке:",
        "imgfile": "датотека",
        "uploadnewversion-linktext": "Пошаљи нову верзију ове датотеке",
        "shared-repo-from": "из $1",
        "shared-repo": "заједничко складиште",
-       "shared-repo-name-wikimediacommons": "{{#SWITCH:{{{1|}}}\n|#default=Викимедијина остава\n|dat=Викимедијиној остави\n}}",
+       "shared-repo-name-wikimediacommons": "Викимедијина остава",
        "filepage.css": "/* CSS који је постављен овде се налази на страницама за опис датотека, као и на страним викијима */",
        "upload-disallowed-here": "Не можете да замените ову датотеку.",
        "filerevert": "Врати $1",
        "ninterwikis": "$1 {{PLURAL:$1|међувики|међувикија|међувикија}}",
        "nlinks": "$1 {{PLURAL:$1|веза|везе|веза}}",
        "nmembers": "$1 {{PLURAL:$1|члан|члана|чланова}}",
+       "nmemberschanged": "$1 → $2 {{PLURAL:$2|члан|члана|чланова}}",
        "nrevisions": "$1 {{PLURAL:$1|измена|измене|измена}}",
        "nviews": "$1 {{PLURAL:$1|преглед|прегледа|прегледа}}",
        "nimagelinks": "Користи се на $1 {{PLURAL:$1|страници|странице|страница}}",
        "wantedfiles": "Тражене датотеке",
        "wantedfiletext-cat": "Следеће датотеке се користе, али не постоје. Датотеке из других ризница могу бити наведене иако не постоје. Такве датотеке ће бити <del>поништене</del> са списка. Поред тога, странице које садрже непостојеће датотеке се налазе [[:$1|овде]].",
        "wantedfiletext-nocat": "Следеће датотеке се користе, али не постоје. Датотеке из других ризница могу бити наведене иако не постоје. Такве датотеке ће бити <del>поништене</del> са списка.",
+       "wantedfiletext-nocat-noforeign": "Следеће датотеке се користе, али не постоје.",
        "wantedtemplates": "Тражени шаблони",
        "mostlinked": "Странице с највише веза",
        "mostlinkedcategories": "Категорије с највише веза",
        "ipb_expiry_invalid": "Време истека је неисправно.",
        "ipb_expiry_temp": "Сакривене блокаде корисника морају бити трајне.",
        "ipb_hide_invalid": "Не могу да потиснем овај налог; има више од {{PLURAL:$1|једне измене|$1 измена}}.",
-       "ipb_already_blocked": "„$1“ је већ блокиран",
+       "ipb_already_blocked": "„$1“ је већ блокиран.",
        "ipb-needreblock": "$1 је већ блокиран. Желите ли да промените подешавања?",
        "ipb-otherblocks-header": "{{PLURAL:$1|Друга блокада|Друге блокаде}}",
        "unblock-hideuser": "Не можете деблокирати овог корисника јер је његово корисничко име сакривено.",
        "movenotallowedfile": "Немате дозволу да премештате датотеке.",
        "cant-move-user-page": "Немате дозволу за премештање основних корисничких страница (осим подстраница).",
        "cant-move-to-user-page": "Немате дозволу за премештање странице на вашу корисничку страницу (осим на корисничку подстраницу).",
+       "cant-move-category-page": "Немате дозволу да премештате странице категорија.",
        "newtitle": "Нови наслов:",
        "move-watch": "Надгледај ову страницу",
        "movepagebtn": "Премести страницу",
        "movepage-page-exists": "Страница $1 већ постоји и не може се заменити.",
        "movepage-page-moved": "Страница $1 је премештена на $2.",
        "movepage-page-unmoved": "Страница $1 не може да се премести на $2.",
-       "movepage-max-pages": "Највише $1 {{PLURAL:$1|страница је премештена|странице су премештене|страница је премештено}}, и више не може да буде аутоматски премештено.",
+       "movepage-max-pages": "Највише $1 {{PLURAL:$1|страница је премештена|странице су премештене|страница је премештено}} и више не може да буде аутоматски премештено.",
        "movelogpage": "Дневник премештања",
        "movelogpagetext": "Испод се налази списак премештања страница.",
        "movesubpage": "{{PLURAL:$1|Подстраница|Подстранице}}",
        "importinterwiki": "Међувики увоз",
        "import-interwiki-text": "Изаберите вики и наслов странице за увоз.\nДатуми и имена уредника ће бити сачувани.\nСве радње при увозу с других викија су забележене у [[Special:Log/import|дневнику увоза]].",
        "import-interwiki-source": "Извор викија/странице:",
-       "import-interwiki-history": "Копирај све старије измене ове странице",
+       "import-interwiki-history": "Копирај све верзије историје за ову страницу",
        "import-interwiki-templates": "Укључи све шаблоне",
        "import-interwiki-submit": "Увези",
        "import-interwiki-namespace": "Одредишни именски простор:",
        "import-rootpage-nosubpage": "Именски простор „$1“ основне странице не дозвољава подстранице.",
        "importlogpage": "Дневник увоза",
        "importlogpagetext": "Административни увози страница с историјама измена с других викија.",
-       "import-logentry-upload": "{{GENDER:|је увезао|је увезла|уведе}} „[[$1]]“ отпремањем датотеке",
+       "import-logentry-upload": "увезено [[$1]] отпремањем датотеке",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|измена|измене|измена}}",
        "import-logentry-interwiki": "премештено с другог викија: $1",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|измена|измене|измена}} од $2",
        "rcpatroldisabled": "Патролирање скорашњих измена је онемогућено",
        "rcpatroldisabledtext": "Патролирање скорашњих измена је онемогућено.",
        "markedaspatrollederror": "Не могу да означим као патролирано",
-       "markedaspatrollederrortext": "Морате изабрати измену да бисте је означили као прегледану.",
+       "markedaspatrollederrortext": "Морате изабрати измену да бисте је означили као патролирану.",
        "markedaspatrollederror-noautopatrol": "Не можете да означите своје измене као патролиране.",
        "markedaspatrollednotify": "Ова измена на страници „$1“ је означена као патролирана.",
        "markedaspatrollederrornotify": "Означавање ове странице патролираном није успело.",
        "duplicate-defaultsort": "'''Упозорење:''' подразумевани кључ сврставања „$2“ мења некадашњи кључ „$1“.",
        "version": "Верзија",
        "version-extensions": "Инсталирана проширења",
-       "version-skins": "Теме",
+       "version-skins": "Ð\98нÑ\81Ñ\82алиÑ\80ане Ñ\82еме",
        "version-specialpages": "Посебне странице",
        "version-parserhooks": "Куке рашчлањивача",
        "version-variables": "Променљиве",
        "logentry-move-move_redir": "$1 је {{GENDER:$2|преместио|преместила}} страницу $3 на $4 преко преусмерења",
        "logentry-move-move_redir-noredirect": "$1 је {{GENDER:$2|преместио|преместила}} страницу $3 на $4 преко преусмерења без остављања преусмерења",
        "logentry-patrol-patrol": "$1 је {{GENDER:$2|означио|означила}} измену $4 странице $3 као патролирану",
-       "logentry-patrol-patrol-auto": "$1 је аутоматски {{GENDER:$2|означио|означила}} измену $4 странице $3 као прегледану",
+       "logentry-patrol-patrol-auto": "$1 је аутоматски {{GENDER:$2|означио|означила}} измену $4 странице $3 као патролирану",
        "logentry-newusers-newusers": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог",
        "logentry-newusers-create": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог",
        "logentry-newusers-create2": "$1 је {{GENDER:$2|отворио|отворила}} кориснички налог $3",
index a6025d7..a1bcf4c 100644 (file)
@@ -16,7 +16,8 @@
                        "Жељко Тодоровић",
                        "Михајло Анђелковић",
                        "לערי ריינהארט",
-                       "아라"
+                       "아라",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Podvlačenje veza:",
        "talkpagelinktext": "razgovor",
        "specialpage": "Posebna stranica",
        "personaltools": "Lične alatke",
-       "postcomment": "Novi odeljak",
        "articlepage": "Pogledaj stranicu sa sadržajem",
        "talk": "Razgovor",
        "views": "Pregledi",
        "externaldberror": "Došlo je do greške pri prepoznavanju baze podataka ili nemate ovlašćenja da ažurirate svoj spoljni nalog.",
        "login": "Prijavi me",
        "nav-login-createaccount": "Prijava/registracija",
-       "loginprompt": "Omogućite kolačiće da biste se prijavili na ovaj viki.",
        "userlogin": "Prijava/registracija",
        "userloginnocreate": "Prijava",
        "logout": "Odjava",
        "loginerror": "Greška pri prijavljivanju",
        "createacct-error": "Došlo je do greške pri kreiranju naloga",
        "createaccounterror": "Ne mogu da otvorim nalog: $1",
-       "nocookiesnew": "Korisnički nalog je otvoren, ali niste prijavljeni.\nOvaj viki koristi kolačiće za prijavu. Vama su kolačići onemogućeni.\nOmogućite ih, pa se onda prijavite sa svojim korisničkim imenom i lozinkom.",
-       "nocookieslogin": "Ovaj viki koristi kolačiće za prijavljivanje korisnika.\nVama su kolačići onemogućeni. Omogućite ih i pokušajte ponovo.",
+       "nocookiesnew": "Korisnički nalog je otvoren, ali niste prijavljeni.\n{{SITENAME}} koristi kolačiće za prijavu. Vama su kolačići onemogućeni.\nOmogućite ih, pa se onda prijavite sa svojim korisničkim imenom i lozinkom.",
+       "nocookieslogin": "{{SITENAME}} koristi kolačiće za prijavljivanje korisnika.\nVama su kolačići onemogućeni. Omogućite ih i pokušajte ponovo.",
        "nocookiesfornew": "Korisnički nalog nije otvoren jer njegov izvor nije potvrđen.\nOmogućite kolačiće na pregledaču i ponovo učitajte stranicu.",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "noname": "Uneli ste neispravno korisničko ime.",
        "showhideselectedversions": "Prikaži/sakrij izabrane izmene",
        "editundo": "poništi",
        "diff-empty": "(Nema razlike)",
-       "diff-multi-sameuser": "({{PLURAL:$1|Jedna međuizmena istog korisnika nije prikazana|$1 međuizmena istog korisnika nije prikazano}})",
-       "diff-multi-otherusers": "({{PLURAL:$1|Jedna međuizmena|$1 međuizmena}} od strane {{PLURAL:$2|još jednog korisnika nije prikazana|$2 korisnika nije prikazano}})",
+       "diff-multi-sameuser": "({{PLURAL:$1|Jedna međuizmena istog korisnika nije prikazana|$1 međuizmene istog korisnika nije prikazano|$1 međuizmena istog korisnika nije prikazano}})",
+       "diff-multi-otherusers": "({{PLURAL:$1|Jedna međuizmena|$1 međuizmene|$1 međuizmena}} od strane {{PLURAL:$2|još jednog korisnika nije prikazana|$2 korisnika nije prikazano}})",
        "diff-multi-manyusers": "({{PLURAL:$1|Nije prikazana međuizmena|Nisu prikazane $1 međuizmene|Nije prikazano $1 međuizmena}} od više od $2 korisnika)",
        "difference-missing-revision": "Ne mogu da pronađem {{PLURAL:$2|jednu izmenu|$2 izmene|$2 izmena}} od ove razlike ($1).\n\nOvo se obično dešava kada pratite zastarelu vezu do stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} dnevniku brisanja].",
        "searchresults": "Rezultati pretrage",
        "uploadnewversion-linktext": "Pošalji novo izdanje ove datoteke",
        "shared-repo-from": "iz $1",
        "shared-repo": "zajedničko skladište",
-       "shared-repo-name-wikimediacommons": "{{#SWITCH:{{{1|}}}\n|#default=Vikimedijina ostava\n|dat=Vikimedijinoj ostavi\n}}",
+       "shared-repo-name-wikimediacommons": "Vikimedijina ostava",
        "filepage.css": "/* CSS koji je postavljen ovde se nalazi na stranicama za opis datoteka, kao i na stranim vikijima */",
        "upload-disallowed-here": "Ne možete da zamenite ovu datoteku.",
        "filerevert": "Vrati $1",
        "ninterwikis": "$1 {{PLURAL:$1|međuviki|međuvikija|međuvikija}}",
        "nlinks": "$1 {{PLURAL:$1|veza|veze|veza}}",
        "nmembers": "$1 {{PLURAL:$1|član|člana|članova}}",
+       "nmemberschanged": "$1 → $2 {{PLURAL:$2|član|člana|članova}}",
        "nrevisions": "$1 {{PLURAL:$1|izmena|izmene|izmena}}",
        "nviews": "$1 {{PLURAL:$1|pregled|pregleda|pregleda}}",
        "nimagelinks": "Koristi se na $1 {{PLURAL:$1|stranici|stranice|stranica}}",
        "ipb_expiry_invalid": "Vreme isteka je neispravno.",
        "ipb_expiry_temp": "Sakrivene blokade korisnika moraju biti trajne.",
        "ipb_hide_invalid": "Ne mogu da potisnem ovaj nalog; ima više od {{PLURAL:$1|jedne izmene|$1 izmena}}.",
-       "ipb_already_blocked": "„$1“ je već blokiran",
+       "ipb_already_blocked": "„$1“ je već blokiran.",
        "ipb-needreblock": "$1 je već blokiran. Želite li da promenite podešavanja?",
        "ipb-otherblocks-header": "{{PLURAL:$1|Druga blokada|Druge blokade}}",
        "unblock-hideuser": "Ne možete deblokirati ovog korisnika jer je njegovo korisničko ime sakriveno.",
        "movenotallowedfile": "Nemate dozvolu da premeštate datoteke.",
        "cant-move-user-page": "Nemate dozvolu za premeštanje osnovnih korisničkih stranica (osim podstranica).",
        "cant-move-to-user-page": "Nemate dozvolu za premeštanje stranice na vašu korisničku stranicu (osim na korisničku podstranicu).",
+       "cant-move-category-page": "Nemate dozvolu da premeštate stranice kategorija.",
        "newtitle": "Novi naslov:",
        "move-watch": "Nadgledaj ovu stranicu",
        "movepagebtn": "Premesti stranicu",
        "movepage-page-exists": "Stranica $1 već postoji i ne može se zameniti.",
        "movepage-page-moved": "Stranica $1 je premeštena na $2.",
        "movepage-page-unmoved": "Stranica $1 ne može da se premesti na $2.",
-       "movepage-max-pages": "Najviše $1 {{PLURAL:$1|stranica je premeštena|stranice su premeštene|stranica je premešteno}}, i više ne može da bude automatski premešteno.",
+       "movepage-max-pages": "Najviše $1 {{PLURAL:$1|stranica je premeštena|stranice su premeštene|stranica je premešteno}} i više ne može da bude automatski premešteno.",
        "movelogpage": "Dnevnik premeštanja",
        "movelogpagetext": "Ispod se nalazi spisak premeštanja stranica.",
        "movesubpage": "{{PLURAL:$1|Podstranica|Podstranice}}",
        "importinterwiki": "Međuviki uvoz",
        "import-interwiki-text": "Izaberite viki i naslov stranice za uvoz.\nDatumi i imena urednika će biti sačuvani.\nSve radnje pri uvozu s drugih vikija su zabeležene u [[Special:Log/import|dnevniku uvoza]].",
        "import-interwiki-source": "Izvor vikija/stranice:",
-       "import-interwiki-history": "Umnoži sve izmene ove stranice",
+       "import-interwiki-history": "Kopiraj sve verzije istorije za ovu stranicu",
        "import-interwiki-templates": "Uključi sve šablone",
        "import-interwiki-submit": "Uvezi",
        "import-interwiki-namespace": "Odredišni imenski prostor:",
        "import-rootpage-nosubpage": "Imenski prostor „$1“ osnovne stranice ne dozvoljava podstranice.",
        "importlogpage": "Dnevnik uvoza",
        "importlogpagetext": "Administrativni uvozi stranica s istorijama izmena s drugih vikija.",
-       "import-logentry-upload": "{{GENDER:|je uvezao|je uvezla|uvede}} „[[$1]]“ otpremanjem datoteke",
+       "import-logentry-upload": "uvezeno [[$1]] otpremanjem datoteke",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|izmena|izmene|izmena}}",
        "import-logentry-interwiki": "premešteno s drugog vikija: $1",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|izmena|izmene|izmena}} od $2",
        "rcpatroldisabled": "Patroliranje skorašnjih izmena je onemogućeno",
        "rcpatroldisabledtext": "Patroliranje skorašnjih izmena je onemogućeno.",
        "markedaspatrollederror": "Ne mogu da označim kao patrolirano",
-       "markedaspatrollederrortext": "Morate izabrati izmenu da biste je označili kao pregledanu.",
+       "markedaspatrollederrortext": "Morate izabrati izmenu da biste je označili kao patroliranu.",
        "markedaspatrollederror-noautopatrol": "Ne možete da označite svoje izmene kao patrolirane.",
        "markedaspatrollednotify": "Ova izmena na stranici „$1“ je označena kao patrolirana.",
        "markedaspatrollederrornotify": "Označavanje ove stranice patroliranom nije uspelo.",
        "logentry-move-move_redir": "$1 je {{GENDER:$2|premestio|premestila}} stranicu $3 na $4 preko preusmerenja",
        "logentry-move-move_redir-noredirect": "$1 je {{GENDER:|premestio|premestila}} stranicu $3 na $4 preko preusmerenja bez ostavljanja preusmerenja",
        "logentry-patrol-patrol": "$1 je {{GENDER:$2|označio|označila}} izmenu $4 stranice $3 kao patroliranu",
-       "logentry-patrol-patrol-auto": "$1 je automatski {{GENDER:$2|označio|označila}} izmenu $4 stranice $3 kao pregledanu",
+       "logentry-patrol-patrol-auto": "$1 je automatski {{GENDER:$2|označio|označila}} izmenu $4 stranice $3 kao patroliranu",
        "logentry-newusers-newusers": "$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog",
        "logentry-newusers-create": "$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog",
        "logentry-newusers-create2": "$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog $3",
index 337eb45..50ad2f7 100644 (file)
        "talkpagelinktext": "Diskussion",
        "specialpage": "Specialsida",
        "personaltools": "Personliga verktyg",
-       "postcomment": "Nytt avsnitt",
        "articlepage": "Visa innehållssida",
        "talk": "Diskussion",
        "views": "Visningar",
        "externaldberror": "Antingen inträffade autentiseringsproblem med en extern databas, eller så får du inte uppdatera ditt externa konto.",
        "login": "Logga in",
        "nav-login-createaccount": "Logga in / skapa konto",
-       "loginprompt": "Du måste tillåta kakor för att logga in på {{SITENAME}}.",
        "userlogin": "Logga in / skapa konto",
        "userloginnocreate": "Logga in",
        "logout": "Logga ut",
        "subject": "Ämne/rubrik:",
        "minoredit": "Mindre ändring (m)",
        "watchthis": "Bevaka denna sida",
-       "savearticle": "Spara sida",
+       "savearticle": "Spara sidan",
        "preview": "Förhandsgranska",
        "showpreview": "Visa förhandsgranskning",
        "showdiff": "Visa ändringar",
        "revdelete-text-text": "Raderade sidversioner kommer fortfarande synas i sidans historik, men delar av innehållet kommer inte att bli tillgängligt offentligt.",
        "revdelete-text-file": "Raderade filversioner kommer fortfarande synas i filens historik, men delar av innehållet kommer inte att bli tillgängligt offentligt.",
        "logdelete-text": "Raderade logghändelser kommer fortfarande synas i loggarna, men delar av innehållet kommer inte att bli tillgängligt offentligt.",
-       "revdelete-text-others": "Andra administratörer på {{SITENAME}} kommer fortfarande att kunna komma åt det dolda innehållet och återställa det igen genom samma gränssnitt om inte tilläggande begränsningar används.",
+       "revdelete-text-others": "Andra administratörer kommer fortfarande att kunna komma åt det dolda innehållet och återställa det igen om inte ytterligare begränsningar används.",
        "revdelete-confirm": "Var god bekräfta att du vill göra detta, och att du förstår konsekvenserna, och att du gör så i enlighet med [[{{MediaWiki:Policy-url}}|policyn]].",
        "revdelete-suppress-text": "Undanhållande ska '''bara''' användas i följande fall:\n* Eventuell förolämpande information\n* Opassande personlig information\n*: ''hemadresser och telefonnummer, personnummer, etc.''",
        "revdelete-legend": "Ändra synlighet",
        "right-deletedtext": "Visa raderad text och ändringar mellan raderade versioner",
        "right-browsearchive": "Sök efter raderade sidor",
        "right-undelete": "Återställ raderade sidor",
-       "right-suppressrevision": "Se och återställa sidversioner som dolts för administratörer",
+       "right-suppressrevision": "Se, dölj och ta fram specifika sidversioner som dolts för alla användare",
+       "right-viewsuppressed": "Se sidversioner som dolts från alla användare",
        "right-suppressionlog": "Se privata loggar",
        "right-block": "Blockera andra användare från att redigera",
        "right-blockemail": "Blockera användare från att skicka e-post",
        "license": "Licens:",
        "license-header": "Licensiering",
        "nolicense": "Ingen angiven",
+       "licenses-edit": "Redigera licensalternativ",
        "license-nopreview": "(Förhandsvisning är inte tillgänglig)",
        "upload_source_url": " (en giltig URL som är allmänt åtkomlig)",
        "upload_source_file": " (en fil på din dator)",
+       "listfiles-delete": "radera",
        "listfiles-summary": "Den här specialsidan visar alla filer som laddats upp.",
        "listfiles_search_for": "Sök efter filnamn:",
        "imgfile": "fil",
        "wantedpages-badtitle": "Ogiltig titel bland resultaten: $1",
        "wantedfiles": "Önskade filer",
        "wantedfiletext-cat": "Följande filer används men finns inte. Filer från utländska databaser kan vara listade trots att de inte finns. Sådana falska realiteter kommer att <del>tas bort</del>. Sidor som bäddar in filer som inte finns listas upp på [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Följande filer används men finns inte. Sidor som bäddar in filer som inte finns listas i [[:$1]].",
        "wantedfiletext-nocat": "Följande filer används men finns inte. Filer från utländska databaser kan vara listade trots att de inte finns. Sådana falska realiteter kommer att <del>tas bort</del>.",
+       "wantedfiletext-nocat-noforeign": "Följande filer används men finns inte.",
        "wantedtemplates": "Önskade mallar",
        "mostlinked": "Sidor med flest länkar till sig",
        "mostlinkedcategories": "Kategorier med flest länkar till sig",
        "allinnamespace": "Alla sidor (i namnrymden $1)",
        "allpagessubmit": "Visa",
        "allpagesprefix": "Visa sidor med prefixet:",
-       "allpagesbadtitle": "Den sökta sidtiteln var ogiltig eller så innehöll den ett prefix för annan språkversion eller interwiki-prefix. Titeln kan innehålla bokstäver som inte är tillåtna i sidtitlar.",
+       "allpagesbadtitle": "Den angivna sidtiteln var ogiltig eller innehöll ett prefix för annan språkversion eller ett interwiki-prefix.\nDen kan innehålla en eller fler tecken som inte är tillåtna i titlar.",
        "allpages-bad-ns": "Namnrymden \"$1\" finns inte på {{SITENAME}}.",
        "allpages-hide-redirects": "Göm omdirigeringar",
        "cachedspecial-viewing-cached-ttl": "Du visar en cachad version av denna sida, som kan vara upp till $1 gammal.",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|diskussion]])",
        "unknown_extension_tag": "Okänd tagg \"$1\"",
        "duplicate-defaultsort": "'''Varning:''' Standardsorteringsnyckeln \"$2\" tar över från den tidigare standardsorteringsnyckeln \"$1\".",
+       "duplicate-displaytitle": "<strong>Varning:</strong> Visningstiteln \"$2\" skriver över den tidigare visningstiteln \"$1\".",
        "version": "Version",
        "version-extensions": "Installerade programtillägg",
        "version-skins": "Installerade utseenden",
        "expand_templates_generate_xml": "Visa parseträd som XML",
        "expand_templates_generate_rawhtml": "Visa rå HTML",
        "expand_templates_preview": "Förhandsvisning",
-       "pagelanguage": "Språkväljare för sidor",
+       "pagelanguage": "Sidspråksväljare",
        "pagelang-name": "Sida",
        "pagelang-language": "Språk",
        "pagelang-use-default": "Använd standardspråk",
        "pagelang-select-lang": "Välj språk",
        "right-pagelang": "Ändra sidans språk",
        "action-pagelang": "ändra sidspråket",
-       "log-name-pagelang": "Ändra språklogg",
+       "log-name-pagelang": "Språkändringslogg",
        "log-description-pagelang": "Detta är en logg över ändringar i sidspråken.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|ändrade}} sidspråket för $3 från $4 till $5."
 }
index 083efdd..b265193 100644 (file)
        "talkpagelinktext": "พูดคุย",
        "specialpage": "หน้าพิเศษ",
        "personaltools": "เครื่องมือส่วนตัว",
-       "postcomment": "ส่วนใหม่",
        "articlepage": "ดูหน้าเนื้อหา",
        "talk": "อภิปราย",
        "views": "ดู",
        "externaldberror": "มีข้อผิดพลาดของฐานข้อมูลในการพิสูจน์ตัวจริง หรือคุณไม่ได้รับอนุญาตให้ปรับบัญชีภายนอกของคุณ",
        "login": "ล็อกอิน",
        "nav-login-createaccount": "ล็อกอิน / สร้างบัญชี",
-       "loginprompt": "ต้องเปิดใช้คุกกี้ก่อนจะล็อกอินเข้าสู่ {{SITENAME}}",
        "userlogin": "ล็อกอิน / สร้างบัญชี",
        "userloginnocreate": "ล็อกอิน",
        "logout": "ล็อกเอาต์",
        "watchlistedit-raw-done": "รายการเฝ้าดูของคุณได้ปรับแล้ว",
        "watchlistedit-raw-added": "$1 ชื่อเรื่องได้ถูกเพิ่มเข้าไป:",
        "watchlistedit-raw-removed": "$1 ชื่อเรื่องได้ถูกนำออกไป:",
+       "watchlistedit-clear-title": "ล้างรายการเฝ้าดู",
        "watchlistedit-clear-legend": "ล้างรายการเฝ้าดู",
+       "watchlistedit-clear-explain": "ชื่อเรื่องทั้งหมดจะถูกนำออกจากรายการเฝ้าดูของคุณ",
+       "watchlistedit-clear-titles": "ชื่อเรื่อง:",
+       "watchlistedit-clear-submit": "ล้างรายการเฝ้าดู (เป็นการถาวร!)",
+       "watchlistedit-clear-done": "ล้างรายการเฝ้าดูของคุณแล้ว",
+       "watchlistedit-clear-removed": "$1 ชื่อเรื่องถูกนำออก:",
+       "watchlistedit-too-many": "มีหน้ามากเกินไปที่จะแสดงผลที่นี่",
        "watchlisttools-clear": "ล้างรายการเฝ้าดู",
        "watchlisttools-view": "ดูการเปลี่ยนแปลงที่เกี่ยวข้อง",
        "watchlisttools-edit": "ดูและแก้ไขรายการเฝ้าดู",
index 5b9b74a..d8d1b2d 100644 (file)
        "talkpagelinktext": "Mesaj",
        "specialpage": "Özel sayfa",
        "personaltools": "Kişisel araçlar",
-       "postcomment": "Yeni bölüm",
        "articlepage": "İçerik sayfasını gör",
        "talk": "Tartışma",
        "views": "Görünümler",
        "externaldberror": "Ya doğrulama veritabanı hatası var ya da kullanıcı hesabınızı güncellemeye yetkiniz yok.",
        "login": "Oturum aç",
        "nav-login-createaccount": "Oturum aç / hesap oluştur",
-       "loginprompt": "{{SITENAME}} sitesinde oturum açabilmek için çerezleri etkinleştirmeniz gerekmektedir.",
        "userlogin": "Oturum aç / hesap oluştur",
        "userloginnocreate": "Giriş yap",
        "logout": "Oturumu kapat",
        "resetpass-submit-cancel": "İptal",
        "resetpass-wrong-oldpass": "Geçersiz geçici veya güncel şifre.\nŞifrenizi zaten başarıyla değiştirdiniz ya da yeni bir geçici şifre istediniz.",
        "resetpass-recycled": "Lütfen parolanızı eski parolanızdan farklı olarak değiştirin.",
+       "resetpass-temp-emailed": "E-postayla gönderilmiş geçici kodla giriş yaptınız. Oturum açmayı tamamlamak için yeni bir şifre belirlemeniz gerekiyor:",
        "resetpass-temp-password": "Geçici parola:",
        "resetpass-abort-generic": "Parola değişikliği bir uzantı tarafından iptal edildi.",
        "resetpass-expired": "Parolanızın süresi bitti. Lütfen, giriş için yeni bir parola oluşturun.",
        "resetpass-expired-soft": "Parolanızın süresi bitti ve değiştirilmesi gerekiyor. Lütfen, yeni bir parola seçin veya daha sonra oluşturmak için \"{{int:resetpass-submit-cancel}}\" butonuna tıklayın.",
+       "resetpass-validity-soft": "Parolanız geçerli değiş: $1\n\nLütfen yeni bir şifre belirleyin veya daha sonra sıfırlamak için \"{{int:resetpass-submit-cancel}}\" bağlantısını tıklayın.",
        "passwordreset": "Parola sıfırlama",
        "passwordreset-text-one": "Parolanızı sıfırlamak için bu formu doldurun.",
        "passwordreset-text-many": "{{PLURAL:$1|E-posta ile geçici bir parola almak için alanlardan birini doldurun.}}",
        "revdelete-show-file-confirm": "\"<nowiki>$1</nowiki>\" dosyasının $2 $3 tarihli silinmiş bir revizyonunu görmek istediğinize emin misiniz?",
        "revdelete-show-file-submit": "Evet",
        "logdelete-selected": "{{PLURAL:$1|Seçili kayıt olayı|Seçili kayıt olayları}}:",
+       "revdelete-text-text": "Silinen sürümler sayfa geçmişinde yer almaya devam edecek ancak okuyucular tarafından içeriklerine erişilemeyecektir.",
+       "revdelete-text-file": "Silinen dosya sürümleri dosya geçmişinde yer almaya devam edecek ancak okuyucular tarafından içerik bölümlerine erişilemeyecektir.",
        "revdelete-confirm": "Lütfen, bunu yapmak istediğinizi , sonuçlarını anladığınızı, ve bunu [[{{MediaWiki:Policy-url}}|ilkelere]] göre yapıyor olduğunuzu onaylayın.",
        "revdelete-suppress-text": "Saklama '''sadece''' aşağıdaki durumlarda kullanılmalıdır:\n* Muhtemel iftira niteliğindeki bilgi\n* Uygunsuz kişisel bilgi\n*: ''ev adresleri ve telefon numaraları, sosyal güvenlik numaraları, vs.''",
        "revdelete-legend": "Görünürlük kısıtlamaları ayarla",
        "license-nopreview": "(Önizleme etkin değil)",
        "upload_source_url": " (geçerli, herkesin ulaşabileceği bir URL)",
        "upload_source_file": " (bilgisayarınızdaki bir dosya)",
+       "listfiles-delete": "sil",
        "listfiles-summary": "Bu özel sayfa yüklenen tüm dosyaları gösterir.",
        "listfiles_search_for": "Medya adı ara:",
        "imgfile": "dosya",
        "filedelete-maintenance": "Dosyaların silinmesi ve geri getirilmesi bakım süresince geçici olarak devre dışı bırakıldı.",
        "filedelete-maintenance-title": "Dosya silinemiyor",
        "mimesearch": "MIME araması",
-       "mimesearch-summary": "Bu sayfa, MIME türü dosyaların süzülmesini sağlar. Girdi: içeriktürü/alttürü, e.g. <code>resim/jpeg</code>.",
+       "mimesearch-summary": "Bu sayfa, dosyaların MIME türlerine göre filtrelenmesini sağlar. Girdi: içerik_türü/alt_tür veya içerik_türü/*, örn. <code>image/jpeg</code>.",
        "mimetype": "MIME türü:",
        "download": "yükle",
        "unwatchedpages": "İzlenmeyen sayfalar",
        "pageswithprop-prophidden-binary": "ikili özellik değeri gizlendi ($1)",
        "doubleredirects": "Çift yönlendirmeler",
        "doubleredirectstext": "Bu sayfa diğer yönlendirme sayfalarına yönlendirme yapan sayfaları listeler.\nHer satırın içerdiği bağlantılar; birinci ve ikinci yönlendirme, ayrıca ikinci yönlendirmenin hedefi, ki bu genelde birinci yönlendirmenin göstermesi gereken \"gerçek\" hedef sayfasıdır.\n<del>Üstü çizili</del> girdiler çözülmüştür.",
-       "double-redirect-fixed-move": "[[$1]] taşındı, artık [[$2]] sayfasına yönlendiriyor",
+       "double-redirect-fixed-move": "[[$1]] taşındı.\nYönlendirme otomatik olarak güncellendi ve [[$2]] sayfasına yönlendirildi.",
        "double-redirect-fixed-maintenance": "[[$1]] - [[$2]] yapılan çift yönlendirme düzeltiliyor.",
        "double-redirect-fixer": "Yönlendirme tamircisi",
        "brokenredirects": "Boş yönlendirmeler",
        "movenotallowedfile": "Sayfaları taşımaya izniniz yok.",
        "cant-move-user-page": "Kullanıcı sayfalarını taşımaya izniniz yok (altsayfalardan başka).",
        "cant-move-to-user-page": "Bir sayfayı, bir kullanıcı sayfasına taşımaya izniniz yok (bir kullanıcı altsayfası dışında).",
+       "cant-move-category-page": "Kategori sayfalarını taşıma yetkiniz yok.",
        "cant-move-to-category-page": "Bir sayfayı, bir kategoriye taşımaya izniniz yok.",
        "newtitle": "Yeni isim",
        "move-watch": "Bu sayfayı izle",
        "expand_templates_remove_nowiki": "Sonuçlarda <nowiki> etiketlerini bastır",
        "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": "Önizleme",
+       "pagelang-language": "Dil",
+       "pagelang-use-default": "Varsayılan dili kullan",
+       "pagelang-select-lang": "Dil seçin",
+       "right-pagelang": "Sayfa dilini değiştir",
+       "action-pagelang": "sayfa dilini değiştir"
 }
index 8cc9001..0fa99e0 100644 (file)
        "talkpagelinktext": "Бәхәс",
        "specialpage": "Махсус бит",
        "personaltools": "Шәхси кораллар",
-       "postcomment": "Яңа бүлек",
        "articlepage": "Мәкаләне карау",
        "talk": "Бәхәс",
        "views": "Караулар",
        "externaldberror": "Тышкы мәгълүмат базасы ярдәмендә аутентификация үткәндә хата чыкты, яисә тышкы хисап язмагызга үзгәрешләр кертү хокукыгыз юк.",
        "login": "Керү",
        "nav-login-createaccount": "Керү / теркәлү",
-       "loginprompt": "{{SITENAME}} проектына керү өчен «cookies» рөхсәт ителгән булырга тиеш.",
        "userlogin": "Керү / теркәлү",
        "userloginnocreate": "Керү",
        "logout": "Чыгу",
        "newimages": "Яңа сүрәтләр җыелмасы",
        "newimages-legend": "Фильтр",
        "ilsubmit": "Эзләү",
+       "hours": "{{PLURAL:$1|$1 cәгать|$1 cәгать}}",
+       "hours-ago": "$1 cәгать элек",
+       "minutes-ago": "$1 минут элек",
        "bad_image_list": "Киләчәк рәвеш кирәк:\n\nИсемлек кисәкләре генә (* символыннан башланучы юллар) саналырлар.\nЮлның беренче сылтамасы куйма өчен тыелган рәсемгә сылтама булырга тиеш.\nШул ук юлның киләчәк сылтамалары чыгармалар, рәсемгә тыелмаган битләре, саналырлар.",
        "metadata": "Мета мәгълүматлар",
        "metadata-help": "Бу файлда гадәттә санлы камера яки сканер тарафыннан өстәлгән мәгълүмат бар. Әгәр бу файл төзү вакытыннан соң үзгәртелгән булса, аның кайбер параметрлары дөрес булмаска мөмкин.",
index b3a08bc..5940869 100644 (file)
@@ -50,7 +50,7 @@
                        "Calak"
                ]
        },
-       "tog-underline": "Підкреслювати посилання:\nПідкреслювання посилань:",
+       "tog-underline": "Підкреслювання посилань:",
        "tog-hideminor": "Приховати незначні редагування у списку останніх змін",
        "tog-hidepatrolled": "Приховувати патрульовані редагування у списку нових редагувань",
        "tog-newpageshidepatrolled": "Приховувати патрульовані сторінки у списку нових сторінок",
        "talkpagelinktext": "обговорення",
        "specialpage": "Спеціальна сторінка",
        "personaltools": "Особисті інструменти",
-       "postcomment": "Новий розділ",
        "articlepage": "Переглянути статтю",
        "talk": "Обговорення",
        "views": "Перегляди",
        "unexpected": "Неочікуване значення: «$1»=«$2».",
        "formerror": "Помилка: неможливо передати дані форми",
        "badarticleerror": "Ця дія не може бути виконана на цій сторінці.",
-       "cannotdelete": "Неможливо вилучити сторінку або файл \"$1\".\nМожливо, її (його) вже вилучив хтось інший.",
+       "cannotdelete": "Неможливо вилучити сторінку або файл «$1».\nМожливо, її (його) вже вилучив хтось інший.",
        "cannotdelete-title": "Не вдається видалити сторінку «$1»",
        "delete-hook-aborted": "Вилучення було скасовано процедурою-перехоплювачем. \nНіяких поясненень надано не було.",
        "no-null-revision": "Не вдалося створити нульову версію сторінки «$1»",
        "namespaceprotected": "У вас нема дозволу редагувати сторінки в просторі назв «$1».",
        "customcssprotected": "У вас немає прав на редагування цієї CSS-сторінки, так як вона містить особисті налаштування іншого користувача.",
        "customjsprotected": "У вас немає дозволу на редагування цієї JavaScript-сторінки, так як вона містить особисті налаштування іншого користувача.",
-       "mycustomcssprotected": "У Ð²ас немає прав для редагування цієї CSS сторінки.",
+       "mycustomcssprotected": "У Ð\92ас немає прав для редагування цієї CSS сторінки.",
        "mycustomjsprotected": "Ви не маєте дозволу для редагування цієї сторінки JavaScript.",
        "myprivateinfoprotected": "У Вас немає дозволу на редагування своєї приватної інформації.",
        "mypreferencesprotected": "У Вас немає дозволу на редагування своїх налаштувань.",
        "externaldberror": "Сталася помилка при автентифікації за допомогою зовнішньої бази даних, або у вас недостатньо прав для внесення змін до свого зовнішнього облікового запису.",
        "login": "Вхід до системи",
        "nav-login-createaccount": "Вхід / реєстрація",
-       "loginprompt": "Ви повинні активувати куки (cookies) для входу до {{GRAMMAR:genitive|{{SITENAME}}}}.",
        "userlogin": "Вхід / реєстрація",
        "userloginnocreate": "Увійти",
        "logout": "Вихід із системи",
        "currentrev": "Поточна версія",
        "currentrev-asof": "Поточна версія на $1",
        "revisionasof": "Версія за $1",
-       "revision-info": "Версія від $1; $2",
+       "revision-info": "Версія від $1, створена {{GENDER:$6|$2}}$7",
        "previousrevision": "← Попередня версія",
        "nextrevision": "Новіша версія →",
        "currentrevisionlink": "Поточна версія",
        "revdelete-text-text": "Видалені версії будуть як і раніше видно в історії сторінки, але їх частини вмісту будуть доступні для учасників.",
        "revdelete-text-file": "Видалені версії файлу будуть як і раніше видно в історії сторінки, але їх частини вмісту будуть доступні для учасників.",
        "logdelete-text": "Видалені події в журналі будуть як і раніше видно в журналах, але частини їх вмісту будуть доступні для учасників.",
-       "revdelete-text-others": "Інші адміністратори на {{grammar:genitive|{{SITENAME}}}} як і раніше буде мати можливість доступу до прихованого вмісту і зможуть відновити його знову через цей же інтерфейс, якщо не встановлено додаткові обмеження.",
+       "revdelete-text-others": "Інші адміністратори на як і раніше будуть мати можливість доступу до прихованого вмісту і зможуть відновити його, якщо не встановлено додаткові обмеження.",
        "revdelete-confirm": "Будь ласка, підтвердить, що ви справді бажаєте це здійснити, усвідомлюєте наслідки та робите це згідно з [[{{MediaWiki:Policy-url}}|правилами]].",
        "revdelete-suppress-text": "Приховування може відбуватися '''лише''' в таких випадках:\n* Потенційно наклепницькі відомості\n* Недоречна особиста інформація\n*: ''домашні адреси, номери телефонів, номер паспорта тощо.''",
        "revdelete-legend": "Встановити обмеження видимості",
        "mergehistory-empty": "Не знайдені редагування для об'єднання.",
        "mergehistory-success": "$3 {{PLURAL:$3|редагування|редагування|редагувань}} з [[:$1]] успішно перенесені до [[:$2]].",
        "mergehistory-fail": "Не вдалося здійснити об'єднання історій сторінок, будь ласка, перевірте параметри сторінки й часу.",
+       "mergehistory-fail-toobig": "Не вдалося виконати злиття історії оскільки буде перейменовано більше, ніж ліміт у $1 {{PLURAL:$1|версію|версії|версій}}.",
        "mergehistory-no-source": "Вихідна сторінка «$1» не існує.",
        "mergehistory-no-destination": "Цільова сторінка «$1» не існує.",
        "mergehistory-invalid-source": "Джерело повинне мати правильний заголовок.",
        "userrights": "Керування правами користувачів",
        "userrights-lookup-user": "Керування групами користувача",
        "userrights-user-editname": "Введіть ім'я користувача:",
-       "editusergroup": "Редагувати групи користувача",
+       "editusergroup": "Редагувати групи користувачів",
        "editinguser": "Зміна прав користувача '''[[User:$1|$1]]''' $2",
-       "userrights-editusergroup": "Змінити групи користувача",
+       "userrights-editusergroup": "Змінити групи користувачів",
        "saveusergroups": "Зберегти групи користувача",
        "userrights-groupsmember": "Член груп:",
        "userrights-groupsmember-auto": "Неявний член:",
        "right-deletedtext": "перегляд вилученого тексту та змін між вилученими версіями",
        "right-browsearchive": "Пошук вилучених сторінок",
        "right-undelete": "Відновлення сторінок",
-       "right-suppressrevision": "Перегляд і відновлення версій, прихованих від адміністраторів",
+       "right-suppressrevision": "Перегляд, приховання та відновлення конкретних змін сторінок від будь-якого користувача",
+       "right-viewsuppressed": "Перегляд змін, приховаих від усіх користувачів",
        "right-suppressionlog": "Перегляд приватних журналів",
        "right-block": "Заборона редагувань для інших дописувачів",
        "right-blockemail": "Блокування користувачам надсилання електронної пошти",
        "largefileserver": "Розмір файлу більший за максимальнодозволений.",
        "emptyfile": "Завантажений вами файл ймовірно порожній. Можливо, це сталося через помилку при введенні імені файлу. Будь-ласка, перевірте, чи справді ви бажаєте звантажити цей файл.",
        "windows-nonascii-filename": "Ця вікі не підтримує імена файлів зі спеціальними символами.",
-       "fileexists": "Файл з такою назвою вже існує.\nБудь ласка, перевірте <strong>[[:$1]]</strong>, якщо ви не впевнені, чи хочете замінити його.\n[[$1|thumb]]",
+       "fileexists": "Файл з такою назвою вже існує.\nБудь ласка, перевірте <strong>[[:$1]]</strong>, якщо {{GENDER:|ви}} не впевнені, чи хочете замінити його.\n[[$1|thumb]]",
        "filepageexists": "Сторінка опису цього файлу вже створена як <strong>[[:$1]]</strong>, але файлу з такою назвою немає. Уведений опис не з'явиться на сторінці опису зображення. Щоб додати новий опис, вам доведеться змінити його вручну. [[$1|thumb]]",
-       "fileexists-extension": "Ð\86Ñ\81нÑ\83Ñ\94 Ñ\84айл Ð·Ñ\96 Ñ\81Ñ\85ожоÑ\8e Ð½Ð°Ð·Ð²Ð¾Ñ\8e: [[$2|thumb]]\n* Ð\9dазва Ð·Ð°Ð²Ð°Ð½Ñ\82аженого Ñ\84айлÑ\83: <strong>[[:$1]]</strong>\n* Ð\9dазва Ñ\96Ñ\81нÑ\83Ñ\8eÑ\87ого Ñ\84айлÑ\83: <strong>[[:$2]]</strong>\nÐ\91Ñ\83дÑ\8cÑ\82е Ð»Ð°Ñ\81кавÑ\96, Ð²Ð¸Ð±ÐµÑ\80Ñ\96Ñ\82Ñ\8c Ñ\96нÑ\88Ñ\83 Ð½Ð°Ð·Ð²Ñ\83.",
+       "fileexists-extension": "Ð\86Ñ\81нÑ\83Ñ\94 Ñ\84айл Ð·Ñ\96 Ñ\81Ñ\85ожоÑ\8e Ð½Ð°Ð·Ð²Ð¾Ñ\8e: [[$2|thumb]]\n* Ð\9dазва Ð·Ð°Ð²Ð°Ð½Ñ\82аженого Ñ\84айлÑ\83: <strong>[[:$1]]</strong>\n* Ð\9dазва Ñ\96Ñ\81нÑ\83Ñ\8eÑ\87ого Ñ\84айлÑ\83: <strong>[[:$2]]</strong>\nÐ\9cожливо, Ð²Ð¸ Ñ\85оÑ\87еÑ\82е Ð¾Ð±Ñ\80аÑ\82и Ð½Ð°Ð·Ð²Ñ\83, Ñ\89о Ð±Ñ\83де Ð±Ñ\96лÑ\8cÑ\88е Ð²Ñ\96дÑ\80Ñ\96знÑ\8fÑ\82иÑ\81Ñ\8f?",
        "fileexists-thumbnail-yes": "Можливо, файл є зменшеною копією (мініатюрою). [[$1|thumb]]\nБудь ласка, перевірте файл <strong>[[:$1]]</strong>.\nЯкщо вказаний файл є тим самим зображенням, не варто окремо завантажувати його зменшену копію.",
        "file-thumbnail-no": "Назва файлу починається на <strong>$1</strong>.\nМожливо, це зменшена копія зображення ''(мініатюра)''.\nЯкщо у вас є це зображення в повному розмірі, завантажте його, інакше змініть назву файлу.",
        "fileexists-forbidden": "Файл з такою назвою вже існує і не може бути перезаписаний.\nЯкщо ви все одно хочете завантажити цей файл, будь ласка, поверніться назад і оберіть іншу назву.\n[[File:$1|thumb|center|$1]]",
        "license": "Ліцензування:",
        "license-header": "Ліцензування",
        "nolicense": "Відсутнє",
+       "licenses-edit": "Редагувати параметри ліцензії",
        "license-nopreview": "(Попередній перегляд недоступний)",
        "upload_source_url": " (вірна, публічно доступна інтернет-адреса)",
        "upload_source_file": " (файл на вашому комп'ютері)",
+       "listfiles-delete": "видалити",
        "listfiles-summary": "Ця спеціальна сторінка показує всі завантажені файли.",
        "listfiles_search_for": "Пошук по назві зображення:",
        "imgfile": "файл",
        "filedelete-maintenance": "Вилучення та відновлення файлів відімкнене на час технічних робіт.",
        "filedelete-maintenance-title": "Не вдається видалити файл",
        "mimesearch": "Пошук по MIME",
-       "mimesearch-summary": "Ця сторінка дозволяє вибирати файли за їх MIME-типом. Формат вводу: тип_вмісту/підтип, наприклад <code>image/jpeg</code>.",
+       "mimesearch-summary": "Ця сторінка дозволяє вибирати файли за їх MIME-типом. Формат вводу: тип_вмісту/підтип або тип_вмісту/* тощо, наприклад <code>image/jpeg</code>.",
        "mimetype": "MIME-тип:",
        "download": "завантажити",
        "unwatchedpages": "Сторінки, за якими ніхто не спостерігає",
        "wantedpages-badtitle": "Неправильний заголовок у результатах запиту: $1",
        "wantedfiles": "Необхідні файли",
        "wantedfiletext-cat": "Наступні файли використовують, але вони не існують. У цей список можуть помилково потрапити файли, що знаходяться на зовнішніх сховищах. Такі хибні моменти помічаються <del>перекреслюванням</del>. Крім того, сторінки, що використовують неіснуючі файли, перелічені в [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Наступні файли використовуються, але не існують. Крім того, сторінки, що посилаються на фійли, які не існують, перераховані у [[:$1]].",
        "wantedfiletext-nocat": "Наступні файли використовують, але вони не існують. У цей список можуть помилково потрапити файли, що знаходяться на зовнішніх сховищах. Такі хибні моменти помічаються <del>перекреслюванням</del>.",
+       "wantedfiletext-nocat-noforeign": "Наступні файли використовуються, але не існують.",
        "wantedtemplates": "Необхідні шаблони",
        "mostlinked": "Сторінки, на які найбільше посилань",
        "mostlinkedcategories": "Найбільші категорії",
-       "mostlinkedtemplates": "Ð\9dайÑ\83живанÑ\96Ñ\88Ñ\96 Ñ\88аблони",
+       "mostlinkedtemplates": "Ð\9dайÑ\87аÑ\81Ñ\82Ñ\96Ñ\88е Ð²ÐºÐ»Ñ\8eÑ\87енÑ\96 Ñ\81Ñ\82оÑ\80Ñ\96нки",
        "mostcategories": "Статті з найбільшою кількістю категорій",
        "mostimages": "Найуживаніші зображення",
        "mostinterwikis": "Сторінки з найбільшою кількістю інтервікі-посилань",
        "watchlistedit-clear-titles": "Сторінки:",
        "watchlistedit-clear-submit": "Очистити список спостереження (це безповоротньо!)",
        "watchlistedit-clear-done": "Ваш список спостереження було очищено.",
+       "watchlistedit-clear-removed": "Було видалено {{PLURAL:$1|1 запис|$1 записів|$1 записи}}:",
        "watchlistedit-too-many": "Забагато сторінок для відображення тут.",
        "watchlisttools-clear": "Очистити список спостереження",
        "watchlisttools-view": "Зміни на сторінках зі списку",
        "timezone-utc": "UTC",
        "unknown_extension_tag": "Невідомий тег доповнення «$1»",
        "duplicate-defaultsort": "Увага. Ключ сортування «$2» перекриває попередній ключ сортування «$1».",
+       "duplicate-displaytitle": "<strong>Увага:</strong> Відображений заголовок \"$2\" заміщує раніше відображений заголовок \"$1\".",
        "version": "Версія MediaWiki",
        "version-extensions": "Установлені розширення",
-       "version-skins": "Ð\9eформлення",
+       "version-skins": "Ð\92Ñ\81Ñ\82ановленÑ\96 Ñ\82еми Ð¾формлення",
        "version-specialpages": "Спеціальні сторінки",
        "version-parserhooks": "Перехоплювачі синтаксичного аналізатора",
        "version-variables": "Змінні",
        "version-hook-name": "Ім'я перехоплювача",
        "version-hook-subscribedby": "Підписаний на",
        "version-version": "($1)",
+       "version-no-ext-name": "[без назви]",
        "version-svn-revision": "(r$2)",
        "version-license": "Ліцензія MediaWik",
        "version-ext-license": "Ліцензія",
        "version-ext-colheader-name": "Розширення",
+       "version-skin-colheader-name": "Тема оформлення",
        "version-ext-colheader-version": "Версія",
        "version-ext-colheader-license": "Ліцензія",
        "version-ext-colheader-description": "Опис",
        "expand_templates_remove_nowiki": "Ігнорувати теги <nowiki> в результаті",
        "expand_templates_generate_xml": "Показати дерево аналізу XML",
        "expand_templates_generate_rawhtml": "Показати сирий HTML",
-       "expand_templates_preview": "Попередній перегляд"
+       "expand_templates_preview": "Попередній перегляд",
+       "pagelanguage": "Вибір мови сторінки",
+       "pagelang-name": "Сторінка",
+       "pagelang-language": "Мова",
+       "pagelang-use-default": "Мова за замовчуванням",
+       "pagelang-select-lang": "Оберіть мову",
+       "right-pagelang": "Змінити мову сторінки",
+       "action-pagelang": "змінити мову сторінки",
+       "log-name-pagelang": "Журнал змін мови",
+       "log-description-pagelang": "Це журнал змін мови сторінок.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|змінив|змінила}} мову сторінки для $3 з $4 на $5."
 }
index ee88984..6bba637 100644 (file)
@@ -44,7 +44,7 @@
        "tog-watchdeletion": "Tự động theo dõi các trang và tập tin tôi xóa",
        "tog-minordefault": "Mặc định đánh dấu tất cả sửa đổi của tôi là sửa đổi nhỏ",
        "tog-previewontop": "Hiển thị phần xem trước nằm trên hộp sửa đổi",
-       "tog-previewonfirst": "Hiện xem trước tại lần sửa đầu tiên",
+       "tog-previewonfirst": "Hiện xem trước tại ngay khi bắt đầu sửa đổi",
        "tog-enotifwatchlistpages": "Gửi thư cho tôi khi có thay đổi tại trang hoặc tập tin tôi theo dõi",
        "tog-enotifusertalkpages": "Gửi thư cho tôi khi có thay đổi tại trang thảo luận của tôi",
        "tog-enotifminoredits": "Gửi thư cho tôi cả những thay đổi nhỏ trong trang và tập tin",
        "talkpagelinktext": "Thảo luận",
        "specialpage": "Trang đặc biệt",
        "personaltools": "Công cụ cá nhân",
-       "postcomment": "Đề mục mới",
        "articlepage": "Xem trang nội dung",
        "talk": "Thảo luận",
        "views": "Các hiển thị",
        "externaldberror": "Có lỗi khi xác nhận cơ sở dữ liệu bên ngoài hoặc bạn không được phép cập nhật tài khoản bên ngoài.",
        "login": "Đăng nhập",
        "nav-login-createaccount": "Đăng nhập / Mở tài khoản",
-       "loginprompt": "Bạn cần bật cookie để đăng nhập vào {{SITENAME}}.",
        "userlogin": "Đăng nhập / Mở tài khoản",
        "userloginnocreate": "Đăng nhập",
        "logout": "Đăng xuất",
        "noemailprefs": "Hãy ghi một địa chỉ thư điện tử trong tùy chọn cá nhân để có thể sử dụng tính năng này.",
        "emailconfirmlink": "Xác nhận địa chỉ thư điện tử",
        "invalidemailaddress": "Địa chỉ thư điện tử không được chấp nhận vì định dạng thư có vẻ sai.\nHãy nhập một địa chỉ có định dạng đúng hoặc bỏ trống ô đó.",
-       "cannotchangeemail": "Không có thể thay đổi địa chỉ thư điện tử của các tài khoản trên wiki này.",
+       "cannotchangeemail": "Không thể thay đổi địa chỉ thư điện tử của các tài khoản trên wiki này.",
        "emaildisabled": "Website này không thể gửi thư điện tử.",
        "accountcreated": "Mở tài khoản thành công",
        "accountcreatedtext": "Tài khoản thành viên cho [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|thảo luận]]) đã được mở.",
        "revdelete-text-text": "Các phiên bản đã xóa sẽ tiếp tục xuất hiện trong lịch sử trang, nhưng một số phần của nội dung sẽ bị ẩn khỏi công chúng.",
        "revdelete-text-file": "Các phiên bản tập tin đã xóa sẽ tiếp tục xuất hiện trong lịch sử tập tin, nhưng một số phần của nội dung sẽ bị ẩn khỏi công chúng.",
        "logdelete-text": "Các sự kiện đã xóa sẽ tiếp tục xuất hiện trong nhật trình, nhưng một số phần của nội dung sẽ bị ẩn khỏi công chúng.",
-       "revdelete-text-others": "Các bảo quản viên khác trên {{SITENAME}} sẽ vẫn có quyền truy cập nội dung ẩn và có thể phục hồi nó qua cùng giao diện này, trừ khi có hạn chế bổ sung.",
+       "revdelete-text-others": "Các bảo quản viên khác sẽ vẫn có quyền truy cập nội dung ẩn và phục hồi nó qua cùng giao diện này, trừ khi có hạn chế bổ sung.",
        "revdelete-confirm": "Xin hãy xác nhận rằng bạn có ý định xóa, nhận biết tầm quan trọng của việc này, và việc xóa tuân theo [[{{MediaWiki:Policy-url}}|quy định]].",
        "revdelete-suppress-text": "Việc ẩn giấu '''chỉ''' nên dùng trong các trường hợp sau:\n* Thông tin có thể phỉ báng\n* Thông tin cá nhân không thích hợp\n*: ''địa chỉ nhà và số điện thoại, số chứng minh nhân dân, số an sinh xã hội, v.v.''",
        "revdelete-legend": "Thiết lập hạn chế khả kiến",
        "prefs-custom-css": "sửa CSS",
        "prefs-custom-js": "sửa JS",
        "prefs-common-css-js": "CSS/JS chung cho mọi giao diện:",
-       "prefs-reset-intro": "Có thể mặc định lại toàn bộ tùy chọn dùng trang này.\nKhông có thể lùi lại tác động này.",
+       "prefs-reset-intro": "Có thể mặc định lại toàn bộ tùy chọn dùng trang này. Điều này không thể hoàn tác.",
        "prefs-emailconfirm-label": "Xác nhận thư điện tử:",
        "youremail": "Thư điện tử:",
        "username": "{{GENDER:$1}}Tên người dùng:",
        "right-deletedtext": "Xem văn bản đã xóa và các thay đổi giữa phiên bản đã xóa",
        "right-browsearchive": "Tìm kiếm trang đã bị xóa",
        "right-undelete": "Phục hồi trang",
-       "right-suppressrevision": "Xem và phục hồi phiên bản mà bảo quản viên không thấy",
+       "right-suppressrevision": "Xem và hiện/ẩn các phiên bản trang cụ thể đối với mọi người dùng khác",
+       "right-viewsuppressed": "Xem các phiên bản được ẩn mà mọi người khác không thấy được",
        "right-suppressionlog": "Xem nhật trình riêng tư",
        "right-block": "Cấm thành viên khác sửa đổi",
        "right-blockemail": "Cấm người dùng gửi thư điện tử",
        "enhancedrc-history": "lịch sử",
        "recentchanges": "Thay đổi gần đây",
        "recentchanges-legend": "Tùy chọn thay đổi gần đây",
-       "recentchanges-summary": "Xem các thay đổi gần đây nhất tại wiki trên trang này.",
+       "recentchanges-summary": "Xem các thay đổi gần đây nhất trên wiki này tại đây.",
        "recentchanges-noresult": "Không có thay đổi trong khoảng thời gian phù hợp với các tiêu chí này.",
        "recentchanges-feed-description": "Theo dõi các thay đổi gần đây nhất của wiki dùng nguồn cấp dữ liệu này.",
        "recentchanges-label-newpage": "Bản sửa này tạo ra trang mới",
        "ignorewarnings": "Bỏ qua cảnh báo",
        "minlength1": "Tên tập tin phải có ít nhất một ký tự.",
        "illegalfilename": "Tên tập tin “$1” có chứa ký tự không được phép dùng cho tựa trang. Xin hãy đổi tên và tải lên lại.",
-       "filename-toolong": "Tên tập tin không có thể dài quá 240 byte.",
+       "filename-toolong": "Tên tập tin không thể dài quá 240 byte.",
        "badfilename": "Tên tập tin đã được đổi thành “$1”.",
        "filetype-mime-mismatch": "Phần mở rộng của tập tin (“.$1”) không phù hợp kiểu MIME được nhận ra ($2).",
        "filetype-badmime": "Không thể tải lên các tập tin có kiểu MIME “$1”.",
        "license": "Giấy phép:",
        "license-header": "Giấy phép",
        "nolicense": "chưa chọn",
+       "licenses-edit": "Sửa các giấy phép",
        "license-nopreview": "(Không xem trước được)",
        "upload_source_url": " (địa chỉ URL đúng, có thể truy cập)",
        "upload_source_file": " (tập tin trên máy của bạn)",
+       "listfiles-delete": "xóa",
        "listfiles-summary": "Trang đặc biệt này liệt kê các tập tin được tải lên.",
        "listfiles_search_for": "Tìm kiếm theo tên tập tin:",
        "imgfile": "tập tin",
        "shared-repo-from": "tại $1",
        "shared-repo": "kho lưu trữ dùng chung",
        "filepage.css": "/* Mã CSS tại đây sẽ ảnh hướng đến trang miêu tả tập tin, cũng như các wiki khách bên ngoài dựa trên wiki này */",
-       "upload-disallowed-here": "Bạn không có thể ghi đè lên tập tin này.",
+       "upload-disallowed-here": "Bạn không thể ghi đè lên tập tin này.",
        "filerevert": "Lùi lại phiên bản của $1",
        "filerevert-legend": "Lùi lại tập tin",
        "filerevert-intro": "Bạn đang lùi '''[[Media:$1|$1]]''' về [$4 phiên bản lúc $3, $2].",
        "wantedpages-badtitle": "Tiêu đề không hợp lệ trong tập kết quả: $1",
        "wantedfiles": "Tập tin cần thiết",
        "wantedfiletext-cat": "Các tập tin sau được nhúng nhưng không tồn tại. Các tập tin từ kho dùng chung có thể được liệt kê trong khi tồn tại; các trường hợp này được <del>gạch bỏ</del>. Ngoài ra, các trang nhúng tập tin không tồn tại được liệt kê tại [[:$1]].",
+       "wantedfiletext-cat-noforeign": "Các tập tin bên dưới được sử dụng nhưng không tồn tại. Các trang nhúng những tập tin không tồn tại cũng được xếp trong [[:$1]].",
        "wantedfiletext-nocat": "Các tập tin sau được nhúng nhưng không tồn tại. Các tập tin từ kho dùng chung có thể được liệt kê trong khi tồn tại; các trường hợp này được <del>gạch bỏ</del>.",
+       "wantedfiletext-nocat-noforeign": "Các tập tin bên dưới được sử dụng nhưng không tồn tại.",
        "wantedtemplates": "Bản mẫu cần viết nhất",
        "mostlinked": "Trang được liên kết đến nhiều nhất",
        "mostlinkedcategories": "Thể loại có nhiều trang nhất",
        "imported-log-entries": "Đã nhập {{PLURAL:$1|mục nhật trình|$1 mục nhật trình}}.",
        "importfailed": "Không nhập được: $1",
        "importunknownsource": "Không hiểu nguồn trang để nhập vào",
-       "importcantopen": "Không có thể mở tập tin để nhập vào",
+       "importcantopen": "Không thể mở tập tin để nhập vào",
        "importbadinterwiki": "Liên kết liên wiki sai",
        "importsuccess": "Nhập thành công!",
        "importnosources": "Không có nguồn nhập giữa wiki và việc nhập lịch sử bị tắt.",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|thảo luận]])",
        "unknown_extension_tag": "Không hiểu thẻ mở rộng “$1”",
        "duplicate-defaultsort": "Cảnh báo: Từ khóa xếp mặc định “$2” ghi đè từ khóa trước, “$1”.",
+       "duplicate-displaytitle": "<strong>Cảnh báo:</strong> Tên hiển thị “$2” ghi đè tên hiển thị “$1” bên trên.",
        "version": "Phiên bản",
        "version-extensions": "Các phần mở rộng được cài đặt",
        "version-skins": "Giao diện đã cài đặt",
index a9aaf52..62b2328 100644 (file)
@@ -12,7 +12,9 @@
                        "十弌",
                        "아라",
                        "Mywood",
-                       "Cwek"
+                       "Cwek",
+                       "Duolaimi",
+                       "Impersonator 1"
                ]
        },
        "tog-underline": "鏈接下橫線:",
        "talkpagelinktext": "討論",
        "specialpage": "特別頁",
        "personaltools": "私人家伙",
-       "postcomment": "新段",
        "articlepage": "望內容頁",
        "talk": "探讨",
        "views": "望",
        "viewyourtext": "你侬好望也好畀'''你侬编个'''复制到箇页:",
        "protectedinterface": "箇页为箇维基个软件提供界面文本,锁牢定防乱用。\n加改全部维基个译文,用[//translatewiki.net/ translatewiki.net],MediaWiki软件个本地化计划。",
        "editinginterface": "'''警告:''' 侬来里编写个页面是畀软件用个界面文本。箇页变化会影响各许人个界面样子。假使要畀全部维基翻译,用 [//translatewiki.net/wiki/Main_Page?setlang=zh-hans translatewiki.net],MediaWiki软件个本地化计划。",
-       "cascadeprotected": "箇只页面拨保护拉许,因为箇只页面拨下底已经标注“联锁保护”个{{PLURAL:$1|一只|多只}}被保护页面包含:\n$2",
+       "cascadeprotected": "箇只页面拨保护拉许,因为箇只页面拨下底已经标注“级联保护”个{{PLURAL:$1|一只|多只}}被保护页面包含:\n$2",
        "namespaceprotected": "侬无没编辑'''$1'''名字空间里向页面个权限。",
        "customcssprotected": "箇CSS页你呒处编,箇页有各许用户个私人设置。",
        "customjsprotected": "箇JavaScript页你呒处编,箇页有各许用户个私人设置。",
        "readonlywarning": "'''警告:数据库锁定垃许维护,侬箇歇弗好保存侬个修改。'''侬作兴希望先拿本段文字复制并保存到文本文件,等歇再修改。\n\n管理员有如下解释:$1",
        "protectedpagewarning": "'''警告:此页已经畀保护,只有拥有管理员权限个用户再好修改。'''\n最近个日志垃拉下底提供以便参考:",
        "semiprotectedpagewarning": "'''注意:''' 本页面畀锁定,仅限注册用户编辑。\n最近个日志垃拉下底提供以便参考:",
-       "cascadeprotectedwarning": "警告:本页已经畀保护,只有拥有管理员权限个用户再好修改,因为本页已畀下底眼连锁保护个{{PLURAL:$1|一只|多只}}页面所包含:",
+       "cascadeprotectedwarning": "警告:本页已经畀保护,只有拥有管理员权限个用户再好修改,因为本页已畀下底眼级联保护个{{PLURAL:$1|一只|多只}}页面所包含:",
        "titleprotectedwarning": "'''警告:本页面已畀锁定,需要[[Special:ListGroupRights|指定权限]]方可创建。'''\n最近个日志垃拉下底提供以便参考:",
        "templatesused": "箇页有{{PLURAL:$1|个模板}}:",
        "templatesusedpreview": "{{PLURAL:$1|只模板}}垃拉箇趟预览里向拨使用:",
        "prefixindex": "全部带前缀个页面",
        "shortpages": "短页面",
        "longpages": "长页面",
-       "protectedpages": "å·²保护页面",
-       "protectedtitles": "å·²保护个标题",
+       "protectedpages": "å\8f\97保护页面",
+       "protectedtitles": "å\8f\97保护个标题",
        "listusers": "用户列表",
        "listusers-creationsort": "照建個日子排",
        "newpages": "新页",
        "rollbackfailed": "恢复失败",
        "revertpage": "恢复[[Special:Contributions/$2|$2]] ([[User talk:$2|讲张]])个改动;恢复到[[User:$1|$1]]个上一版本",
        "protectlogpage": "保护日志",
-       "protectedarticle": "保护“[[$1]]”",
+       "protectedarticle": "保护“[[$1]]”",
        "modifiedarticleprotection": "“[[$1]]”个保护等级改好哉",
        "prot_1movedto2": "[[$1]]捅到[[$2]]",
        "protectcomment": "理由:",
        "protect-fallback": "需要“$1”个许可",
        "protect-level-autoconfirmed": "弗准新用戶搭還朆註冊個用戶",
        "protect-level-sysop": "只准管理員",
-       "protect-summary-cascade": "联锁",
+       "protect-summary-cascade": "级联",
        "protect-expiring": "终止于$1(UTC)",
-       "protect-cascade": "保护本页里向包含个页面(连锁保护)",
+       "protect-cascade": "保护本页里向包含个页面(级联保护)",
        "protect-cantedit": "侬呒此更改迭只页面个保护等级,因为侬呒没权限编辑渠。",
        "protect-othertime": "各許時間:",
        "protect-othertime-op": "各許時間",
index c7d6f91..33d03f5 100644 (file)
        "talkpagelinktext": "שמועס",
        "specialpage": "ספעציעלער בלאט",
        "personaltools": "פערזענלעכע געצייג",
-       "postcomment": "נייע אפטיילונג",
        "articlepage": "זען אינהאַלט בלאַט",
        "talk": "שמועס",
        "views": "קוקן",
        "externaldberror": "עס איז אדער פארגעקומען אן אויטענטיקאציע דאטנבאזע פעלער אדער איר זענט נישט ערמעגליכט צו דערהיינטיגן אייער דרויסנדיגע קאנטע.",
        "login": "אַרײַנלאָגירן",
        "nav-login-createaccount": "ארײַנלאָגירן / זיך אײַנשרײַבן",
-       "loginprompt": "איר מוסט ערלויבן קיכלעך (\"cookies\") אויף צו אַרײַנלאָגירן אינעם {{SITENAME}}.",
        "userlogin": "ארײַנלאָגירן / זיך אײַנשרײַבן",
        "userloginnocreate": "אַרײַנלאגירן",
        "logout": "אַרױסלאָגירן",
        "revdelete-text-text": "אויסגעמעקטע ווערסיעס וועלן נאך דערשיינען אין דער בלאט־היסטאריע, אבער טייל פון זייער אינהאלט וועט נישט זײַן צוגאנגבאר צום עולם.",
        "revdelete-text-file": "אויסגעמעקטע טעקע ווערסיעס וועלן נאך דערשיינען אין דער בלאט־היסטאריע, אבער טייל פון זייער אינהאלט וועט נישט זײַן צוגאנגבאר צום עולם.",
        "logdelete-text": "אויסגעמעקטע לאגביכער־געשעענישן וועלן נאך דערשיינען אינעם לאגבוך, אבער טייל פון זייער אינהאלט וועט נישט זײַן צוגאנגבאר צום עולם.",
-       "revdelete-text-others": "×\90× ×\93ערע ×¡×\99ס×\90פ×\9f ×\91×\99×\99 {{SITENAME}} ×\95×\95×¢×\9c×\9f × ×\90×\9a ×§×¢× ×¢×\9f ×¦×\95ק×\95×\9e×¢×\9f ×¦×\95×\9d ×\91×\90×\94×\90×\9c×\98×¢× ×¢×\9d ×\90×\99× ×\94×\90×\9c×\98 ×\90×\95×\9f ×§×¢× ×¢×\9f ×\90×\99×\9d ×¦×\95ר×\99קש×\98×¢×\9c×\9f ×\93×\95ר×\9b×\9f ×\96×¢×\9c×\91×\9f ×\90×\99×\99×\91ערפ×\9c×\90×\9a, סײַדן ווען מען שטעלט נאך באשרענקונגען.",
+       "revdelete-text-others": "×\90× ×\93ערע ×¡×\99ס×\90פ×\9f ×\95×\95×¢×\9c×\9f × ×\90×\9a ×§×¢× ×¢×\9f ×¦×\95ק×\95×\9e×¢×\9f ×¦×\95×\9d ×\91×\90×\94×\90×\9c×\98×¢× ×¢×\9d ×\90×\99× ×\94×\90×\9c×\98 ×\90×\95×\9f ×§×¢× ×¢×\9f ×\90×\99×\9d ×¦×\95ר×\99קש×\98×¢×\9c×\9f, סײַדן ווען מען שטעלט נאך באשרענקונגען.",
        "revdelete-confirm": "זייט אזוי גוט און באשטעטיקט אז דאס איז טאקע אייער כוונה, אז איר פארשטייט די קאנסעקווענצן, און אז איר טוט דאס לויט  [[{{MediaWiki:Policy-url}}|דער פאליסי]].",
        "revdelete-suppress-text": "אונטערדרוקן זאל בלויז גענוצט ווערן '''נאר''' אין די פאלגנדע פעלער:\n* אינפארמאציע וואס קען זיין מוציא שם רע\n* אויפדעקונג פון פריוואטקייט אינפארמאציע\n*: ''היים אדרעסן, טעלעפאן נומערן, נאציאנאלע אידענטיפיקאציע נומערן, א.א.וו.''",
        "revdelete-legend": "שטעלט ווייזונג באגרענעצונגען",
        "searchrelated": "פארבינדן",
        "searchall": "אלץ",
        "showingresults": "ווייזן ביז {{PLURAL:$1|רעזולטאט '''איינס'''|'''$1''' רעזולטאטן}} אנגעפאנגן פון נומער #'''$2''':",
+       "showingresultsinrange": "ווײַזן אונטן ביז {{PLURAL:$1|<strong>1</strong> רעזולטאט|<strong>$1</strong> רעזולטאטן}} אין גרייך #<strong>$2</strong> ביז #<strong>$3</strong>.",
        "showingresultsheader": "{{PLURAL:$5|רעזולטאַט '''$1''' פֿון '''$3'''| רעזולטאַטן '''$1 - $2''' פֿון '''$3'''}} פֿאַר '''$4'''",
        "search-nonefound": "נישטא קיין רעזולטאטן פֿאַר דער שאלה.",
        "powersearch-legend": "ווײַטהאלטן זוכן",
        "prefs-tokenwatchlist": "טאקן",
        "prefs-diffs": "צווישנשיידן",
        "prefs-help-prefershttps": "דער פרעפערענץ וועט ארבעטן ביי אײַער נעקסטער ארײַנלאגירונג.",
+       "prefs-tabs-navigation-hint": "טיפ: איר קענט ניצן די רעכטס און לינקס פייל־קלאווישן צו נאוויגירן צווישן די צינגלעך אין דער צינגלעך־ליסטע.",
        "email-address-validity-valid": "ע-פּאָסט אַדרעס זעט אויס גילטיק",
        "email-address-validity-invalid": "לייגט אַרײַן א גילטיקן ע־פאסט אַדרעס",
        "userrights": "באַניצער רעכטן פֿאַרוואַלטערשאפט",
        "right-deletedtext": "באַקוקן אויסגעמעקטן טעקסט און ענדערונגען צווישן אויסגעמעקטע ווערסיעס",
        "right-browsearchive": "זוכן אויסגעמעקטע בלעטער",
        "right-undelete": "צוריקשטעלן א בלאט",
-       "right-suppressrevision": "קוק-איבער און דריי-צוריק רעוויזיעס באהאלטן פון אדימיניסטראטורן",
+       "right-suppressrevision": "איבערקוקן, באהאלטן און אויפדעקן געוויסע רעוויזיעס פון בלעטער פאר אלע באניצער",
+       "right-viewsuppressed": "באקוקן רעוויזיעס באהאלטן פון אלע באניצער",
        "right-suppressionlog": "זען פריוואַטע לאגביכער",
        "right-block": "בלאקירן אַנדערע באַניצער פֿון רעדאַקטירן",
        "right-blockemail": "בלאקירן א באַניצער פֿון שיקן ע־פאסט",
        "uploadstash-errclear": "אוועקנעמען די טעקעס דורכגעפאלן.",
        "uploadstash-refresh": "דערפֿרישן די רשימה פון טעקעס",
        "img-auth-accessdenied": "צוטריט אָפגעזאָגט",
+       "img-auth-notindir": "געשיכטעס שטעג איז נישט אין דער קאנפיגורטער ארויפלאד־דירעקטאריע.",
        "img-auth-badtitle": "קען נישט שאפֿן א גילטיקן טיטל פֿון \"$1\"",
        "img-auth-nologinnWL": "איר זענט נישט ארײַנלאגירט און \"$1\" איז נישט אין דער ווײַסער ליסטע.",
        "img-auth-nofile": "טעקע \"$1\" עקזיסטירט נישט.",
        "license": "ליצענץ:",
        "license-header": "ליצענץ:",
        "nolicense": "גארנישט",
+       "licenses-edit": "רעדאקטירן ליצענץ אפציעס",
        "license-nopreview": "(פֿאראויסקוק נישט פֿאַראַן)",
        "upload_source_url": " (א גילטיקע , צוגעגנלעכער URL)",
        "upload_source_file": "(א טעקע אויף אײַער קאמפיוטער)",
+       "listfiles-delete": "אויסמעקן",
        "listfiles-summary": "דער דאזיקער באזונדערער בלאט ווייזט אלע ארויפגעלאדענע טעקעס.",
        "listfiles_search_for": "זוכן פֿאַר מעדיע נאָמען:",
        "imgfile": "טעקע",
        "double-redirect-fixer": "מתקן ווײַטערפֿירונגען",
        "brokenredirects": "צעבראָכענע ווײַטערפֿירונגען",
        "brokenredirectstext": "די פֿאלגנדע ווײַטערפֿירונגען פֿאַרבינדן צו בלעטער וואס עקזיסטירן נאך נישט:",
-       "brokenredirects-edit": "×¢× ×\93×¢רן",
+       "brokenredirects-edit": "רע×\93×\90ַק×\98×\99רן",
        "brokenredirects-delete": "אויסמעקן",
        "withoutinterwiki": "בלעטער אן שפראך פֿארבינדונגען",
        "withoutinterwiki-summary": "די פֿאלגנדע בלעטער פֿאַרבינדן נישט מיט אַנדערע שפראַך ווערסיעס",
        "wantedpages-badtitle": "אומגילטיקער טיטל אין רעזולטאַט: $1",
        "wantedfiles": "געזוכטע טעקעס",
        "wantedfiletext-cat": "די פֿאלגנדע טעקעס ווערן געניצט אבער זיי עקזיסטירן נישט. טעקעס פון פֿרעמדע רעפאזיטאריעס קענען ווערן אריינגערעכנט טראץ זיי עקזיסטירן יא. אזעלכע גרייזן וועלן ווערן <del>אויסגעשריכן </del>. דערצו, בלעטער וואס ניצן אומעקזיסטירנדע טעקעס ווערן אריינגערעכנט אין [[:$1]].",
+       "wantedfiletext-nocat-noforeign": "די פאלגנדע טעקעס ווערן געניצט אבער זענען נישט פאראן.",
        "wantedtemplates": "געזוכטע מוסטערן",
        "mostlinked": "מערסט פֿארבינדענע בלעטער",
        "mostlinkedcategories": "מערסט פֿארבינדענע קאטעגאריעס",
        "creditspage": "בלאט קרעדיטס",
        "nocredits": "נישט פאראן קיין אינפארמאציע פאר דעם בלאט.",
        "spamprotectiontitle": "ספעם באשיצונג פילטער",
+       "spamprotectionmatch": "די פאלגנדער טעקסט האט געלאזט אין גאנג אונזער ספאם־פילטער: $1",
        "spambot_username": "מעדיעוויקי ספאם פוצן",
        "spam_reverting": "צוריקגעשטעלט צו דער לעצטער ווערסיע אן לינקען צו $1",
        "spam_blanking": "אלע רעוויזיעס האבן לינקען צו $1, אויסליידיקן",
        "spam_deleting": "אלע רעוויזיעס האבן לינקען צו $1, אויסמעקן",
+       "simpleantispam-label": "אנטי־ספאם קאנטראלע.\n'''נישט''' אײַנגעבן קיין אײַנגאב דא!",
        "pageinfo-title": "אינפֿאָרמאַציע פֿאַר \"$1\"",
        "pageinfo-not-current": "קען ווייזן אינפארמאציע נאר פאר דער לויפיקער רעוויזיע.",
        "pageinfo-header-basic": "גרונטלעכע אינפֿארמאַציע",
        "exif-giffilecomment": "GIF טעקע הערה",
        "exif-intellectualgenre": "ארט  איינהייט",
        "exif-subjectnewscode": "טעמע קאד",
+       "exif-scenecode": "IPTC סצענע־קאד",
+       "exif-event": "געוויזענער געשעעניש",
        "exif-organisationinimage": "אויסגעשטעלטע ארגאניזאציע",
        "exif-personinimage": "אויסגעשטעלטער מענטש",
+       "exif-originalimageheight": "בילד־הייך פארן צעשנײַדן",
+       "exif-originalimagewidth": "בילד־ברייט פארן צעשנײַדן",
        "exif-compression-1": "אומ-צאמגעקוועטשט",
        "exif-copyrighted-true": "געשיצט מיט קאפירעכט",
        "exif-copyrighted-false": "קאפירעכט סטאטוס נישט געשטעלט",
        "exif-lightsource-9": "פֿייַן וועטער",
        "exif-lightsource-10": "פאַרוואָלקנטער וועטער",
        "exif-lightsource-11": "שאָטן",
+       "exif-lightsource-255": "אנדער ליכטקוואל",
+       "exif-flash-fired-0": "קיין פלאש",
        "exif-flash-mode-3": "אויטא מאדע",
        "exif-flash-function-1": "קיין בליץ־פונקציע",
        "exif-flash-redeye-1": "רויט־אויג רעדוקציע",
        "watchlistedit-raw-done": "אייער אויפֿפאַסונג ליסטע איז געווארן דערהײַנטיקט",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 טיטל איז|$1 טיטלען זענען}} געווען צוגעלייגט:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 טיטל איז|$1 טיטלען זענען}} געווען אַראָפגענומען:",
+       "watchlistedit-clear-title": "אפגעראמט די אויפפאסן ליסטע",
        "watchlistedit-clear-legend": "ליידיקן די אויפפאסן ליסטע",
+       "watchlistedit-clear-explain": "אלע בלעטער וועט מען אראפנעמען פון אײַער אויפפאסונג־ליסטע",
        "watchlistedit-clear-titles": "טיטלען:",
        "watchlisttools-clear": "ליידיקן די אויפפאסן ליסטע",
        "watchlisttools-view": "ווייזן שייכדיגע ענדערונגען",
        "version-parser-extensiontags": "פארזער פארברייטערן טאַגן",
        "version-hook-name": "נאמען פון hook",
        "version-version": "(ווערסיע $1)",
+       "version-no-ext-name": "[קיין נאמען]",
        "version-license": "מעדיעוויקי ליצענץ",
        "version-ext-license": "ליצענץ",
        "version-ext-colheader-name": "פארברייטערונג",
+       "version-skin-colheader-name": "סקין",
        "version-ext-colheader-version": "ווערסיע",
        "version-ext-colheader-license": "ליצענץ",
        "version-ext-colheader-description": "באַשרײַבונג",
        "version-ext-colheader-credits": "שרייבער",
+       "version-license-title": "ליצענץ פאר $1",
        "version-poweredby-others": "אַנדערע",
        "version-poweredby-translators": "translatewiki.net איבערזעצער",
        "version-credits-summary": "מיר ווילן אנערקענען די פֿאלגנדע מענטשן פֿאר זייער בײַשטײַערוג צו [[Special:Version|מעדיעוויקי]].",
        "api-error-badtoken": "אינערלעכער גרײַז: סימן טויג נישט.",
        "api-error-copyuploaddisabled": "אַרויפֿלאָדן דורך URL איז אומאַקטיווירט אויף דעם סערווירער.",
        "api-error-duplicate": "שוין דאָ אין דער וויקי {{PLURAL:$1|[$2 ָאַן אַנדער טעקע]|[$2 אַנדערע טעקעס]}} מיטן זעלבן תוכן.",
-       "api-error-duplicate-archive": "ס'איז שוין געווען {{PLURAL:$1| [ $2 אַן אַנדער טעקע] | געווען [ $2 עטלעכע אַנדערע טעקעס]}} אויף דעם פּלאַץ מיט דעם זעלביקן תוכן, אָבער {{PLURAL:$1| עס איז | זיי זענען}}  געווארן אויסגעמעקט.",
-       "api-error-duplicate-archive-popup-title": "פֿאַרטאפלטע {{PLURAL:$1| טעקע | טעקעס}} וואָס זענען שוין געווארן אויסגעמעקט",
+       "api-error-duplicate-archive": "ס'איז שוין געווען {{PLURAL:$1| [$2 אַן אַנדער טעקע] | [$1 עטלעכע אַנדערע טעקעס]}} אויף דעם פּלאַץ מיט דעם זעלביקן תוכן, אָבער {{PLURAL:$1| עס איז | זיי זענען}}  געווארן אויסגעמעקט.",
+       "api-error-duplicate-archive-popup-title": "פֿאַרטאפלטע {{PLURAL:$1| טעקע וואָס איז| טעקעס וואָס זענען}}  שוין געווארן אויסגעמעקט",
        "api-error-duplicate-popup-title": "פֿאַרטאפלטע {{PLURAL:$1| טעקע | טעקעס}}",
        "api-error-empty-file": "די טעקע וואָס איר האט אײַנגעגעבן איז ליידיג.",
        "api-error-emptypage": "שאפן נייע ליידיקע בלעטער איז נישט ערלויבט.",
index a67e3d9..0c53e99 100644 (file)
@@ -45,6 +45,7 @@
        "tog-showhiddencats": "Ṣ'àfihàn àwọn ẹ̀ka pípamọ́",
        "tog-norollbackdiff": "Fo ìyàtọ̀ lẹ́yín síṣe ìyísẹ́yìn",
        "tog-useeditwarning": "Kìlọ̀ fún mi tí mo bá únkúrò ní ojúewé àtúnṣe láì tíì mupamọ́",
+       "tog-prefershttps": "Lo ìjáwọlé oníàbò ní gbogbo ìgbà",
        "underline-always": "Nígbà gbogbo",
        "underline-never": "Rárá",
        "underline-default": "Ti àwọ tàbí ẹrọ́ ìtọ́kùn",
        "permalink": "Ìjápọ̀ tíkòníyípadà",
        "print": "Ìtẹ̀síìwé",
        "view": "Ìwòran",
+       "view-foreign": "Ìgbéwò lórí $1",
        "edit": "Àtúnṣe",
+       "edit-local": "Àtúnṣe ìjúwe ìhàhín",
        "create": "Ṣèdá",
+       "create-local": "Ìfikún ìjúwe ìhàhín",
        "editthispage": "S'àtúnṣe ojúewé yi",
        "create-this-page": "Ṣè'dá ojúewé yìí",
        "delete": "Ìparẹ́",
        "talkpagelinktext": "Ọ̀rọ̀",
        "specialpage": "Ojúewé Pàtàkì",
        "personaltools": "Àwọn irinṣẹ́ àdáni",
-       "postcomment": "Abala tuntun",
        "articlepage": "Ìfihàn àkóónú ojúewé",
        "talk": "Ìfọ̀rọ̀wérọ̀",
        "views": "Àwọn ìwò",
        "externaldberror": "Bóyá àsìṣe ìfidájú ibùdó dátà ló ṣẹlẹ̀ tàbí ẹ kò jẹ́ gbígbà ní ààyè láti sọ àpamọ́ òde yín di ọ̀tun.",
        "login": "Ìjáwọlé",
        "nav-login-createaccount": "Ìwọlé / Ìforúkọ sílẹ̀",
-       "loginprompt": "Ẹ gbọ́dọ̀ jọ̀wọ́ cookies láti wọlé sí {{SITENAME}}.",
        "userlogin": "Ìwọlé / ìforúkọ sílẹ̀",
        "userloginnocreate": "Ìjáwọlé",
        "logout": "Ìjáde",
        "duplicate-defaultsort": "'''Ìkìlọ̀:''' Bọ́tìnì ìtò àkọ́kọ́ṣe \"$2\" dípò Bọ́tìnì ìtò àkọ́kọ́ṣe \"$1\" tẹ́lẹ̀.",
        "version": "Àtẹ̀jáde",
        "version-extensions": "Àwọn ìfàgùn kíkànsínú",
+       "version-skins": "Skin (Àwọ̀)",
        "version-specialpages": "Àwọn ojúewé pàtàkì",
        "version-variables": "Ayàtọ̀",
        "version-antispam": "Ìdínà spam",
-       "version-skins": "Skin (Àwọ̀)",
        "version-other": "Òmíràn",
        "version-hooks": "Àwọn hook",
        "version-hook-name": "Orúkọ hook",
index 4c403ac..71d1d7b 100644 (file)
@@ -76,7 +76,8 @@
                        "Hudafu",
                        "아라",
                        "Mywood",
-                       "Impersonator 1"
+                       "Impersonator 1",
+                       "Duolaimi"
                ]
        },
        "tog-underline": "链接下划线:",
        "talkpagelinktext": "讨论",
        "specialpage": "特殊页面",
        "personaltools": "个人工具",
-       "postcomment": "新段落",
        "articlepage": "查看内容页面",
        "talk": "讨论",
        "views": "查看",
        "viewyourtext": "您可以查看并复制<strong>您对此页面作出编辑后</strong>的源代码:",
        "protectedinterface": "该页提供此wiki软件的界面文字,它已被保护以防止恶意修改。\n如欲修改所有wiki的翻译,请到[//translatewiki.net/ translatewiki.net]上的MediaWiki本地化计划。",
        "editinginterface": "'''警告:'''您正在编辑的页面是用于提供软件的界面文字。\n改变此页将影响其他在此wiki上的用户界面外观。\n如欲修改所有wiki的翻译,请到[//translatewiki.net/ translatewiki.net]上的MediaWiki本地化计划。",
-       "cascadeprotected": "此页é\9d¢å·²è¢«ä¿\9dæ\8a¤ï¼\8cå\9b ä¸ºè¿\99个页é\9d¢è¢«ä»¥ä¸\8bå·²æ \87注â\80\9cè\81\94é\94\81ä¿\9dæ\8a¤â\80\9dç\9a\84{{PLURAL:$1|ä¸\80个|å¤\9a个}}被ä¿\9dæ\8a¤é¡µé\9d¢å\8c\85å\90«ï¼\9a\n$2",
+       "cascadeprotected": "æ\9c¬é¡µé\9d¢å·²ç»\8få\8f\97å\88°ä¿\9dæ\8a¤ï¼\8cä¸\8dè\83½ç¼\96è¾\91ï¼\8cå\9b ä¸ºå®\83被åµ\8cå\85¥äº\86以ä¸\8bå\90¯ç\94¨â\80\9c级è\81\94â\80\9dé\80\89项ç\9a\84å\8f\97ä¿\9dæ\8a¤{{PLURAL:$1|页é\9d¢}}ï¼\9a$2",
        "namespaceprotected": "您没有权限编辑'''$1'''名字空间内的页面。",
        "customcssprotected": "您没有权限编辑此CSS页面,因为它包含另一位用户的个人设置。",
        "customjsprotected": "您没有权限编辑此JavaScript页面,因为它包含另一位用户的个人设置。",
        "externaldberror": "验证数据库出错或您被禁止更新您的外部账号。",
        "login": "登录",
        "nav-login-createaccount": "登录/创建账户",
-       "loginprompt": "你必须启用Cookie才能登录{{SITENAME}}。",
        "userlogin": "登录/创建账户",
        "userloginnocreate": "登录",
        "logout": "退出",
        "readonlywarning": "警告:数据库被锁定以进行维护,所以您目前将无法保存您的修改。'''您或许希望将本段文字先剪贴并保存到文本文件,并在稍后进行修改。\n\n锁定数据库的管理员有如下解释:$1",
        "protectedpagewarning": "'''警告:本页面已被保护,只有拥有管理员权限的用户可以编辑。'''下面提供最后的日志条目以供参考:",
        "semiprotectedpagewarning": "'''注意:'''本页面已被保护,只有注册用户可以编辑。下面提供最后的日志条目以供参考:",
-       "cascadeprotectedwarning": "'''警告:'''本页面已被保护,只有拥有管理员权限的用户可以编辑,因为其包含于以下受连锁保护的{{PLURAL:$1|页面}}:",
+       "cascadeprotectedwarning": "<strong>警告:</strong>本页面已经被保护,只有拥有管理员权限的用户可以编辑,因为它被嵌入了以下启用级联保护的{{PLURAL:$1|页面}}:",
        "titleprotectedwarning": "'''警告:本页面已被保护,创建本页面需要[[Special:ListGroupRights|特定权限]]。'''下面提供最后的日志条目以供参考:",
        "templatesused": "该页面使用的{{PLURAL:$1|模板}}:",
        "templatesusedpreview": "本预览使用的{{PLURAL:$1|模板}}:",
        "templatesusedsection": "该段落使用的{{PLURAL:$1|模板}}:",
-       "template-protected": "ï¼\88å·²保护)",
-       "template-semiprotected": "(半保护)",
+       "template-protected": "ï¼\88å\8f\97保护)",
+       "template-semiprotected": "ï¼\88å\8f\97å\8d\8aä¿\9dæ\8a¤ï¼\89",
        "hiddencategories": "该页面属于$1个隐藏分类:",
        "edittools": "<!-- 这里的文字将显示在编辑和上传表格下面。 -->",
        "nocreatetext": "{{SITENAME}}已经限制创建新页面功能。你可以返回编辑现有页面或[[Special:UserLogin|登录或创建账户]]。",
        "revdelete-text-text": "已删除版本仍将在页面历史中显示,但涉及部分的内容将对公众不可见。",
        "revdelete-text-file": "已删除文件版本仍将在文件历史中显示,但涉及部分的内容将对公众不可见。",
        "logdelete-text": "已删除日志事件仍将在日志中显示,但涉及部分的内容将对公众不可见。",
-       "revdelete-text-others": "å\9c¨{{SITENAME}}ç\9a\84å\85¶ä»\96管ç\90\86å\91\98ä»\8då°\86å\8f¯ä»¥è®¿é\97®é\9a\90è\97\8få\86\85容ï¼\8c并å\9c¨ä¸\80å®\9aæ\9d¡ä»¶ä¸\8bè\83½å¤\9fé\80\9aè¿\87ç\9b¸å\90\8cç\95\8cé\9d¢å\8f\96æ¶\88å\88 é\99¤,除非附加条件被设定。",
+       "revdelete-text-others": "å\85¶ä»\96管ç\90\86å\91\98ä»\8då°\86å\8f¯ä»¥è®¿é\97®é\9a\90è\97\8få\86\85容并å\88 é\99¤å®\83,除非附加条件被设定。",
        "revdelete-confirm": "请确认该操作,明白其后果,并确保该操作符合[[{{MediaWiki:Policy-url}}|方针]]。",
        "revdelete-suppress-text": "阻止应'''仅'''用于以下情况:\n* 潜在的诽谤信息\n* 不合适的个人信息\n*: ''家庭地址、电话号码和社保号码等。''",
        "revdelete-legend": "设置可见性之限制",
        "right-deletedtext": "查看已被删除的文本及已删除版本间的差异",
        "right-browsearchive": "搜索已被删除的页面",
        "right-undelete": "还原页面",
-       "right-suppressrevision": "复核并还原对管理员隐藏的版本",
+       "right-suppressrevision": "查看、隐藏与取消隐藏任何用户对页面做出的特定版本",
+       "right-viewsuppressed": "查看被隐藏的任何用户的修订",
        "right-suppressionlog": "查看非公开日志",
        "right-block": "阻止其他用户编辑",
        "right-blockemail": "阻止用户发送电子邮件",
        "right-ipblock-exempt": "绕过IP封禁、自动封禁和段封禁",
        "right-proxyunbannable": "避开代理服务器的自动封禁",
        "right-unblockself": "自我解封",
-       "right-protect": "更改保护级别和编辑受连锁保护的页面",
+       "right-protect": "更改保护级别和编辑受级联保护页面",
        "right-editprotected": "编辑保护级别为“{{int:protect-level-sysop}}”的页面",
        "right-editsemiprotected": "编辑保护级别为“{{int:protect-level-autoconfirmed}}”的页面",
        "right-editinterface": "编辑用户界面",
        "license": "授权协议:",
        "license-header": "授权协议",
        "nolicense": "未选定",
+       "licenses-edit": "编辑许可选项",
        "license-nopreview": "(无预览可用)",
        "upload_source_url": "(有效、可以公开访问的URL)",
        "upload_source_file": "(您计算机上的一个文件)",
+       "listfiles-delete": "删除",
        "listfiles-summary": "本特殊页面展示所有上传的文件。",
        "listfiles_search_for": "按媒体名称搜索:",
        "imgfile": "文件",
        "filehist-comment": "备注",
        "imagelinks": "文件用途",
        "linkstoimage": "以下$1个页面链接至本文件:",
-       "linkstoimage-more": "超过$1个页面连接到这个文件。\n此处只列出首$1个链接到该文件的页面。\n您也可以查看[[Special:WhatLinksHere/$2|完整的列表]]。",
+       "linkstoimage-more": "超过$1个{{PLURAL:$1|页面链接至}}本文件。下面的列表只显示链接至本文件的{{PLURAL:$1|首个页面|前$1个页面}}。[[Special:WhatLinksHere/$2|完整列表]]。",
        "nolinkstoimage": "没有页面链接到本文件。",
        "morelinkstoimage": "查看连接到这个文件的[[Special:WhatLinksHere/$1|更多链接]]。",
        "linkstoimage-redirect": "$1(文件重定向)$2",
        "wantedpages-badtitle": "在结果组上的无效标题:$1",
        "wantedfiles": "需要的文件",
        "wantedfiletext-cat": "以下文件被使用,但并不存在。来自外部库的文件即使存在也可能被列出。任何这类误报会用<del>删除线</del>标记。另外,插入不存在的文件的页面列于[[:$1]]。",
+       "wantedfiletext-cat-noforeign": "以下文件被使用但尚不存在。此外嵌入不存在文件的页面在[[:$1]]列出。",
        "wantedfiletext-nocat": "以下文件被使用,但并不存在。来自外部库的文件即使存在也可能被列出。任何这类误报会用<del>删除线</del>标记。",
+       "wantedfiletext-nocat-noforeign": "以下文件被使用但尚不存在。",
        "wantedtemplates": "需要的模板",
        "mostlinked": "最多链接页面",
        "mostlinkedcategories": "最多链接分类",
        "protectedpages": "受保护页面",
        "protectedpages-indef": "仅无限期保护",
        "protectedpages-summary": "本页面列出当前受保护的页面。要浏览受限制创建的标题列表,请参见[[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]]。",
-       "protectedpages-cascade": "仅连锁保护",
+       "protectedpages-cascade": "仅级联保护",
        "protectedpages-noredirect": "隐藏重定向",
        "protectedpagesempty": "在这些参数下没有页面正在保护。",
        "protectedpages-timestamp": "时间戳",
        "protect-locked-blocked": "您不能在被封禁时更改保护级别。以下是页面'''$1'''的当前设置:",
        "protect-locked-dblock": "您不能在数据库锁定时更改保护级别。以下是页面'''$1'''的当前设置:",
        "protect-locked-access": "您的帐户没有足够的权限去更改保护级别。以下是页面'''$1'''的当前设置:",
-       "protect-cascadeon": "以下$1个页面包含本页面的同时,启动了连锁保护,因此此页面也被保护。您可以设置本页面的保护级别,但这并不会对连锁保护有所影响。",
+       "protect-cascadeon": "该页面目前受到保护,因为它被嵌入了以下启用级联保护的{{PLURAL:$1|页面}}。更改该页面的保护级别不会影响级联保护。",
        "protect-default": "允许所有用户",
        "protect-fallback": "仅允许拥有“$1”权限的用户",
        "protect-level-autoconfirmed": "仅允许自动确认用户",
        "protect-level-sysop": "仅允许管理员",
        "protect-summary-desc": "[$1=$2]($3)",
-       "protect-summary-cascade": "联锁",
+       "protect-summary-cascade": "级联",
        "protect-expiring": "终止于$1(UTC)",
        "protect-expiring-local": "终止于$1",
        "protect-expiry-indefinite": "无限期",
-       "protect-cascade": "保护本页中包含的页面(连锁保护)",
+       "protect-cascade": "保护嵌入该页面的页面(级联保护)",
        "protect-cantedit": "您无法更改这个页面的保护等级,因为您没有权限去编辑它。",
        "protect-othertime": "其它时间:",
        "protect-othertime-op": "其它时间",
        "pageinfo-redirectsto-info": "信息",
        "pageinfo-contentpage": "计为内容页面",
        "pageinfo-contentpage-yes": "是",
-       "pageinfo-protect-cascading": "保护连锁自此",
+       "pageinfo-protect-cascading": "保护级联自这里",
        "pageinfo-protect-cascading-yes": "是",
-       "pageinfo-protect-cascading-from": "保护连锁自",
+       "pageinfo-protect-cascading-from": "保护级联自",
        "pageinfo-category-info": "分类信息",
        "pageinfo-category-pages": "页面数",
        "pageinfo-category-subcats": "子分类数",
        "signature": "[[{{ns:user}}:$1|$2]]([[{{ns:user_talk}}:$1|讨论]])",
        "unknown_extension_tag": "未知扩展标签“$1”",
        "duplicate-defaultsort": "'''警告:'''默认排序关键词“$2”覆盖了之前的默认排序关键词“$1”。",
+       "duplicate-displaytitle": "<strong>警告:</strong>显示的标题“$2”重写了此前显示的标题“$1”。",
        "version": "版本",
        "version-extensions": "安装的扩展程序",
        "version-skins": "已安装皮肤",
index cbca22e..ce4477d 100644 (file)
        "tog-minordefault": "預設標記所有的編輯為小修訂",
        "tog-previewontop": "顯示預覽於編輯框上方",
        "tog-previewonfirst": "第一次編輯時顯示預覽",
-       "tog-enotifwatchlistpages": "當我的監視清單中的頁面或檔案有變更時,送電子郵件通知我",
-       "tog-enotifusertalkpages": "當我的對話頁面有變更時,送電子郵件通知我",
-       "tog-enotifminoredits": "當頁面與檔案有小修訂時,送電子郵件通知我",
-       "tog-enotifrevealaddr": "在通知信件中顯示我的電子郵件址",
+       "tog-enotifwatchlistpages": "當我的監視清單中的頁面或檔案有變更時,送電子郵件通知我",
+       "tog-enotifusertalkpages": "當我的對話頁面有變更時,送電子郵件通知我",
+       "tog-enotifminoredits": "當頁面與檔案有小修訂時,送電子郵件通知我",
+       "tog-enotifrevealaddr": "在通知信件中顯示我的電子郵件址",
        "tog-shownumberswatching": "顯示正在監視的使用者數",
        "tog-oldsig": "現有簽名:",
        "tog-fancysig": "將簽名視為 Wikitext 語言 (不自動產生連結)",
@@ -90,7 +90,7 @@
        "tog-watchlisthideliu": "隱藏監視清單中已登入使用者的編輯",
        "tog-watchlisthideanons": "隱藏監視清單中匿名使用者的編輯",
        "tog-watchlisthidepatrolled": "隱藏監視清單中已巡查的編輯",
-       "tog-ccmeonemails": "送郵件給他人時,也送一份副本到我的電子郵件信箱",
+       "tog-ccmeonemails": "送郵件給他人時,也送一份副本到我的電子郵件信箱",
        "tog-diffonly": "比對版本差異時下面不顯示頁面內容",
        "tog-showhiddencats": "顯示隱藏分類",
        "tog-norollbackdiff": "執行還原後略過差異比對",
        "history_short": "歷史",
        "updatedmarker": "自我最後一次訪問以後的更新",
        "printableversion": "可列印版",
-       "permalink": "固定連結",
+       "permalink": "靜態連結",
        "print": "列印",
        "view": "檢視",
        "view-foreign": "用 $1 檢視",
        "talkpagelinktext": "對話",
        "specialpage": "特殊頁面",
        "personaltools": "個人工具",
-       "postcomment": "新章節",
        "articlepage": "檢視內容頁面",
        "talk": "討論",
        "views": "檢視",
        "categorypage": "檢視分類頁面",
        "viewtalkpage": "檢視討論頁面",
        "otherlanguages": "其他語言",
-       "redirectedfrom": "(重定向自$1)",
-       "redirectpagesub": "重向頁面",
+       "redirectedfrom": "(已重新導向自 $1)",
+       "redirectpagesub": "重新導向頁面",
        "lastmodifiedat": "此頁面最後修訂於 $1 $2。",
        "viewcount": "此頁面已被檢視過 $1 次。",
        "protectedpage": "受保護頁面",
        "mainpage-description": "首頁",
        "policy-url": "Project:方針",
        "portal": "社群主頁",
-       "portal-url": "Project:社專頁",
+       "portal-url": "Project:社專頁",
        "privacy": "隱私政策",
        "privacypage": "Project:Privacy policy",
        "badaccess": "權限錯誤",
        "nstab-project": "專案頁面",
        "nstab-image": "檔案",
        "nstab-mediawiki": "訊息",
-       "nstab-template": "模æ\9d¿",
+       "nstab-template": "樣ç\89\88",
        "nstab-help": "說明頁面",
        "nstab-category": "分類",
        "nosuchaction": "無此動作",
        "externaldberror": "這可能是由於資料庫驗證錯誤,或是不允許您更新外部帳號。",
        "login": "登入",
        "nav-login-createaccount": "登入/建立帳號",
-       "loginprompt": "您必須允許瀏覽器紀錄 Cookie 才能成功登入 {{SITENAME}}。",
        "userlogin": "登入/建立帳號",
        "userloginnocreate": "登入",
        "logout": "登出",
        "createacct-emailoptional": "電子郵件位址 (選填)",
        "createacct-email-ph": "輸入您的電子郵件位址",
        "createacct-another-email-ph": "輸入電子郵件位址",
-       "createaccountmail": "使用臨時的隨機密碼,並將它發送到指定的電子郵件地址",
+       "createaccountmail": "使用臨時的隨機密碼,並將它傳送到指定的電子郵件位址",
        "createacct-realname": "真實姓名 (選填)",
        "createaccountreason": "原因:",
        "createacct-reason": "原因",
        "createacct-captcha": "安全驗證",
        "createacct-imgcaptcha-ph": "輸入您在上方看到的文字",
        "createacct-submit": "建立您的帳號",
-       "createacct-another-submit": "建立另一帳號",
+       "createacct-another-submit": "建ç«\8bå\8f¦ä¸\80å\80\8b帳è\99\9f",
        "createacct-benefit-heading": "{{SITENAME}} 是由像您一樣貢獻的人所建立的。",
        "createacct-benefit-body1": " {{PLURAL:$1|次編輯}}",
        "createacct-benefit-body2": " $1 頁",
        "mailmypassword": "重設密碼",
        "passwordremindertitle": "{{SITENAME}} 的新臨時密碼",
        "passwordremindertext": "不明人士 (可能是您自己,來自 IP 位址 $1) 要求重設在 {{SITENAME}} ($4) 的密碼。\n給使用者 \"$2\" 的臨時密碼設為 \"$3\"。\n如果這個動作是您做的,您需要立即登入並設定一個新的密碼,\n您的臨時密碼將於{{PLURAL:$5|一|$5}}天內過期。\n\n如果不是您要求重設密碼,或您已想起密碼,並不準備修改,\n您可以忽略此訊息並且繼續使用您原本的密碼。",
-       "noemail": "使用者 \"$1\" 未登記電子郵件址。",
-       "noemailcreate": "您需要提供一個有效的電子郵件址。",
-       "passwordsent": "使用者 \"$1\" 的新密碼已寄至當出登記的電子郵件地址,\n請稍後收到信件後再登入。",
+       "noemail": "使用者 \"$1\" 未登記電子郵件址。",
+       "noemailcreate": "您需要提供一個有效的電子郵件址。",
+       "passwordsent": "使用者 \"$1\" 的新密碼已寄至當出登記的電子郵件地址,\n請稍後收到信件後再登入。",
        "blocked-mailpassword": "您的 IP 位址已被封鎖不允許編輯,密碼復原的功能也同樣被禁止使用以防止被濫用。",
-       "eauthentsent": "以發送一封確認信到您所設定的電子郵件地址。\n在未收到其它電子郵件前,您必須先依照信件中的指示,確認這個帳號確實是您本人。",
-       "throttled-mailpassword": "密碼重設的電子郵件已經在最近 $1 小時內送出。\n為防止濫用,$1 小時內只能發送一次密碼重設信件。",
-       "mailerror": "發送郵件錯誤:$1",
-       "acct_creation_throttle_hit": "使用您目前的 IP 位址的參觀者在最近一天建立了 {{PLURAL:$1|1 個帳號|$1 個帳號}},已超出系統允許的上限。\n因此,目前無法讓使用此 IP 位址的參觀者建立帳號。",
+       "eauthentsent": "已寄出一封確認信到您所設定的電子郵件位址。\n在未收到其它電子郵件前,您必須先依照信件中的指示,確認這個帳號確實是您本人。",
+       "throttled-mailpassword": "密碼重設的電子郵件已經在最近 $1 小時內寄出。\n為防止濫用,$1 小時內只能寄出一次密碼重設信件。",
+       "mailerror": "傳送電子郵件錯誤:$1",
+       "acct_creation_throttle_hit": "使用您目前的 IP 位址的訪客在最近一天建立了 {{PLURAL:$1|1 個帳號|$1 個帳號}},已超出系統允許的上限。\n因此,目前無法讓使用此 IP 位址的訪客建立帳號。",
        "emailauthenticated": "您的電子郵件位址已確認於 $2 的 $3。",
-       "emailnotauthenticated": "您的電子郵件地址尚未確認,\n尚不會發送以下功能的電子郵件給您。",
+       "emailnotauthenticated": "您的電子郵件地址尚未確認,\n尚不會寄出以下功能的電子郵件給您。",
        "noemailprefs": "在您的偏好設定中設定電子郵件地址,讓您可以使用這些功能。",
        "emailconfirmlink": "確認您的電子郵件位址",
        "invalidemailaddress": "無法接受格式不正確的電子郵件地址,\n請輸入正確的電子郵件地址格式或略過填寫該欄位。",
        "cannotchangeemail": "此 Wiki 不允許更改帳號的電子郵件位址。",
-       "emaildisabled": "此網站不能送電子郵件。",
+       "emaildisabled": "此網站不能送電子郵件。",
        "accountcreated": "已建立帳號",
        "accountcreatedtext": "使用者帳號 [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|對話]]) 已建立。",
        "createaccount-title": "{{SITENAME}} 的帳號建立",
        "pt-createaccount": "建立帳號",
        "pt-userlogout": "登出",
        "php-mail-error-unknown": "PHP 的 mail() 函數發生不明錯誤。",
-       "user-mail-no-addy": "試圖發送沒有電子郵件地址的電子郵件。",
-       "user-mail-no-body": "試圖發送一個空的或異常簡短的電子郵件。",
+       "user-mail-no-addy": "試圖傳送沒有電子郵件位址的信件。",
+       "user-mail-no-body": "試圖寄出一個空的或異常簡短的電子郵件。",
        "changepassword": "變更密碼",
        "resetpass_announce": "要完成登入,您必須設定一個新密碼。",
        "resetpass_text": "<!-- 在此處加入文字 -->",
        "resetpass-submit-cancel": "取消",
        "resetpass-wrong-oldpass": "無效的臨時或現有密碼。\n您可能早已成功地更改了您的密碼,或者已經請求一個新的臨時密碼。",
        "resetpass-recycled": "請重設您的密碼為一個與目前不同的密碼。",
-       "resetpass-temp-emailed": "您使用臨時電子郵件送的代碼登入。\n要完成登入,您必須在這裡設定一個新密碼:",
+       "resetpass-temp-emailed": "您使用臨時電子郵件送的代碼登入。\n要完成登入,您必須在這裡設定一個新密碼:",
        "resetpass-temp-password": "臨時密碼:",
        "resetpass-abort-generic": "擴充套件已中止了變更密碼的操作。",
        "resetpass-expired": "您的密碼已過期。請設定一個新的密碼以登入。",
        "passwordreset-username": "使用者名稱:",
        "passwordreset-domain": "網域名稱:",
        "passwordreset-capture": "檢視電子郵件內容?",
-       "passwordreset-capture-help": "若您勾選此核選方塊,電子郵件 (包含臨時密碼) 將直接顯示,並發送給使用者。",
+       "passwordreset-capture-help": "若您勾選此核選方塊,電子郵件 (包含臨時密碼) 將直接顯示,並給使用者。",
        "passwordreset-email": "電子郵件位址:",
        "passwordreset-emailtitle": "於 {{SITENAME}} 的帳號詳細資訊",
        "passwordreset-emailtext-ip": "不明人士 (可能是您自己,來自 IP 位址 $1) 要求重設在 {{SITENAME}} ($4) 的密碼,下列是與此電子郵件地址有關的使用者{{PLURAL:$3|帳號}}:\n\n$2\n\n{{PLURAL:$3|這個臨時密碼|這些臨時密碼}}將會在{{PLURAL:$5|一天|$5 天}}內到期,\n您應立即登入並更改新的密碼。如果不是您要求重設密碼,或您已想起密碼,並不準備修改,\n您可以忽略此訊息並且繼續使用您原本的密碼。",
-       "passwordreset-emailtext-user": "使用者 $1 要求重設在 {{SITENAME}} ($4) 的密碼,下列是與此電子郵件址有關的使用者{{PLURAL:$3|帳號}}:\n\n$2\n\n{{PLURAL:$3|這個臨時密碼|這些臨時密碼}}將會在{{PLURAL:$5|一天|$5 天}}內到期,\n您應立即登入並更改新的密碼。如果不是您要求重設密碼,或您已想起密碼,並不準備修改,\n您可以忽略此訊息並且繼續使用您原本的密碼。",
+       "passwordreset-emailtext-user": "使用者 $1 要求重設在 {{SITENAME}} ($4) 的密碼,下列是與此電子郵件址有關的使用者{{PLURAL:$3|帳號}}:\n\n$2\n\n{{PLURAL:$3|這個臨時密碼|這些臨時密碼}}將會在{{PLURAL:$5|一天|$5 天}}內到期,\n您應立即登入並更改新的密碼。如果不是您要求重設密碼,或您已想起密碼,並不準備修改,\n您可以忽略此訊息並且繼續使用您原本的密碼。",
        "passwordreset-emailelement": "使用者名稱:$1\n臨時密碼:$2",
-       "passwordreset-emailsent": "已發送重設密碼的電子郵件。",
-       "passwordreset-emailsent-capture": "已發送重設密碼的電子郵件,並在下面顯示。",
-       "passwordreset-emailerror-capture": "產生的重設密碼的電子郵件如下所示,但送給{{GENDER:$2|使用者}}失敗:$1",
+       "passwordreset-emailsent": "已寄出重設密碼的電子郵件。",
+       "passwordreset-emailsent-capture": "已寄出重設密碼的電子郵件,並在下面顯示。",
+       "passwordreset-emailerror-capture": "產生的重設密碼的電子郵件如下所示,但送給{{GENDER:$2|使用者}}失敗:$1",
        "changeemail": "變更電子郵件位址",
        "changeemail-header": "變更帳號的電子郵件位址",
-       "changeemail-text": "填寫表格以修改您的電子郵件址。您需要輸入密碼以確認此次變更。",
-       "changeemail-no-info": "您必須登入方可直接訪問此頁面。",
+       "changeemail-text": "填寫表格以修改您的電子郵件址。您需要輸入密碼以確認此次變更。",
+       "changeemail-no-info": "您必須登入方可直接存取此頁面。",
        "changeemail-oldemail": "目前的電子郵件位址:",
        "changeemail-newemail": "新的電子郵件位址:",
        "changeemail-none": "(無)",
        "summary-preview": "摘要預覽:",
        "subject-preview": "主旨/標題預覽:",
        "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若您已在 [[Special:Preferences|偏好設定]] 中設定了一個有效的電子郵件地址,且尚未被封鎖郵件功能,則您可透過 \"送電子郵件給這位使用者\" 的功能來聯絡相關管理員。\n您目刖的 IP 位址是 $3,此次封鎖的 ID 爲 #$5。\n請您在詢問時附註以上詳細訊息。",
-       "autoblockedtext": "因先前的另一位使用者被 $1 封鎖,您的 IP 位址已被自動封鎖。\n原因是:\n\n:<em>$2</em>\n\n* 封鎖開始時間:$8\n* 封鎖結束時間:$6\n* 相關封鎖對象:$7\n\n您可以聯繫 $1 或其他的 [[{{MediaWiki:Grouppage-sysop}}|管理員]] 討論封鎖的相關問題。\n若您已在 [[Special:Preferences|偏好設定]] 中設定了一個有效的電子郵件地址,且尚未被封鎖郵件功能,則您可透過 \"送電子郵件給這位使用者\" 的功能來聯絡相關管理員。\n您目刖的 IP 位址是 $3,此次封鎖的 ID 爲 #$5。\n請您在詢問時附註以上詳細訊息。",
+       "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若您已在 [[Special:Preferences|偏好設定]] 中設定了一個有效的電子郵件地址,且尚未被封鎖郵件功能,則您可透過 \"送電子郵件給這位使用者\" 的功能來聯絡相關管理員。\n您目刖的 IP 位址是 $3,此次封鎖的 ID 爲 #$5。\n請您在詢問時附註以上詳細訊息。",
+       "autoblockedtext": "因先前的另一位使用者被 $1 封鎖,您的 IP 位址已被自動封鎖。\n原因是:\n\n:<em>$2</em>\n\n* 封鎖開始時間:$8\n* 封鎖結束時間:$6\n* 相關封鎖對象:$7\n\n您可以聯繫 $1 或其他的 [[{{MediaWiki:Grouppage-sysop}}|管理員]] 討論封鎖的相關問題。\n若您已在 [[Special:Preferences|偏好設定]] 中設定了一個有效的電子郵件地址,且尚未被封鎖郵件功能,則您可透過 \"送電子郵件給這位使用者\" 的功能來聯絡相關管理員。\n您目刖的 IP 位址是 $3,此次封鎖的 ID 爲 #$5。\n請您在詢問時附註以上詳細訊息。",
        "blockednoreason": "未說明原因",
        "whitelistedittext": "請先 $1 才可編輯頁面。",
        "confirmedittext": "在編輯此頁之前您必須確認您的電子郵件位址。\n請透過 [[Special:Preferences|偏好設定]] 設定並驗證您的電子郵件位址。",
        "nosuchsectiontitle": "找不到章節",
-       "nosuchsectiontext": "æ\82¨å\98\97試編輯ç\9a\84ç« ç¯\80並ä¸\8då­\98å\9c¨ã\80\82\nå\8f¯è\83½å\9c¨æ\82¨æ\9f¥ç\9c\8b頁面時已經移動或刪除。",
+       "nosuchsectiontext": "æ\82¨å\98\97試編輯ç\9a\84ç« ç¯\80並ä¸\8då­\98å\9c¨ã\80\82\nå\8f¯è\83½å\9c¨æ\82¨æª¢è¦\96頁面時已經移動或刪除。",
        "loginreqtitle": "需要登入",
        "loginreqlink": "登入",
        "loginreqpagetext": "您必須 $1 才能檢視其它頁面。",
        "accmailtext": "[[User talk:$1|$1]] 的隨機密碼已經寄送至 $2,可登入後至 <em>[[Special:ChangePassword|變更密碼]] 頁面更改</em>。",
        "newarticle": "(新)",
        "newarticletext": "您正連結至一頁不存在頁面。\n要建立該頁面,請在下方的編輯框中輸入內容 (詳情請參考 [$1 説明頁面])。\n如果您是不小心來到此頁面,請點選瀏覽器的 <strong>返回</strong> 按鈕。",
-       "anontalkpagetext": "----\n<em>此討論頁面是給尚未建立帳號的匿名使用者使用</em>\n因此我們必須使用 IP 位址來辨識身份,但相同的 IP 位可能由許多不同的使用者所共用。\n如果您是匿名使用者並且覺得評論的內容與您無關,請 [[Special:UserLogin/signup|建立新帳號]] 或 [[Special:UserLogin|登入]] 避免與其他匿名使用者混淆。",
+       "anontalkpagetext": "----\n<em>此討論頁面是給尚未建立帳號的匿名使用者使用</em>\n因此我們必須使用 IP 位址來辨識身份,但相同的 IP 位可能由許多不同的使用者所共用。\n如果您是匿名使用者並且覺得評論的內容與您無關,請 [[Special:UserLogin/signup|建立新帳號]] 或 [[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}}}} 刪除日誌]。",
        "session_fail_preview": "<strong>很抱歉!由於連線階段的資料遺失,我們無法處理您的編輯動作。</strong>\n請再試一次。\n如果仍然失敗,請 [[Special:UserLogout|登出]] 後重新登入。",
        "session_fail_preview_html": "<strong>很抱歉!由於連線階段的資料遺失,我們無法處理您的編輯動作。</strong>\n\n<em>由於 {{SITENAME}} 開啟了原始 HTML 模式,將不會顯示預覽畫面以避免 JavaScript 攻擊。</em>\n\n<strong>若這是符合規範的編輯動作,請再試一次。</strong>\n如果仍然有問題,請 [[Special:UserLogout|登出]] 後再重新登入一次。",
        "token_suffix_mismatch": "<strong>您使用的瀏覽器刪除了編輯資訊中的特殊符號,已拒絕此編輯動作。</strong>\n為了避免破壞頁面內容,已拒絕此編輯動作,\n這通常是因為您使用了有問題的匿名網頁代理伺服器。",
-       "edit_form_incomplete": "<strong>部份編輯的內容未送至伺服器,請檢查您的編輯內容是否完整並再試一次。</strong>",
+       "edit_form_incomplete": "<strong>部份編輯的內容未送至伺服器,請檢查您的編輯內容是否完整並再試一次。</strong>",
        "editing": "正在編輯 $1",
        "creating": "正在建立 $1",
        "editingsection": "正在編輯 $1 (章節)",
        "explainconflict": "在您開始編輯之後已有其他人儲存了此頁面。\n上方的文字框內顯示了目前頁面中的文字內容,\n您所變更的文字內容顯示在下方文字框中。\n您須要將您所變更的文字內容合併到已儲存的文字內容當中。\n若您直接點選 \"{{int:savearticle}}\" <strong>只有</strong> 上方文字框中的內容會被儲存。",
        "yourtext": "您的文字",
        "storedversion": "已儲存修訂",
-       "nonunicodebrowser": "<strong>警告:您的瀏覽器不相容 Unicode。</strong>\n暫時解決的方式是先在您可安全編輯頁面的地方編輯:非 ASCII 字元在編輯框中會以 16 進位編碼顯示。",
+       "nonunicodebrowser": "<strong>警告:您的瀏覽器與 Unicode 不相容。</strong>\n暫時解決的方式是先在您可安全編輯頁面的地方編輯:非 ASCII 字元在編輯框中會以 16 進位編碼顯示。",
        "editingold": "<strong>警告:您目前正編輯頁面的舊修訂版本。</strong>\n若您儲存,在此修訂之後變更的任何內容將會遺失。",
        "yourdiff": "差異",
        "copyrightwarning": "請注意,所有於 {{SITENAME}} 所做的貢獻會依據 $2 授權條款發佈 (詳情請見 $1)。\n若您不希望您的著作被任意修改與散佈,請勿在此發表文章。<br />\n您同時向我們保証在此的著作內容是您自行撰寫,或是取自不受版權保護的公開領域或自由資源。\n<strong>請勿在未經授權的情況下發表文章!</strong>",
        "diff-multi-sameuser": "(未顯示相同使用者於中間所作的 $1 次修訂)",
        "diff-multi-otherusers": "(未顯示由 $2 位使用者於中間所作的 $1 次修訂)",
        "diff-multi-manyusers": "(未顯示由超過 $2 位使用者於中間所作的 $1 次修訂)",
-       "difference-missing-revision": "{{PLURAL:$2|1次修è¨\82|$2 æ¬¡ä¿®è¨\82}}å·®ç\95°($1)ä¸\8då­\98å\9c¨ã\80\82\n\né\80\99é\80\9a常æ\98¯å\9b ç\82ºé\81\8eæ\99\82ç\9a\84é \81é\9d¢ä¿®è¨\82å·®ç\95°é\8f\88æ\8e¥被刪除。\n詳情請閱[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌]。",
+       "difference-missing-revision": "{{PLURAL:$2|1次修è¨\82|$2 æ¬¡ä¿®è¨\82}}å·®ç\95°($1)ä¸\8då­\98å\9c¨ã\80\82\n\né\80\99é\80\9a常æ\98¯å\9b ç\82ºé\81\8eæ\99\82ç\9a\84é \81é\9d¢ä¿®è¨\82å·®ç\95°é\80£çµ\90被刪除。\n詳情請閱[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌]。",
        "searchresults": "搜尋結果",
        "searchresults-title": "\"$1\" 的搜尋結果",
        "titlematches": "頁面標題符合",
        "search-result-size": "$1 ($2 個字)",
        "search-result-category-size": "$1 位成員 ($2 個子分類,$3 個檔案)",
        "search-result-score": "相關度:$1%",
-       "search-redirect": "(重定向自 $1)",
+       "search-redirect": "(重新導向 $1)",
        "search-section": "(章節 $1)",
        "search-file-match": "(符合檔案內容)",
        "search-suggest": "您指的是不是:$1",
        "powersearch-togglelabel": "請選擇:",
        "powersearch-toggleall": "全部",
        "powersearch-togglenone": "無",
-       "powersearch-remember": "記住選項用於以後搜",
+       "powersearch-remember": "記住選項用於以後搜",
        "search-external": "外部搜尋",
        "searchdisabled": "{{SITENAME}} 已停用搜尋功能。\n您可以改透過 Google 搜尋。\n請注意,在 Google 中搜尋到的 {{SITENAME}} 頁面內容可能不是最新的。",
        "search-error": "搜尋時發生錯誤:$1",
        "right-move-rootuserpages": "移動根使用者頁面",
        "right-move-categorypages": "移動分類頁面",
        "right-movefile": "移動檔案",
-       "right-suppressredirect": "移動頁面時不在原頁面建立重定向",
+       "right-suppressredirect": "移動頁面時不在原頁面位置建立重新導向頁面",
        "right-upload": "上傳檔案",
        "right-reupload": "覆蓋現有的檔案",
        "right-reupload-own": "覆蓋自己上傳的檔案",
        "right-suppressrevision": "複查與還原由管理員隱藏的修訂",
        "right-suppressionlog": "檢視非公開日誌",
        "right-block": "封鎖其他使用者的編輯權限",
-       "right-blockemail": "封鎖使用者送電子郵件的權限",
+       "right-blockemail": "封鎖使用者送電子郵件的權限",
        "right-hideuser": "封鎖使用者名稱,避免公開顯示",
        "right-ipblock-exempt": "略過 IP 封鎖、自動封鎖及範圍封鎖檢查",
        "right-proxyunbannable": "略過 Proxy 自動封鎖檢查",
        "right-userrights-interwiki": "編輯使用者在其它 Wiki 上的權限",
        "right-siteadmin": "鎖定和解除鎖定資料庫",
        "right-override-export-depth": "匯出頁面包含連結內容,深度上限為 5 層",
-       "right-sendemail": "送電子郵件給其他使用者",
+       "right-sendemail": "送電子郵件給其他使用者",
        "right-passwordreset": "檢視重設密碼電子郵件",
        "newuserlogpage": "建立使用者日誌",
        "newuserlogpagetext": "此為建立使用者的日誌。",
        "action-userrights": "編輯所有使用者的權限",
        "action-userrights-interwiki": "編輯在其它 Wiki 上的使用者權限",
        "action-siteadmin": "鎖定和解除鎖定資料庫",
-       "action-sendemail": "送電子郵件",
+       "action-sendemail": "送電子郵件",
        "action-editmywatchlist": "編輯您的監視清單",
        "action-viewmywatchlist": "檢視您的監視清單",
-       "action-viewmyprivateinfo": "æ\9f¥ç\9c\8b您的個人資料",
+       "action-viewmyprivateinfo": "檢è¦\96您的個人資料",
        "action-editmyprivateinfo": "編輯您的個人資料",
        "nchanges": "$1 次變更",
        "enhancedrc-since-last-visit": "自上次訪問已有 $1",
        "upload-file-error-text": "嘗試在伺服器上建立臨時檔案時發生內部錯誤。\n請連絡 [[Special:ListUsers/sysop|管理員]]。",
        "upload-misc-error": "不明的上傳錯誤",
        "upload-misc-error-text": "上傳時發生不明錯誤。\n請檢查您的 URL 是否有效且可存取,然後再重試一次。\n如果仍有問題,請聯絡 [[Special:ListUsers/sysop|管理員]]。",
-       "upload-too-many-redirects": "URL 中包含太多重定向",
+       "upload-too-many-redirects": "該 URL 重新導向至太多其他位址",
        "upload-http-error": "發生 HTTP 錯誤:$1",
        "upload-copy-upload-invalid-domain": "此網域不允許複製上傳的檔案。",
        "backend-fail-stream": "無法傳輸檔案 \"$1\"。",
        "license": "授權條款:",
        "license-header": "授權條款",
        "nolicense": "尚未選擇",
+       "licenses-edit": "編輯授權條款選項",
        "license-nopreview": "(不可預覽)",
        "upload_source_url": "(有效,可公開存取的 URL)",
        "upload_source_file": "(在您電腦上的檔案)",
+       "listfiles-delete": "刪除",
        "listfiles-summary": "此特殊頁面顯示所有上傳過的檔案。",
        "listfiles_search_for": "搜尋媒體名稱:",
        "imgfile": "檔案",
        "filehist-dimensions": "尺寸",
        "filehist-filesize": "檔案大小",
        "filehist-comment": "註解",
-       "imagelinks": "檔案使用",
-       "linkstoimage": "下列 $1 個頁面連結到此檔案:",
-       "linkstoimage-more": "超過$1個頁面連接到這個檔案。\n此處只列出首$1個連接到此檔案的頁面。\n您也可以查看[[Special:WhatLinksHere/$2|完整的清單]]。",
+       "imagelinks": "檔案用途",
+       "linkstoimage": "下列 {{PLURAL:$1|頁面連結|$1 個頁面連結}}到此檔案:",
+       "linkstoimage-more": "超過$1個{{PLURAL:$1|頁面連結|頁面連結}}到這個檔案。\n此處只列出{{PLURAL:$1|首個連結|首$1個連結}}到此檔案的頁面。\n您也可以檢視[[Special:WhatLinksHere/$2|完整的清單]]。",
        "nolinkstoimage": "沒有頁面連接到本檔案。",
-       "morelinkstoimage": "檢視連到這個檔案的[[Special:WhatLinksHere/$1|更多連結]]。",
-       "linkstoimage-redirect": "$1(檔案重定向)$2",
+       "morelinkstoimage": "檢視連到這個檔案的[[Special:WhatLinksHere/$1|更多連結]]。",
+       "linkstoimage-redirect": "$1 (檔案重新導向) $2",
        "duplicatesoffile": "以下 $1 個檔案與此檔案重覆 ([[Special:FileDuplicateSearch/$2|了解詳細資訊]]):",
        "sharedupload": "此檔案來自 $1 且可能被其他專案所使用。",
        "sharedupload-desc-there": "此檔案來自 $1 且可能被其他專案所使用。\n請參考 [$2 檔案描述頁面] 了解進一步資訊。",
        "mimetype": "MIME 類型:",
        "download": "下載",
        "unwatchedpages": "未監視的頁面",
-       "listredirects": "重向頁面清單",
+       "listredirects": "重新導向頁面清單",
        "listduplicatedfiles": "重複檔案列表",
        "listduplicatedfiles-summary": "以下列表中某檔案之最新版本與其他檔案之最新版本重複。進包含本地檔案",
        "listduplicatedfiles-entry": "[[:File:$1|$1]] 有[[$3|其他 $2 個重複檔案]]。",
        "randomincategory-nopages": "[[:Category:$1]]中沒有頁面。",
        "randomincategory-selectcategory": "從分類中獲取隨機頁面:$1 $2",
        "randomincategory-selectcategory-submit": "執行",
-       "randomredirect": "隨機重向",
-       "randomredirect-nopages": "在命名空間\"$1\"中沒有任何重定向頁面。",
+       "randomredirect": "隨機重新導向",
+       "randomredirect-nopages": "在命名空間 \"$1\" 中沒有任何重新導向頁面。",
        "statistics": "統計",
        "statistics-header-pages": "頁面統計",
        "statistics-header-edits": "編輯統計",
        "statistics-header-hooks": "其它統計",
        "statistics-articles": "內容頁面",
        "statistics-pages": "頁面",
-       "statistics-pages-desc": "在 wiki 上所有的頁面,包括對話頁面、重定向頁面等。",
+       "statistics-pages-desc": "在 Wiki 上所有的頁面,包括對話頁面、重新導向頁面等。",
        "statistics-files": "已經上傳的檔案",
        "statistics-edits": "自 {{SITENAME}} 成立以來的頁面編輯數",
        "statistics-edits-average": "每頁平均編輯數",
        "pageswithprop-submit": "執行",
        "pageswithprop-prophidden-long": "已隱藏過長的屬性值 ($1)",
        "pageswithprop-prophidden-binary": "已隱藏二進位屬性值 ($1)",
-       "doubleredirects": "雙重重定向",
-       "doubleredirectstext": "這一頁列出所有重定向頁面重定向到另一個重定向頁的頁面。每一行都包含到第一和第二個重定向頁面的連結,以及第二個重定向頁面的目標,通常顯示的都會是\"真正\"的目標頁面,也就是第一個重定向頁面應該指向的頁面。\n<del>已劃去</del>的為已經解決之項目。",
-       "double-redirect-fixed-move": "[[$1]] 已完成移動。\n此頁面已自動更新並重向至 [[$2]]。",
-       "double-redirect-fixed-maintenance": "作為維護工作自動修復於[[$1]]至[[$2]]之雙重重定向。",
-       "double-redirect-fixer": "重向修正者",
-       "brokenredirects": "損壞的重定向頁面",
-       "brokenredirectstext": "以下的重定向頁面均指向不存在的頁面:",
+       "doubleredirects": "雙重的重新導向",
+       "doubleredirectstext": "此頁列出所有重新導向頁面連結到另一個重新導向頁面的頁面清單。每一列都包含第一次和第二次重新導向頁面的連結,以及第二次重新導向之後的目標,第二次重新導向之後的目標通常是 \"實際\" 的目標頁面,也是第一個重新導向頁面應該指向的頁面。\n<del>刪節線</del> 代表該項目的問題已經解決。",
+       "double-redirect-fixed-move": "[[$1]] 已完成移動。\n此頁面已自動更新並重新導向至 [[$2]]。",
+       "double-redirect-fixed-maintenance": "在維護作業時自動修正雙重的重新導向自 [[$1]] 至 [[$2]]。",
+       "double-redirect-fixer": "重新導向修正者",
+       "brokenredirects": "損壞的重新導向",
+       "brokenredirectstext": "以下的重新導向頁面連結的頁面不存在:",
        "brokenredirects-edit": "編輯",
        "brokenredirects-delete": "刪除",
        "withoutinterwiki": "未有語言連結的頁面",
        "wantedpages": "需要的頁面",
        "wantedpages-badtitle": "在結果組上的無效標題: $1",
        "wantedfiles": "需要的檔案",
-       "wantedfiletext-cat": "以下檔案被使用,但不存在。外部儲存庫的文件儘管現有,但可能會在此列出,任何此類的誤報將被<del>剔除</del>。此外,內嵌了不存在的檔案的網頁將在[[:$1]]列出。",
+       "wantedfiletext-cat": "以下檔案被使用,但不存在。外部儲存庫的檔案儘管現有,但可能會在此列出,任何此類的誤報將被<del>剔除</del>。此外,內嵌了不存在的檔案的網頁將在[[:$1]]列出。",
+       "wantedfiletext-cat-noforeign": "下列檔案已被使用但不存在。 除此之外,頁面已內嵌但不存在的檔案列於 [[:$1]]。",
        "wantedfiletext-nocat": "以下檔案被使用,但不存在。外部儲存庫的文件儘管現有,但可能會在此列出,任何此類的誤報將被<del>剔除</del>。",
+       "wantedfiletext-nocat-noforeign": "下列檔案已被使用但不存在。",
        "wantedtemplates": "需要的樣版",
        "mostlinked": "最多連結頁面",
        "mostlinkedcategories": "最多連結分類",
-       "mostlinkedtemplates": "最多被嵌入包含的頁面",
+       "mostlinkedtemplates": "被引用最多的頁面",
        "mostcategories": "最多分類頁面",
        "mostimages": "最多連結檔案",
        "mostinterwikis": "最多 Interwiki 連結的頁面",
        "protectedpages-indef": "只顯示無限期的保護頁面",
        "protectedpages-summary": "此頁面列出目前受保護的頁面。 欲查詢受保護標題清單,請參考 [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]]。",
        "protectedpages-cascade": "只顯示連鎖的保護頁面",
-       "protectedpages-noredirect": "隱藏重向頁面",
+       "protectedpages-noredirect": "隱藏重新導向頁面",
        "protectedpagesempty": "在這些參數下沒有頁面正在保護。",
        "protectedpages-timestamp": "日期時間",
        "protectedpages-page": "頁面",
        "allpagesprefix": "顯示以此為字首頁面:",
        "allpagesbadtitle": "指定的頁面標題無效、包含內部語言或內部 Wiki 的字首。\n它可能包含一個或多個的不能用於標題的字元。",
        "allpages-bad-ns": "{{SITENAME}} 沒有 \"$1\" 命名空間。",
-       "allpages-hide-redirects": "隱藏重向頁面",
+       "allpages-hide-redirects": "隱藏重新導向頁面",
        "cachedspecial-viewing-cached-ttl": "你正在瀏覽本頁的緩存版本,至多可能存在$1的延遲。",
        "cachedspecial-viewing-cached-ts": "您正在閱讀此頁的緩存版本,這可能不是完整的版本。",
-       "cachedspecial-refresh-now": "æ\9f¥ç\9c\8b最新。",
+       "cachedspecial-refresh-now": "檢è¦\96最新。",
        "categories": "頁面分類",
        "categoriespagetext": "下列為包含頁面或媒體的{{PLURAL:$1|分類}}。\n[[Special:UnusedCategories|未使用的分類]] 不會在此顯示。\n請參考 [[Special:WantedCategories|需要的分類]]。",
        "categoriesfrom": "顯示由此項起之分類:",
        "deletedcontributions": "已刪除的使用者貢獻",
        "deletedcontributions-title": "已刪除的使用者貢獻",
        "sp-deletedcontributions-contribs": "貢獻",
-       "linksearch": "å¤\96é\83¨é\8f\88æ\8e¥æ\90\9cç´¢",
+       "linksearch": "å¤\96é\83¨é\80£çµ\90æ\90\9cå°\8b",
        "linksearch-pat": "搜尋網址:",
        "linksearch-ns": "命名空間:",
        "linksearch-ok": "搜尋",
-       "linksearch-text": "可使用通配符,如“*.wikipedia.org”。至少需要一個頂級域名,例如“*.org”。<br />\n支持的{{PLURAL:$2|協議}}:<code>$1</code>(若沒有指定協議,預設為http://)。",
+       "linksearch-text": "可使用萬用字元如 \"*.wikipedia.org\"。\n萬用字元必須使用在最上層網域,例如 \"*.org\".<br />\n支援的{{PLURAL:$2|通訊協定|通訊協定}}有:<code>$1</code> (若未指定則預設使用 http:// 通訊協定)。",
        "linksearch-line": "$1 連自 $2",
        "linksearch-error": "萬用字元僅可在主機名稱的開頭使用。",
        "listusersfrom": "顯示使用者開始自:",
        "listgrouprights-removegroup": "移除的{{PLURAL:$2|一個|多個}}群組: $1",
        "listgrouprights-addgroup-all": "加入所有群組",
        "listgrouprights-removegroup-all": "移除所有群組",
-       "listgrouprights-addgroup-self": "在自己的賬戶中加入的{{PLURAL:$2|一個|多個}}群組: $1",
-       "listgrouprights-removegroup-self": "在自己的賬戶中移除的{{PLURAL:$2|一個|多個}}群組: $1",
-       "listgrouprights-addgroup-self-all": "在自己的賬戶中加入所有群組",
-       "listgrouprights-removegroup-self-all": "在自己的賬戶中移除所有群組",
+       "listgrouprights-addgroup-self": "在自己的帳號中加入的{{PLURAL:$2|一個|多個}}群組: $1",
+       "listgrouprights-removegroup-self": "在自己的帳號中移除的{{PLURAL:$2|一個|多個}}群組: $1",
+       "listgrouprights-addgroup-self-all": "在自己的帳號中加入所有群組",
+       "listgrouprights-removegroup-self-all": "在自己的帳號中移除所有群組",
        "listgrouprights-namespaceprotection-header": "命名空間限制",
        "listgrouprights-namespaceprotection-namespace": "命名空間",
        "listgrouprights-namespaceprotection-restrictedto": "允許使用者編輯的權限",
        "hidden-category-category-desc": "此分類帶有<code><nowiki>__HIDDENCAT__</nowiki></code>,它預設防止於頁面分類連接盒中顯示。",
        "trackingcategories-nodesc": "並無說明。",
        "trackingcategories-disabled": "分類被禁用",
-       "mailnologin": "沒有送位址",
-       "mailnologintext": "您必須先 [[Special:UserLogin|登入]]\n並在 [[Special:Preferences|偏好設定]]\n中設定一個有效的電子郵件地址才可以發送信件給其他使用者。",
+       "mailnologin": "沒有送位址",
+       "mailnologintext": "您必須先 [[Special:UserLogin|登入]]\n並在 [[Special:Preferences|偏好設定]]\n中設定一個有效的電子郵件位址才可以傳送信件給其他使用者。",
        "emailuser": "寄信給此使用者",
        "emailuser-title-target": "寄信給此{{GENDER:$1|使用者}}",
        "emailuser-title-notarget": "寄信給使用者",
        "emailpage": "E-mail 給使用者",
-       "emailpagetext": "您可以使用以下表格發送電子郵件給這位 {{Gender:$1|使用者}}。\n您在 [[Special:Preferences|偏好設定]] 中所輸入的電子郵件地址將會作為郵件的 \"寄件人\",因此該使用者可直接回覆您。",
-       "defemailsubject": "來自使用者 \"$1\" 於 {{SITENAME}} 發送的電子郵件",
+       "emailpagetext": "您可以使用以下表格傳送電子郵件給這位 {{Gender:$1|使用者}}。\n您在 [[Special:Preferences|偏好設定]] 中所輸入的電子郵件位址將會作為郵件的 \"寄件人\",因此該使用者可直接回覆您。",
+       "defemailsubject": "來自使用者 \"$1\" 於 {{SITENAME}} 寄來的電子郵件",
        "usermaildisabled": "使用者電子郵件已停用",
-       "usermaildisabledtext": "您不可送信件到這個 Wiki 上的其他使用者",
-       "noemailtitle": "沒有電子郵件址",
-       "noemailtext": "此使用者尚未指定一個有效的電子郵件址。",
+       "usermaildisabledtext": "您不可送信件到這個 Wiki 上的其他使用者",
+       "noemailtitle": "沒有電子郵件址",
+       "noemailtext": "此使用者尚未指定一個有效的電子郵件址。",
        "nowikiemailtext": "此使用者選擇不接收其他使用者的信件。",
        "emailnotarget": "收件人不存在或無效的使用者名稱。",
        "emailtarget": "輸入收件人使用者名稱",
        "emailusername": "使用者名稱:",
        "emailusernamesubmit": "送出",
-       "email-legend": "送電子郵件給另一位 {{SITENAME}} 使用者",
+       "email-legend": "送電子郵件給另一位 {{SITENAME}} 使用者",
        "emailfrom": "寄件人:",
        "emailto": "收件人:",
        "emailsubject": "主題:",
        "emailmessage": "訊息:",
-       "emailsend": "送",
-       "emailccme": "送一份副本到我的電子郵件信箱。",
-       "emailccsubject": "您發送給 $1 的訊息副本:$2",
-       "emailsent": "電子郵件已發送",
+       "emailsend": "送",
+       "emailccme": "送一份副本到我的電子郵件信箱。",
+       "emailccsubject": "您給 $1 的訊息副本:$2",
+       "emailsent": "電子郵件已送出",
        "emailsenttext": "您的電子郵件訊息已經送出。",
-       "emailuserfooter": "這封電子郵件是由 $1 透過 {{SITENAME}} 的 \"送信件給使用者\" 功能寄給 $2。",
+       "emailuserfooter": "這封電子郵件是由 $1 透過 {{SITENAME}} 的 \"送信件給使用者\" 功能寄給 $2。",
        "usermessage-summary": "留給系統訊息。",
        "usermessage-editor": "系統訊息",
        "watchlist": "監視清單",
        "deletecomment": "原因:",
        "deleteotherreason": "其它/額外的原因:",
        "deletereasonotherlist": "其它理由",
-       "deletereason-dropdown": "* 常見的刪除原因\n** 濫發廣告訊息\n** 破壞\n** 侵犯版權\n** 作者請求\n** 損壞的重定向",
+       "deletereason-dropdown": "* 常見的刪除原因\n** 濫發廣告訊息\n** 破壞\n** 侵犯版權\n** 作者請求\n** 損壞的重新導向連結",
        "delete-edit-reasonlist": "編輯刪除理由",
        "delete-toobig": "這個頁面有一個十分大量的編輯歷史,超過$1次修訂。刪除此類頁面的動作已經被限制,以防止在{{SITENAME}}上的意外擾亂。",
        "delete-warning-toobig": "這個頁面有一個十分大量的編輯歷史,超過$1次修訂。刪除它可能會擾亂{{SITENAME}}的資料庫操作;在繼續此動作前請小心。",
        "linkshere": "以下頁面連結到[[:$1]]:",
        "nolinkshere": "沒有頁面連結到[[:$1]]。",
        "nolinkshere-ns": "已選擇的命名空間中沒有頁面連結到 [[:$1]]。",
-       "isredirect": "重向頁面",
+       "isredirect": "重新導向頁面",
        "istemplate": "引用",
        "isimage": "檔案連結",
        "whatlinkshere-prev": "前 $1 筆",
        "whatlinkshere-next": "後 $1 筆",
        "whatlinkshere-links": "← 連入",
-       "whatlinkshere-hideredirs": "$1 重向頁面",
+       "whatlinkshere-hideredirs": "$1 重新導向頁面",
        "whatlinkshere-hidetrans": "$1 引用",
        "whatlinkshere-hidelinks": "$1 連結",
        "whatlinkshere-hideimages": "$1 檔案連結",
        "ipbreason-dropdown": "*常見的封鎖原因\n** 填寫不實資訊\n** 刪除頁面內容\n** 散佈外部廣告連結\n** 在頁面填寫無意義文字\n** 無禮的行為、攻擊/騷擾別人\n** 濫用多個帳號\n** 使用不受歡迎的使用者名稱",
        "ipb-hardblock": "避免使用此 IP 位址登入的使用者編輯",
        "ipbcreateaccount": "禁止建立帳號",
-       "ipbemailban": "禁止使用者送電子郵件",
-       "ipbenableautoblock": "自動封鎖此使用者最後使用的 IP 位,以及所有之後嘗試編輯使用的 IP 位址",
-       "ipbsubmit": "查封該地址",
+       "ipbemailban": "禁止使用者送電子郵件",
+       "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": "在編輯及清單中隱藏使用者名稱",
        "unblocklink": "解除封鎖",
        "change-blocklink": "變更封鎖",
        "contribslink": "貢獻",
-       "emaillink": "送電子郵件",
+       "emaillink": "送電子郵件",
        "autoblocker": "您的 IP 位址因最近被 [[User:$1|$1]] 使用過而被自動封鎖。\n封鎖 $1 的原因為 \"$2\"",
        "blocklogpage": "查封日誌",
        "blocklog-showlog": "此使用者先前被封鎖過。\n以下為封鎖紀錄以供參考:",
        "blocklog-showsuppresslog": "此使用者先前被封鎖並且隱藏過。\n以下為禁止顯示紀錄以供參考:",
        "blocklogentry": "已封鎖 [[$1]] 的期限至 $2 $3",
        "reblock-logentry": "更改 [[$1]] 的封鎖期限至 $2 $3",
-       "blocklogtext": "æ­¤ç\82ºä½¿ç\94¨è\80\85ç\9a\84å°\81é\8e\96å\8f\8aå\8f\96æ¶\88å°\81é\8e\96è¨\98é\8c\84ã\80\82\nä¸\8då\8c\85è\87ªå\8b\95å°\81é\8e\96ç\9a\84 IP ä½\8då\9d\80ã\80\82\nè«\8bå\8f\83è\80\83 [[Special:BlockList|å°\81é\8e\96æ¸\85å\96®]] ä»¥æ\9f¥ç\9c\8b目前的封鎖。",
+       "blocklogtext": "æ­¤ç\82ºä½¿ç\94¨è\80\85ç\9a\84å°\81é\8e\96å\8f\8aå\8f\96æ¶\88å°\81é\8e\96è¨\98é\8c\84ã\80\82\nä¸\8då\8c\85è\87ªå\8b\95å°\81é\8e\96ç\9a\84 IP ä½\8då\9d\80ã\80\82\nè«\8bå\8f\83è\80\83 [[Special:BlockList|å°\81é\8e\96æ¸\85å\96®]] ä»¥æª¢è¦\96目前的封鎖。",
        "unblocklogentry": "已解封 $1",
        "block-log-flags-anononly": "僅限匿名使用者",
        "block-log-flags-nocreate": "停用帳號建立",
        "ip_range_invalid": "無效的 IP 範圍。",
        "ip_range_toolarge": "不允許封鎖範圍大於 /$1。",
        "proxyblocker": "代理封鎖器",
-       "proxyblockreason": "因您的 IP 位址是開放代理伺服器,已被封鎖。\n請聯繫您的網服務供應商或您所在組織的技術支援,告知他們此嚴重的安全性問題。",
-       "sorbsreason": "您的IP位址在{{SITENAME}}中被 DNSBL列為屬於開放代理服務器。",
-       "sorbs_create_account_reason": "您連線到 {{SITENAME}} 的 IP 位址被 DNSBL 列為開放代理伺服。\n您不能建立帳號。",
+       "proxyblockreason": "因您的 IP 位址是開放代理伺服器,已被封鎖。\n請聯繫您的網服務供應商或您所在組織的技術支援,告知他們此嚴重的安全性問題。",
+       "sorbsreason": "您的 IP 位址在{{SITENAME}}中被 DNSBL列為屬於開放代理服務器。",
+       "sorbs_create_account_reason": "您連線到 {{SITENAME}} 的 IP 位址被 DNSBL 列為開放代理伺服。\n您不能建立帳號。",
        "xffblockreason": "您的 IP 位址使用 X-Forwarded-For 標頭,您或您使用的代理伺服器已被封鎖。\n封鎖的原因為:$1",
        "cant-see-hidden-user": "您欲封鎖的使用者已經被封鎖並且隱藏。\n您沒有隱藏使用者的權限,您無法檢視或編輯該使用者的封鎖狀態。",
        "ipbblocked": "因您已被封鎖,故無法封鎖或解除封鎖其他使用者。",
        "lockedbyandtime": "(由 {{GENDER:$1|$1}} 於 $2 的 $3)",
        "move-page": "移動 $1",
        "move-page-legend": "移動頁面",
-       "movepagetext": "以下表格可以用來重新命名頁面,並將該頁面的所有歷史記錄一併移至擁有新名稱的頁面。\n舊標題的頁面將會變成重定向頁面,指向使用新標題的頁面。\n您可以選擇自動更新所有指向舊頁面的重定向,讓它們改為指向新頁面。\n若您選擇不自動更新,請檢查有沒有[[Special:DoubleRedirects|雙重重定向]]或[[Special:BrokenRedirects|損壞的重定向]]需要修正。\n您有責任讓連結繼續指向正確的地方。\n\n請注意,若新的頁面名稱已經被使用,則此頁面將<strong>不會</strong>移動至該處,除非新名稱下是個重定向頁面而且沒有任何編輯記錄。\n即是說,您可以將錯誤移動至其他名稱的頁面還原到原有名稱,但不能覆蓋任何現有的頁面。\n\n<strong>警告!</strong>\n這個動作對受歡迎的頁面來說可能是重大而唐突的更改;\n在行動前請先確認您了解移動可能帶來的後果。",
+       "movepagetext": "以下表格可以用來重新命名頁面,並將該頁面的所有歷史記錄一併移至擁有新名稱的頁面。\n舊標題的頁面將會變成重新導向頁面,指向使用新標題的頁面。\n您可以選擇自動更新所有指向舊頁面的重新導向,讓它們改為指向新頁面。\n若您選擇不自動更新,請檢查有沒有[[Special:DoubleRedirects|雙重重新導向]]或[[Special:BrokenRedirects|損壞的重新導向]]需要修正。\n您有責任讓連結繼續指向正確的地方。\n\n請注意,若新的頁面名稱已經被使用,則此頁面將<strong>不會</strong>移動至該處,除非新名稱下是個重新導向頁面而且沒有任何編輯記錄。\n即是說,您可以將錯誤移動至其他名稱的頁面還原到原有名稱,但不能覆蓋任何現有的頁面。\n\n<strong>警告!</strong>\n這個動作對受歡迎的頁面來說可能是重大而唐突的更改;\n在行動前請先確認您了解移動可能帶來的後果。",
        "movepagetext-noredirectfixer": "以下表格可以用來重新命名頁面,並將該頁面的所有歷史記錄一併移至擁有新名稱的頁面。\n舊標題的頁面將會變成重新導向頁面,指向使用新標題的頁面。\n請檢查有沒有[[Special:DoubleRedirects|雙重重新導向]]或[[Special:BrokenRedirects|損壞的重新導向]]需要修正。\n您有責任讓連結繼續指向正確的地方。\n\n請注意,若新的頁面名稱已經被使用,則此頁面將<strong>不會</strong>移動至該處,除非新名稱下是個重新導向頁面而且沒有任何編輯記錄。\n即是說,您可以將錯誤移動至其他名稱的頁面還原到原有名稱,但不能覆蓋任何現有的頁面。\n\n<strong>警告!</strong>\n這個動作對受歡迎的頁面來說可能是重大而唐突的更改;\n在行動前請先確認您了解移動可能帶來的後果。",
        "movepagetalktext": "相關的的對話頁面 (如果有的話) 會自動與該頁面一起移動,<strong>除非:</strong>\n*新的名稱已有一個存在的對話頁面,或\n*您未勾選此核選方塊。\n\n在上述情況下,若有必要您必須手動移動或合併已存在的頁面。",
        "movearticle": "移動頁面:",
        "movepagebtn": "移動頁面",
        "pagemovedsub": "移動成功",
        "movepage-moved": "<strong>已移動 \"$1\" 至 \"$2\"</strong>",
-       "movepage-moved-redirect": "已建立重向頁面。",
-       "movepage-moved-noredirect": "已禁止建立重向頁面。",
+       "movepage-moved-redirect": "已建立重新導向頁面。",
+       "movepage-moved-noredirect": "已禁止建立重新導向頁面。",
        "articleexists": "該頁面名稱已存在,或您選擇的名稱無效。\n請改選擇其他名稱。",
        "cantmove-titleprotected": "您選擇的新標題已被禁止使用,您不可移動頁面到該位置。",
        "movetalk": "移動相關的對話頁面",
        "nonfile-cannot-move-to-file": "不可以移動非檔案到檔案命名空間",
        "imagetypemismatch": "新的檔案副檔名不符合該檔案的類型",
        "imageinvalidfilename": "目標檔案名稱無效",
-       "fix-double-redirects": "更新所有指向原標題的重定向",
-       "move-leave-redirect": "留下重向頁面",
+       "fix-double-redirects": "更新所有指向原標題的重新導向頁面",
+       "move-leave-redirect": "留下重新導向頁面",
        "protectedpagemovewarning": "<strong>警告:</strong>本頁已經被保護,只有擁有管理員權限的使用者才可移動。\n以下提供最近的日誌以便參考:",
        "semiprotectedpagemovewarning": "<strong>注意:</strong>本頁已經被保護,只有已註冊的使用者才可移動。\n以下提供最近的日誌以便參考:",
        "move-over-sharedrepo": "== 檔案已存在 ==\n[[:$1]] 已存在於共用檔案庫,將檔案移動到此標題會覆蓋該共用檔案。",
        "tooltip-pt-userpage": "您的使用者頁面",
        "tooltip-pt-anonuserpage": "您編輯使用的 IP 位址所對應的使用者頁面",
        "tooltip-pt-mytalk": "您的對話頁面",
-       "tooltip-pt-anontalk": "對於來自此IP地址編輯的對話",
+       "tooltip-pt-anontalk": "對於來自此 IP 位址編輯的對話",
        "tooltip-pt-preferences": "您的偏好設定",
        "tooltip-pt-watchlist": "您監視變更頁面清單",
        "tooltip-pt-mycontris": "您的貢獻清單",
        "tooltip-feed-rss": "訂閱此頁面的 RSS feed",
        "tooltip-feed-atom": "訂閱此頁面的 Atom feed",
        "tooltip-t-contributions": "此使用者的貢獻清單",
-       "tooltip-t-emailuser": "送電子郵件給這個使用者",
+       "tooltip-t-emailuser": "送電子郵件給這個使用者",
        "tooltip-t-upload": "上傳檔案",
        "tooltip-t-specialpages": "全部特殊頁面的列表",
        "tooltip-t-print": "此頁面的可列印版本",
        "pageinfo-views": "檢視次數",
        "pageinfo-watchers": "頁面監視者數",
        "pageinfo-few-watchers": "少於 $1 名監視者",
-       "pageinfo-redirects-name": "指向此頁面的重定向數量",
+       "pageinfo-redirects-name": "指向此頁面的重新導向頁面數量",
        "pageinfo-subpages-name": "此頁面的子頁面",
-       "pageinfo-subpages-value": "$1($2 個重定向頁面; $3 個非重定向頁面)",
-       "pageinfo-firstuser": "頁面建立者",
-       "pageinfo-firsttime": "é \81é\9d¢å\89µå»º日期",
+       "pageinfo-subpages-value": "$1 ($2 個重新導向頁面; $3 個非重新導向頁面)",
+       "pageinfo-firstuser": "頁面建立者",
+       "pageinfo-firsttime": "é \81é\9d¢å»ºç«\8b日期",
        "pageinfo-lastuser": "最近編輯者",
-       "pageinfo-lasttime": "最編輯日期",
+       "pageinfo-lasttime": "最編輯日期",
        "pageinfo-edits": "編輯總次數",
        "pageinfo-authors": "作者總數",
        "pageinfo-recent-edits": "最近編輯次數 (過去$1內)",
-       "pageinfo-recent-authors": "最近作者數",
+       "pageinfo-recent-authors": "最近作者數",
        "pageinfo-magic-words": "魔術{{PLURAL:$1|字}} ($1)",
        "pageinfo-hidden-categories": "隱藏{{PLURAL:$1|分類}} ($1)",
-       "pageinfo-templates": "引用樣版 ($1)",
+       "pageinfo-templates": "引用樣版 ($1)",
        "pageinfo-transclusions": "頁面被引用於 ($1)",
        "pageinfo-toolboxlink": "頁面資訊",
-       "pageinfo-redirectsto": "重向至",
+       "pageinfo-redirectsto": "重新導向至",
        "pageinfo-redirectsto-info": "資訊",
        "pageinfo-contentpage": "作為內容頁面計算",
        "pageinfo-contentpage-yes": "是",
        "monthsall": "全部",
        "confirmemail": "確認郵箱位址",
        "confirmemail_noemail": "您尚未於 [[Special:Preferences|偏好設定]] 輸入一個有效的電子郵件地址。",
-       "confirmemail_text": "{{SITENAME}}要求您在使用郵件功能之前驗證您的郵箱位址。\n點擊以下按鈕可向您的郵箱發送一封確認郵件。該郵件包含有一行代碼連結;\n請在您的瀏覽器中加載此連結以確認您的郵箱位址是有效的。",
+       "confirmemail_text": "{{SITENAME}}要求您在使用郵件功能之前驗證您的郵箱位址。\n點選以下按鈕可向您的郵箱發送一封確認郵件。該郵件包含有一行代碼連結;\n請在您的瀏覽器中載入此連結以確認您的郵箱位址是有效的。",
        "confirmemail_pending": "確認碼已發送至您的電子郵件,\n若您才剛建立好您的帳號,可能需要稍後幾分鐘才能收到。\n若沒有收到,請再重新申請一次確認碼。",
        "confirmemail_send": "郵發確認代碼",
        "confirmemail_sent": "確認郵件已發送。",
        "scarytranscludedisabled": "[Interwiki 轉換代碼不可用]",
        "scarytranscludefailed": "[樣版 $1 讀取失敗]",
        "scarytranscludefailed-httpstatus": "[樣版 $1 讀取失敗:HTTP $2]",
-       "scarytranscludetoolong": "[URL 址太長]",
+       "scarytranscludetoolong": "[URL 址太長]",
        "deletedwhileediting": "<strong>警告:</strong>此頁在您開始編輯之後已經被刪除﹗",
        "confirmrecreate": "在您編輯的同時,使用者 [[User:$1|$1]] ([[User talk:$1|對話]]) 刪除了此頁面,原因為:\n: <em>$2</em>\n請確認您是否真的要重新建立此頁面。",
        "confirmrecreate-noreason": "在您編輯的同時,使用者 [[User:$1|$1]] ([[User talk:$1|對話]]) 刪除了此頁面,請確認您是否真的要重新建立此頁面。",
        "table_pager_empty": "沒有結果",
        "autosumm-blank": "清空頁面",
        "autosumm-replace": "使用 \"$1\" 取代內容",
-       "autoredircomment": "頁面已重向至 [[$1]]",
+       "autoredircomment": "頁面已重新導向至 [[$1]]",
        "autosumm-new": "已建立頁面,內容為 \"$1\"",
        "size-bytes": "$1 位元組",
        "lag-warn-normal": "此清單可能不會顯示最近 $1 {{PLURAL:$1|秒}}內的變更。",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|對話]])",
        "unknown_extension_tag": "不明的擴充標籤 \"$1\"",
        "duplicate-defaultsort": "<strong>警告:</strong>預設的排序鍵 \"$2\" 會覆蓋先前預設的排序鍵 \"$1\"。",
+       "duplicate-displaytitle": "<strong>警告:</strong> 顯示標題 \"$2\" 覆蓋之前的顯示標題 \"$1\"。",
        "version": "版本",
        "version-extensions": "已安裝的擴充套件",
-       "version-skins": "已外觀",
+       "version-skins": "已安裝的外觀",
        "version-specialpages": "特殊頁面",
        "version-parserhooks": "語法連結(Hook)",
        "version-variables": "變數",
        "version-entrypoints": "入口 URL",
        "version-entrypoints-header-entrypoint": "入口",
        "version-entrypoints-header-url": "URL",
-       "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath 條目路徑]",
-       "redirect": "指向檔案、使用者、頁面或修訂 ID 的重定向",
-       "redirect-legend": "重定向至檔案或頁面",
-       "redirect-summary": "此特殊頁面可用來建立重定向,指向任何檔案(指定檔案名)、頁面(指定修訂 ID 或頁面 ID)或使用者頁面(指定使用者 ID)。用法:[[{{#Special:Redirect}}/file/Example.jpg]]、[[{{#Special:Redirect}}/page/64308]]、[[{{#Special:Redirect}}/revision/328429]] 或 [[{{#Special:Redirect}}/user/101]]。",
+       "version-entrypoints-articlepath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgArticlePath 文章路徑]",
+       "version-entrypoints-scriptpath": "[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgScriptPath Script 路徑]",
+       "redirect": "重新導向至檔案、使用者、頁面或修訂 ID",
+       "redirect-legend": "重新導向至檔案或頁面",
+       "redirect-summary": "此特殊頁面可用來重新導向至檔案 (指定檔案名稱)、頁面 (指定修訂 ID 或頁面 ID) 或使用者頁面 (指定使用者 ID)。用法:[[{{#Special:Redirect}}/file/Example.jpg]]、[[{{#Special:Redirect}}/page/64308]]、[[{{#Special:Redirect}}/revision/328429]] 或 [[{{#Special:Redirect}}/user/101]]。",
        "redirect-submit": "執行",
        "redirect-lookup": "尋找:",
        "redirect-value": "值:",
        "specialpages-group-pages": "頁面清單",
        "specialpages-group-pagetools": "頁面工具",
        "specialpages-group-wiki": "資料和工具",
-       "specialpages-group-redirects": "重定向到別處的特殊頁面",
+       "specialpages-group-redirects": "重新導向相關特殊頁面",
        "specialpages-group-spam": "反垃圾訊息工具",
        "blankpage": "空白頁面",
        "intentionallyblankpage": "此頁面被故意設為空白。",
        "htmlform-int-toolow": "您所指定的值低於最小值$1",
        "htmlform-int-toohigh": "您所指定的值高於最大值$1",
        "htmlform-required": "此值是必填項",
-       "htmlform-submit": "提交",
+       "htmlform-submit": "送出",
        "htmlform-reset": "還原更改",
        "htmlform-selectorother-other": "其他",
        "htmlform-no": "否",
        "revdelete-restricted": "已套用對管理員的限制",
        "revdelete-unrestricted": "已移除對管理員的限制",
        "logentry-move-move": "$1 {{GENDER:$2|已移動}}頁面 $3 至 $4",
-       "logentry-move-move-noredirect": "$1 已移動頁面 $3 至 $4,不留重定向",
-       "logentry-move-move_redir": "$1 已移動頁面 $3 至 $4 並覆蓋原有重向",
-       "logentry-move-move_redir-noredirect": "$1 已移動頁面 $3 至 $4 並覆蓋原有重定向,不留重定向",
+       "logentry-move-move-noredirect": "$1 已移動頁面 $3 至 $4,不留重新導向頁面",
+       "logentry-move-move_redir": "$1 已移動頁面 $3 至 $4 並覆蓋原有重新導向",
+       "logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|已移動}}頁面 $3 覆蓋重新導向頁面至 $4,未留重新導向頁面",
        "logentry-patrol-patrol": "$1 {{GENDER:$2|已標記}}頁面 $3 的修訂 $4 為已巡查",
        "logentry-patrol-patrol-auto": "$1 已自動{{GENDER:$2|標記}}頁面 $3 的修訂 $4 為已巡查",
        "logentry-newusers-newusers": "已{{GENDER:$2|建立}}使用者帳號 $1",
        "feedback-subject": "主旨:",
        "feedback-message": "訊息:",
        "feedback-cancel": "取消",
-       "feedback-submit": "提交反饋",
+       "feedback-submit": "送出回饋",
        "feedback-adding": "正在頁面添加反饋...",
        "feedback-error1": "錯誤:從API返回無法識別的結果",
        "feedback-error2": "錯誤:編輯失敗",
        "api-error-badaccess-groups": "您沒有權限在此 Wiki 上傳檔案。",
        "api-error-badtoken": "內部錯誤:標記無效。",
        "api-error-copyuploaddisabled": "通過URL上傳的功能已被此伺服器禁用。",
-       "api-error-duplicate": "å\9c¨ç¶²ç«\99ä¸\8aå·²ç¶\93å\85·æ\9c\89ç\9b¸å\90\8cå\85§å®¹ç\9a\84{{PLURAL:$1|[$2 å\8f¦ä¸\80å\80\8bæ\96\87件]|[$2 å\8f¦ä¸\80äº\9bæ\96\87件]}}。",
-       "api-error-duplicate-archive": "å\9c¨ç¶²ç«\99ä¸\8aæ\9b¾ç¶\93å\85·æ\9c\89ç\9b¸å\90\8cå\85§å®¹ç\9a\84{{PLURAL:$1|[$2 å\8f¦ä¸\80å\80\8bæ\96\87件]|[$2 å\8f¦ä¸\80äº\9bæ\96\87件]}},但已被刪除。",
+       "api-error-duplicate": "å\9c¨ç¶²ç«\99ä¸\8aå·²ç¶\93å\85·æ\9c\89ç\9b¸å\90\8cå\85§å®¹ç\9a\84{{PLURAL:$1|[$2 å\8f¦ä¸\80å\80\8bæª\94æ¡\88]|[$2 å\8f¦ä¸\80äº\9bæª\94æ¡\88]}}。",
+       "api-error-duplicate-archive": "å\9c¨ç¶²ç«\99ä¸\8aæ\9b¾ç¶\93å\85·æ\9c\89ç\9b¸å\90\8cå\85§å®¹ç\9a\84{{PLURAL:$1|[$2 å\8f¦ä¸\80å\80\8bæª\94æ¡\88]|[$2 å\8f¦ä¸\80äº\9bæª\94æ¡\88]}},但已被刪除。",
        "api-error-duplicate-archive-popup-title": "已被刪除的重複{{PLURAL:$1|文件}}。",
-       "api-error-duplicate-popup-title": "é\87\8dè¤\87ç\9a\84{{PLURAL:$1|æ\96\87件}}。",
+       "api-error-duplicate-popup-title": "é\87\8dè¤\87ç\9a\84{{PLURAL:$1|æª\94æ¡\88}}。",
        "api-error-empty-file": "您提交的檔案是空的。",
        "api-error-emptypage": "不許創建沒有內容的新頁面。",
-       "api-error-fetchfileerror": "å\85§é\83¨é\8c¯èª¤ï¼\9aç\8d²å\8f\96æ\96\87件時發生錯誤。",
+       "api-error-fetchfileerror": "å\85§é\83¨é\8c¯èª¤ï¼\9aç\8d²å\8f\96æª\94æ¡\88時發生錯誤。",
        "api-error-fileexists-forbidden": "以\" $1 \"命名的檔案已經存在,並且不能被重寫。",
        "api-error-fileexists-shared-forbidden": "以\" $1 \"命名的檔案已經存在於共用檔案儲存庫上,並且不能被重寫。",
        "api-error-file-too-large": "您提交的檔案太大了。",
        "api-error-invalid-file-key": "內部錯誤:於臨時儲存庫中查無檔案。",
        "api-error-missingparam": "內部錯誤:請求中缺少參數。",
        "api-error-missingresult": "內部錯誤:無法確定複製是否成功。",
-       "api-error-mustbeloggedin": "您必須登錄後再上傳文件。",
+       "api-error-mustbeloggedin": "您必須登入後再上傳檔案。",
        "api-error-mustbeposted": "內部錯誤:請求需要 HTTP POST。",
-       "api-error-noimageinfo": "文件成功,但伺服器沒有給我們任何該文件的信息。",
+       "api-error-noimageinfo": "上傳成功,但伺服器沒有給我們任何該檔案的資訊。",
        "api-error-nomodule": "內部錯誤:缺少上傳模塊集。",
        "api-error-ok-but-empty": "內部錯誤:伺服器沒有響應。",
        "api-error-overwrite": "不允許覆蓋現有檔案。",
        "api-error-stashfailed": "內部錯誤:伺服器保存臨時檔案失敗。",
        "api-error-publishfailed": "內部錯誤:伺服器發佈臨時檔案失敗。",
-       "api-error-stasherror": "上檔案存檔時出錯。",
+       "api-error-stasherror": "上檔案存檔時出錯。",
        "api-error-timeout": "伺服器沒有在預期的時間內回應。",
        "api-error-unclassified": "發生未知錯誤。",
        "api-error-unknown-code": "未知錯誤:$1",
-       "api-error-unknown-error": "å\85§é\83¨é\8c¯èª¤ï¼\9aå\98\97試ä¸\8aå\82³æ\96\87件時出錯。",
+       "api-error-unknown-error": "å\85§é\83¨é\8c¯èª¤ï¼\9aå\98\97試ä¸\8aå\82³æª\94æ¡\88時出錯。",
        "api-error-unknown-warning": "未知的警告:$1",
        "api-error-unknownerror": "未知錯誤:$1。",
        "api-error-uploaddisabled": "本wiki的上傳檔案功能已停用。",
index 3729a78..1618bdb 100644 (file)
@@ -57,43 +57,43 @@ $namespaceAliases = array(
 $namespaceGenderAliases = array();
 
 $datePreferences = array(
-    'default',
-    'mdy',
-    'dmy',
-    'ymd',
-    'yyyy-mm-dd',
-    'ISO 8601',
+       'default',
+       'mdy',
+       'dmy',
+       'ymd',
+       'yyyy-mm-dd',
+       'ISO 8601',
 );
 
 $defaultDateFormat = 'ymd';
 
 $datePreferenceMigrationMap = array(
-    'default',
-    'mdy',
-    'dmy',
-    'ymd'
+       'default',
+       'mdy',
+       'dmy',
+       'ymd'
 );
 
 $dateFormats = array(
-    'mdy time' => 'H:i',
-    'mdy date' => 'F j Y "с."',
-    'mdy both' => 'H:i, F j Y "с."',
+       'mdy time' => 'H:i',
+       'mdy date' => 'F j Y "с."',
+       'mdy both' => 'H:i, F j Y "с."',
 
-    'dmy time' => 'H:i',
-    'dmy date' => 'j F Y "с."',
-    'dmy both' => 'H:i, j F Y "с."',
+       'dmy time' => 'H:i',
+       'dmy date' => 'j F Y "с."',
+       'dmy both' => 'H:i, j F Y "с."',
 
-    'ymd time' => 'H:i',
-    'ymd date' => 'Y "с." xg j',
-    'ymd both' => 'H:i, Y "с." xg j',
+       'ymd time' => 'H:i',
+       'ymd date' => 'Y "с." xg j',
+       'ymd both' => 'H:i, Y "с." xg j',
 
-    'yyyy-mm-dd time' => 'xnH:xni:xns',
-    'yyyy-mm-dd date' => 'xnY-xnm-xnd',
-    'yyyy-mm-dd both' => 'xnH:xni:xns, xnY-xnm-xnd',
+       'yyyy-mm-dd time' => 'xnH:xni:xns',
+       'yyyy-mm-dd date' => 'xnY-xnm-xnd',
+       'yyyy-mm-dd both' => 'xnH:xni:xns, xnY-xnm-xnd',
 
-    'ISO 8601 time' => 'xnH:xni:xns',
-    'ISO 8601 date' => 'xnY.xnm.xnd',
-    'ISO 8601 both' => 'xnY.xnm.xnd"T"xnH:xni:xns',
+       'ISO 8601 time' => 'xnH:xni:xns',
+       'ISO 8601 date' => 'xnY.xnm.xnd',
+       'ISO 8601 both' => 'xnY.xnm.xnd"T"xnH:xni:xns',
 );
 
 $separatorTransformTable = array( ','  => '.', '.' => ',' );
index 7fb5df0..6b852b7 100644 (file)
@@ -52,43 +52,43 @@ $namespaceAliases = array(
 );
 
 $datePreferences = array(
-    'default',
-    'mdy',
-    'dmy',
-    'ymd',
-    'yyyy-mm-dd',
-    'ISO 8601',
+       'default',
+       'mdy',
+       'dmy',
+       'ymd',
+       'yyyy-mm-dd',
+       'ISO 8601',
 );
 
 $defaultDateFormat = 'ymd';
 
 $datePreferenceMigrationMap = array(
-    'default',
-    'mdy',
-    'dmy',
-    'ymd'
+       'default',
+       'mdy',
+       'dmy',
+       'ymd'
 );
 
 $dateFormats = array(
-    'mdy time' => 'H:i',
-    'mdy date' => 'F j Y "s."',
-    'mdy both' => 'H:i, F j Y "s."',
+       'mdy time' => 'H:i',
+       'mdy date' => 'F j Y "s."',
+       'mdy both' => 'H:i, F j Y "s."',
 
-    'dmy time' => 'H:i',
-    'dmy date' => 'j F Y "s."',
-    'dmy both' => 'H:i, j F Y "s."',
+       'dmy time' => 'H:i',
+       'dmy date' => 'j F Y "s."',
+       'dmy both' => 'H:i, j F Y "s."',
 
-    'ymd time' => 'H:i',
-    'ymd date' => 'Y "s." xg j',
-    'ymd both' => 'H:i, Y "s." xg j',
+       'ymd time' => 'H:i',
+       'ymd date' => 'Y "s." xg j',
+       'ymd both' => 'H:i, Y "s." xg j',
 
-    'yyyy-mm-dd time' => 'xnH:xni:xns',
-    'yyyy-mm-dd date' => 'xnY-xnm-xnd',
-    'yyyy-mm-dd both' => 'xnH:xni:xns, xnY-xnm-xnd',
+       'yyyy-mm-dd time' => 'xnH:xni:xns',
+       'yyyy-mm-dd date' => 'xnY-xnm-xnd',
+       'yyyy-mm-dd both' => 'xnH:xni:xns, xnY-xnm-xnd',
 
-    'ISO 8601 time' => 'xnH:xni:xns',
-    'ISO 8601 date' => 'xnY.xnm.xnd',
-    'ISO 8601 both' => 'xnY.xnm.xnd"T"xnH:xni:xns',
+       'ISO 8601 time' => 'xnH:xni:xns',
+       'ISO 8601 date' => 'xnY.xnm.xnd',
+       'ISO 8601 both' => 'xnY.xnm.xnd"T"xnH:xni:xns',
 );
 
 $separatorTransformTable = array( ',' => '.', '.' => ',' );
index 2718a48..b796aca 100644 (file)
@@ -261,7 +261,7 @@ $magicWords = array(
  * Date formats list for Special:Preferences
  * see $dateFormats for definitions
  */
-$datePreferences =  array(
+$datePreferences = array(
        'ČSN basic dt',
        'ČSN padded dt',
        'ČSN basic td',
index 4cffd2b..d6f268f 100644 (file)
@@ -35,8 +35,8 @@ $namespaceAliases = array(
 );
 
 $namespaceGenderAliases = array(
-        NS_USER => array( 'male' => 'Wužywaŕ', 'female' => 'Wužywarka' ),
-        NS_USER_TALK => array( 'male' => 'Diskusija_wužywarja', 'female' => 'Diskusija_wužywarki' ),
+       NS_USER => array( 'male' => 'Wužywaŕ', 'female' => 'Wužywarka' ),
+       NS_USER_TALK => array( 'male' => 'Diskusija_wužywarja', 'female' => 'Diskusija_wužywarki' ),
 );
 
 $specialPageAliases = array(
index 6900aeb..17a18c1 100644 (file)
@@ -202,173 +202,175 @@ $bookstoreList = array(
  * This array can be modified at runtime with the LanguageGetMagic hook
  */
 $magicWords = array(
-#   ID                                  CASE  SYNONYMS
-       'redirect'                => array( 0,    '#REDIRECT' ),
-       'notoc'                   => array( 0,    '__NOTOC__' ),
-       'nogallery'               => array( 0,    '__NOGALLERY__' ),
-       'forcetoc'                => array( 0,    '__FORCETOC__' ),
-       'toc'                     => array( 0,    '__TOC__' ),
-       'noeditsection'           => array( 0,    '__NOEDITSECTION__' ),
-       '!'                       => array( 1,    '!' ),
-       'currentmonth'            => array( 1,    'CURRENTMONTH', 'CURRENTMONTH2' ),
-       'currentmonth1'           => array( 1,    'CURRENTMONTH1' ),
-       'currentmonthname'        => array( 1,    'CURRENTMONTHNAME' ),
-       'currentmonthnamegen'     => array( 1,    'CURRENTMONTHNAMEGEN' ),
-       'currentmonthabbrev'      => array( 1,    'CURRENTMONTHABBREV' ),
-       'currentday'              => array( 1,    'CURRENTDAY' ),
-       'currentday2'             => array( 1,    'CURRENTDAY2' ),
-       'currentdayname'          => array( 1,    'CURRENTDAYNAME' ),
-       'currentyear'             => array( 1,    'CURRENTYEAR' ),
-       'currenttime'             => array( 1,    'CURRENTTIME' ),
-       'currenthour'             => array( 1,    'CURRENTHOUR' ),
-       'localmonth'              => array( 1,    'LOCALMONTH', 'LOCALMONTH2' ),
-       'localmonth1'             => array( 1,    'LOCALMONTH1' ),
-       'localmonthname'          => array( 1,    'LOCALMONTHNAME' ),
-       'localmonthnamegen'       => array( 1,    'LOCALMONTHNAMEGEN' ),
-       'localmonthabbrev'        => array( 1,    'LOCALMONTHABBREV' ),
-       'localday'                => array( 1,    'LOCALDAY' ),
-       'localday2'               => array( 1,    'LOCALDAY2' ),
-       'localdayname'            => array( 1,    'LOCALDAYNAME' ),
-       'localyear'               => array( 1,    'LOCALYEAR' ),
-       'localtime'               => array( 1,    'LOCALTIME' ),
-       'localhour'               => array( 1,    'LOCALHOUR' ),
-       'numberofpages'           => array( 1,    'NUMBEROFPAGES' ),
-       'numberofarticles'        => array( 1,    'NUMBEROFARTICLES' ),
-       'numberoffiles'           => array( 1,    'NUMBEROFFILES' ),
-       'numberofusers'           => array( 1,    'NUMBEROFUSERS' ),
-       'numberofactiveusers'     => array( 1,    'NUMBEROFACTIVEUSERS' ),
-       'numberofedits'           => array( 1,    'NUMBEROFEDITS' ),
-       'numberofviews'           => array( 1,    'NUMBEROFVIEWS' ),
-       'pagename'                => array( 1,    'PAGENAME' ),
-       'pagenamee'               => array( 1,    'PAGENAMEE' ),
-       'namespace'               => array( 1,    'NAMESPACE' ),
-       'namespacee'              => array( 1,    'NAMESPACEE' ),
-       'namespacenumber'         => array( 1,    'NAMESPACENUMBER' ),
-       'talkspace'               => array( 1,    'TALKSPACE' ),
-       'talkspacee'              => array( 1,    'TALKSPACEE' ),
-       'subjectspace'            => array( 1,    'SUBJECTSPACE', 'ARTICLESPACE' ),
-       'subjectspacee'           => array( 1,    'SUBJECTSPACEE', 'ARTICLESPACEE' ),
-       'fullpagename'            => array( 1,    'FULLPAGENAME' ),
-       'fullpagenamee'           => array( 1,    'FULLPAGENAMEE' ),
-       'subpagename'             => array( 1,    'SUBPAGENAME' ),
-       'subpagenamee'            => array( 1,    'SUBPAGENAMEE' ),
-       'rootpagename'            => array( 1,    'ROOTPAGENAME' ),
-       'rootpagenamee'           => array( 1,    'ROOTPAGENAMEE' ),
-       'basepagename'            => array( 1,    'BASEPAGENAME' ),
-       'basepagenamee'           => array( 1,    'BASEPAGENAMEE' ),
-       'talkpagename'            => array( 1,    'TALKPAGENAME' ),
-       'talkpagenamee'           => array( 1,    'TALKPAGENAMEE' ),
-       'subjectpagename'         => array( 1,    'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ),
-       'subjectpagenamee'        => array( 1,    'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ),
-       'msg'                     => array( 0,    'MSG:' ),
-       'subst'                   => array( 0,    'SUBST:' ),
-       'safesubst'               => array( 0,    'SAFESUBST:' ),
-       'msgnw'                   => array( 0,    'MSGNW:' ),
-       'img_thumbnail'           => array( 1,    'thumbnail', 'thumb' ),
-       'img_manualthumb'         => array( 1,    'thumbnail=$1', 'thumb=$1' ),
-       'img_right'               => array( 1,    'right' ),
-       'img_left'                => array( 1,    'left' ),
-       'img_none'                => array( 1,    'none' ),
-       'img_width'               => array( 1,    '$1px' ),
-       'img_center'              => array( 1,    'center', 'centre' ),
-       'img_framed'              => array( 1,    'framed', 'enframed', 'frame' ),
-       'img_frameless'           => array( 1,    'frameless' ),
-       'img_lang'                => array( 1,    'lang=$1' ),
-       'img_page'                => array( 1,    'page=$1', 'page $1' ),
-       'img_upright'             => array( 1,    'upright', 'upright=$1', 'upright $1' ),
-       'img_border'              => array( 1,    'border' ),
-       'img_baseline'            => array( 1,    'baseline' ),
-       'img_sub'                 => array( 1,    'sub' ),
-       'img_super'               => array( 1,    'super', 'sup' ),
-       'img_top'                 => array( 1,    'top' ),
-       'img_text_top'            => array( 1,    'text-top' ),
-       'img_middle'              => array( 1,    'middle' ),
-       'img_bottom'              => array( 1,    'bottom' ),
-       'img_text_bottom'         => array( 1,    'text-bottom' ),
-       'img_link'                => array( 1,    'link=$1' ),
-       'img_alt'                 => array( 1,    'alt=$1' ),
-       'img_class'               => array( 1,    'class=$1' ),
-       'int'                     => array( 0,    'INT:' ),
-       'sitename'                => array( 1,    'SITENAME' ),
-       'ns'                      => array( 0,    'NS:' ),
-       'nse'                     => array( 0,    'NSE:' ),
-       'localurl'                => array( 0,    'LOCALURL:' ),
-       'localurle'               => array( 0,    'LOCALURLE:' ),
-       'articlepath'             => array( 0,    'ARTICLEPATH' ),
-       'pageid'                  => array( 0,    'PAGEID' ),
-       'server'                  => array( 0,    'SERVER' ),
-       'servername'              => array( 0,    'SERVERNAME' ),
-       'scriptpath'              => array( 0,    'SCRIPTPATH' ),
-       'stylepath'               => array( 0,    'STYLEPATH' ),
-       'grammar'                 => array( 0,    'GRAMMAR:' ),
-       'gender'                  => array( 0,    'GENDER:' ),
-       'notitleconvert'          => array( 0,    '__NOTITLECONVERT__', '__NOTC__' ),
-       'nocontentconvert'        => array( 0,    '__NOCONTENTCONVERT__', '__NOCC__' ),
-       'currentweek'             => array( 1,    'CURRENTWEEK' ),
-       'currentdow'              => array( 1,    'CURRENTDOW' ),
-       'localweek'               => array( 1,    'LOCALWEEK' ),
-       'localdow'                => array( 1,    'LOCALDOW' ),
-       'revisionid'              => array( 1,    'REVISIONID' ),
-       'revisionday'             => array( 1,    'REVISIONDAY' ),
-       'revisionday2'            => array( 1,    'REVISIONDAY2' ),
-       'revisionmonth'           => array( 1,    'REVISIONMONTH' ),
-       'revisionmonth1'          => array( 1,    'REVISIONMONTH1' ),
-       'revisionyear'            => array( 1,    'REVISIONYEAR' ),
-       'revisiontimestamp'       => array( 1,    'REVISIONTIMESTAMP' ),
-       'revisionuser'            => array( 1,    'REVISIONUSER' ),
-       'revisionsize'            => array( 1,    'REVISIONSIZE' ),
-       'plural'                  => array( 0,    'PLURAL:' ),
-       'fullurl'                 => array( 0,    'FULLURL:' ),
-       'fullurle'                => array( 0,    'FULLURLE:' ),
-       'canonicalurl'            => array( 0,    'CANONICALURL:' ),
-       'canonicalurle'           => array( 0,    'CANONICALURLE:' ),
-       'lcfirst'                 => array( 0,    'LCFIRST:' ),
-       'ucfirst'                 => array( 0,    'UCFIRST:' ),
-       'lc'                      => array( 0,    'LC:' ),
-       'uc'                      => array( 0,    'UC:' ),
-       'raw'                     => array( 0,    'RAW:' ),
-       'displaytitle'            => array( 1,    'DISPLAYTITLE' ),
-       'rawsuffix'               => array( 1,    'R' ),
-       'nocommafysuffix'         => array( 0,    'NOSEP' ),
-       'newsectionlink'          => array( 1,    '__NEWSECTIONLINK__' ),
-       'nonewsectionlink'        => array( 1,    '__NONEWSECTIONLINK__' ),
-       'currentversion'          => array( 1,    'CURRENTVERSION' ),
-       'urlencode'               => array( 0,    'URLENCODE:' ),
-       'anchorencode'            => array( 0,    'ANCHORENCODE' ),
-       'currenttimestamp'        => array( 1,    'CURRENTTIMESTAMP' ),
-       'localtimestamp'          => array( 1,    'LOCALTIMESTAMP' ),
-       'directionmark'           => array( 1,    'DIRECTIONMARK', 'DIRMARK' ),
-       'language'                => array( 0,    '#LANGUAGE:' ),
-       'contentlanguage'         => array( 1,    'CONTENTLANGUAGE', 'CONTENTLANG' ),
-       'pagesinnamespace'        => array( 1,    'PAGESINNAMESPACE:', 'PAGESINNS:' ),
-       'numberofadmins'          => array( 1,    'NUMBEROFADMINS' ),
-       'formatnum'               => array( 0,    'FORMATNUM' ),
-       'padleft'                 => array( 0,    'PADLEFT' ),
-       'padright'                => array( 0,    'PADRIGHT' ),
-       'special'                 => array( 0,    'special' ),
-       'speciale'                => array( 0,    'speciale' ),
-       'defaultsort'             => array( 1,    'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ),
-       'filepath'                => array( 0,    'FILEPATH:' ),
-       'tag'                     => array( 0,    'tag' ),
-       'hiddencat'               => array( 1,    '__HIDDENCAT__' ),
-       'pagesincategory'         => array( 1,    'PAGESINCATEGORY', 'PAGESINCAT' ),
-       'pagesize'                => array( 1,    'PAGESIZE' ),
-       'index'                   => array( 1,    '__INDEX__' ),
-       'noindex'                 => array( 1,    '__NOINDEX__' ),
-       'numberingroup'           => array( 1,    'NUMBERINGROUP', 'NUMINGROUP' ),
-       'staticredirect'          => array( 1,    '__STATICREDIRECT__' ),
-       'protectionlevel'         => array( 1,    'PROTECTIONLEVEL' ),
-       'cascadingsources'        => array( 1,    'CASCADINGSOURCES' ),
-       'formatdate'              => array( 0,    'formatdate', 'dateformat' ),
-       'url_path'                => array( 0,    'PATH' ),
-       'url_wiki'                => array( 0,    'WIKI' ),
-       'url_query'               => array( 0,    'QUERY' ),
-       'defaultsort_noerror'     => array( 0,    'noerror' ),
-       'defaultsort_noreplace'   => array( 0,    'noreplace' ),
-       'pagesincategory_all'     => array( 0,    'all' ),
-       'pagesincategory_pages'   => array( 0,    'pages' ),
-       'pagesincategory_subcats' => array( 0,    'subcats' ),
-       'pagesincategory_files'   => array( 0,    'files' ),
+#   ID                               CASE  SYNONYMS
+       'redirect'                => array( 0, '#REDIRECT' ),
+       'notoc'                   => array( 0, '__NOTOC__' ),
+       'nogallery'               => array( 0, '__NOGALLERY__' ),
+       'forcetoc'                => array( 0, '__FORCETOC__' ),
+       'toc'                     => array( 0, '__TOC__' ),
+       'noeditsection'           => array( 0, '__NOEDITSECTION__' ),
+       '!'                       => array( 1, '!' ),
+       'currentmonth'            => array( 1, 'CURRENTMONTH', 'CURRENTMONTH2' ),
+       'currentmonth1'           => array( 1, 'CURRENTMONTH1' ),
+       'currentmonthname'        => array( 1, 'CURRENTMONTHNAME' ),
+       'currentmonthnamegen'     => array( 1, 'CURRENTMONTHNAMEGEN' ),
+       'currentmonthabbrev'      => array( 1, 'CURRENTMONTHABBREV' ),
+       'currentday'              => array( 1, 'CURRENTDAY' ),
+       'currentday2'             => array( 1, 'CURRENTDAY2' ),
+       'currentdayname'          => array( 1, 'CURRENTDAYNAME' ),
+       'currentyear'             => array( 1, 'CURRENTYEAR' ),
+       'currenttime'             => array( 1, 'CURRENTTIME' ),
+       'currenthour'             => array( 1, 'CURRENTHOUR' ),
+       'localmonth'              => array( 1, 'LOCALMONTH', 'LOCALMONTH2' ),
+       'localmonth1'             => array( 1, 'LOCALMONTH1' ),
+       'localmonthname'          => array( 1, 'LOCALMONTHNAME' ),
+       'localmonthnamegen'       => array( 1, 'LOCALMONTHNAMEGEN' ),
+       'localmonthabbrev'        => array( 1, 'LOCALMONTHABBREV' ),
+       'localday'                => array( 1, 'LOCALDAY' ),
+       'localday2'               => array( 1, 'LOCALDAY2' ),
+       'localdayname'            => array( 1, 'LOCALDAYNAME' ),
+       'localyear'               => array( 1, 'LOCALYEAR' ),
+       'localtime'               => array( 1, 'LOCALTIME' ),
+       'localhour'               => array( 1, 'LOCALHOUR' ),
+       'numberofpages'           => array( 1, 'NUMBEROFPAGES' ),
+       'numberofarticles'        => array( 1, 'NUMBEROFARTICLES' ),
+       'numberoffiles'           => array( 1, 'NUMBEROFFILES' ),
+       'numberofusers'           => array( 1, 'NUMBEROFUSERS' ),
+       'numberofactiveusers'     => array( 1, 'NUMBEROFACTIVEUSERS' ),
+       'numberofedits'           => array( 1, 'NUMBEROFEDITS' ),
+       'numberofviews'           => array( 1, 'NUMBEROFVIEWS' ),
+       'pagename'                => array( 1, 'PAGENAME' ),
+       'pagenamee'               => array( 1, 'PAGENAMEE' ),
+       'namespace'               => array( 1, 'NAMESPACE' ),
+       'namespacee'              => array( 1, 'NAMESPACEE' ),
+       'namespacenumber'         => array( 1, 'NAMESPACENUMBER' ),
+       'talkspace'               => array( 1, 'TALKSPACE' ),
+       'talkspacee'              => array( 1, 'TALKSPACEE' ),
+       'subjectspace'            => array( 1, 'SUBJECTSPACE', 'ARTICLESPACE' ),
+       'subjectspacee'           => array( 1, 'SUBJECTSPACEE', 'ARTICLESPACEE' ),
+       'fullpagename'            => array( 1, 'FULLPAGENAME' ),
+       'fullpagenamee'           => array( 1, 'FULLPAGENAMEE' ),
+       'subpagename'             => array( 1, 'SUBPAGENAME' ),
+       'subpagenamee'            => array( 1, 'SUBPAGENAMEE' ),
+       'rootpagename'            => array( 1, 'ROOTPAGENAME' ),
+       'rootpagenamee'           => array( 1, 'ROOTPAGENAMEE' ),
+       'basepagename'            => array( 1, 'BASEPAGENAME' ),
+       'basepagenamee'           => array( 1, 'BASEPAGENAMEE' ),
+       'talkpagename'            => array( 1, 'TALKPAGENAME' ),
+       'talkpagenamee'           => array( 1, 'TALKPAGENAMEE' ),
+       'subjectpagename'         => array( 1, 'SUBJECTPAGENAME', 'ARTICLEPAGENAME' ),
+       'subjectpagenamee'        => array( 1, 'SUBJECTPAGENAMEE', 'ARTICLEPAGENAMEE' ),
+       'msg'                     => array( 0, 'MSG:' ),
+       'subst'                   => array( 0, 'SUBST:' ),
+       'safesubst'               => array( 0, 'SAFESUBST:' ),
+       'msgnw'                   => array( 0, 'MSGNW:' ),
+       'img_thumbnail'           => array( 1, 'thumbnail', 'thumb' ),
+       'img_manualthumb'         => array( 1, 'thumbnail=$1', 'thumb=$1' ),
+       'img_right'               => array( 1, 'right' ),
+       'img_left'                => array( 1, 'left' ),
+       'img_none'                => array( 1, 'none' ),
+       'img_width'               => array( 1, '$1px' ),
+       'img_center'              => array( 1, 'center', 'centre' ),
+       'img_framed'              => array( 1, 'framed', 'enframed', 'frame' ),
+       'img_frameless'           => array( 1, 'frameless' ),
+       'img_lang'                => array( 1, 'lang=$1' ),
+       'img_page'                => array( 1, 'page=$1', 'page $1' ),
+       'img_upright'             => array( 1, 'upright', 'upright=$1', 'upright $1' ),
+       'img_border'              => array( 1, 'border' ),
+       'img_baseline'            => array( 1, 'baseline' ),
+       'img_sub'                 => array( 1, 'sub' ),
+       'img_super'               => array( 1, 'super', 'sup' ),
+       'img_top'                 => array( 1, 'top' ),
+       'img_text_top'            => array( 1, 'text-top' ),
+       'img_middle'              => array( 1, 'middle' ),
+       'img_bottom'              => array( 1, 'bottom' ),
+       'img_text_bottom'         => array( 1, 'text-bottom' ),
+       'img_link'                => array( 1, 'link=$1' ),
+       'img_alt'                 => array( 1, 'alt=$1' ),
+       'img_class'               => array( 1, 'class=$1' ),
+       'int'                     => array( 0, 'INT:' ),
+       'sitename'                => array( 1, 'SITENAME' ),
+       'ns'                      => array( 0, 'NS:' ),
+       'nse'                     => array( 0, 'NSE:' ),
+       'localurl'                => array( 0, 'LOCALURL:' ),
+       'localurle'               => array( 0, 'LOCALURLE:' ),
+       'articlepath'             => array( 0, 'ARTICLEPATH' ),
+       'pageid'                  => array( 0, 'PAGEID' ),
+       'server'                  => array( 0, 'SERVER' ),
+       'servername'              => array( 0, 'SERVERNAME' ),
+       'scriptpath'              => array( 0, 'SCRIPTPATH' ),
+       'stylepath'               => array( 0, 'STYLEPATH' ),
+       'grammar'                 => array( 0, 'GRAMMAR:' ),
+       'gender'                  => array( 0, 'GENDER:' ),
+       'notitleconvert'          => array( 0, '__NOTITLECONVERT__', '__NOTC__' ),
+       'nocontentconvert'        => array( 0, '__NOCONTENTCONVERT__', '__NOCC__' ),
+       'currentweek'             => array( 1, 'CURRENTWEEK' ),
+       'currentdow'              => array( 1, 'CURRENTDOW' ),
+       'localweek'               => array( 1, 'LOCALWEEK' ),
+       'localdow'                => array( 1, 'LOCALDOW' ),
+       'revisionid'              => array( 1, 'REVISIONID' ),
+       'revisionday'             => array( 1, 'REVISIONDAY' ),
+       'revisionday2'            => array( 1, 'REVISIONDAY2' ),
+       'revisionmonth'           => array( 1, 'REVISIONMONTH' ),
+       'revisionmonth1'          => array( 1, 'REVISIONMONTH1' ),
+       'revisionyear'            => array( 1, 'REVISIONYEAR' ),
+       'revisiontimestamp'       => array( 1, 'REVISIONTIMESTAMP' ),
+       'revisionuser'            => array( 1, 'REVISIONUSER' ),
+       'revisionsize'            => array( 1, 'REVISIONSIZE' ),
+       'plural'                  => array( 0, 'PLURAL:' ),
+       'fullurl'                 => array( 0, 'FULLURL:' ),
+       'fullurle'                => array( 0, 'FULLURLE:' ),
+       'canonicalurl'            => array( 0, 'CANONICALURL:' ),
+       'canonicalurle'           => array( 0, 'CANONICALURLE:' ),
+       'lcfirst'                 => array( 0, 'LCFIRST:' ),
+       'ucfirst'                 => array( 0, 'UCFIRST:' ),
+       'lc'                      => array( 0, 'LC:' ),
+       'uc'                      => array( 0, 'UC:' ),
+       'raw'                     => array( 0, 'RAW:' ),
+       'displaytitle'            => array( 1, 'DISPLAYTITLE' ),
+       'rawsuffix'               => array( 1, 'R' ),
+       'nocommafysuffix'         => array( 0, 'NOSEP' ),
+       'newsectionlink'          => array( 1, '__NEWSECTIONLINK__' ),
+       'nonewsectionlink'        => array( 1, '__NONEWSECTIONLINK__' ),
+       'currentversion'          => array( 1, 'CURRENTVERSION' ),
+       'urlencode'               => array( 0, 'URLENCODE:' ),
+       'anchorencode'            => array( 0, 'ANCHORENCODE' ),
+       'currenttimestamp'        => array( 1, 'CURRENTTIMESTAMP' ),
+       'localtimestamp'          => array( 1, 'LOCALTIMESTAMP' ),
+       'directionmark'           => array( 1, 'DIRECTIONMARK', 'DIRMARK' ),
+       'language'                => array( 0, '#LANGUAGE:' ),
+       'contentlanguage'         => array( 1, 'CONTENTLANGUAGE', 'CONTENTLANG' ),
+       'pagesinnamespace'        => array( 1, 'PAGESINNAMESPACE:', 'PAGESINNS:' ),
+       'numberofadmins'          => array( 1, 'NUMBEROFADMINS' ),
+       'formatnum'               => array( 0, 'FORMATNUM' ),
+       'padleft'                 => array( 0, 'PADLEFT' ),
+       'padright'                => array( 0, 'PADRIGHT' ),
+       'special'                 => array( 0, 'special' ),
+       'speciale'                => array( 0, 'speciale' ),
+       'defaultsort'             => array( 1, 'DEFAULTSORT:', 'DEFAULTSORTKEY:', 'DEFAULTCATEGORYSORT:' ),
+       'filepath'                => array( 0, 'FILEPATH:' ),
+       'tag'                     => array( 0, 'tag' ),
+       'hiddencat'               => array( 1, '__HIDDENCAT__' ),
+       'pagesincategory'         => array( 1, 'PAGESINCATEGORY', 'PAGESINCAT' ),
+       'pagesize'                => array( 1, 'PAGESIZE' ),
+       'index'                   => array( 1, '__INDEX__' ),
+       'noindex'                 => array( 1, '__NOINDEX__' ),
+       'numberingroup'           => array( 1, 'NUMBERINGROUP', 'NUMINGROUP' ),
+       'staticredirect'          => array( 1, '__STATICREDIRECT__' ),
+       'protectionlevel'         => array( 1, 'PROTECTIONLEVEL' ),
+       'cascadingsources'        => array( 1, 'CASCADINGSOURCES' ),
+       'formatdate'              => array( 0, 'formatdate', 'dateformat' ),
+       'url_path'                => array( 0, 'PATH' ),
+       'url_wiki'                => array( 0, 'WIKI' ),
+       'url_query'               => array( 0, 'QUERY' ),
+       'defaultsort_noerror'     => array( 0, 'noerror' ),
+       'defaultsort_noreplace'   => array( 0, 'noreplace' ),
+       'displaytitle_noerror'    => array( 0, 'noerror' ),
+       'displaytitle_noreplace'  => array( 0, 'noreplace' ),
+       'pagesincategory_all'     => array( 0, 'all' ),
+       'pagesincategory_pages'   => array( 0, 'pages' ),
+       'pagesincategory_subcats' => array( 0, 'subcats' ),
+       'pagesincategory_files'   => array( 0, 'files' ),
 );
 
 /**
@@ -402,7 +404,7 @@ $specialPageAliases = array(
        'Diff'                      => array( 'Diff' ),
        'DoubleRedirects'           => array( 'DoubleRedirects' ),
        'EditWatchlist'             => array( 'EditWatchlist' ),
-       'Emailuser'                 => array( 'EmailUser' ),
+       'Emailuser'                 => array( 'EmailUser', 'Email' ),
        'ExpandTemplates'           => array( 'ExpandTemplates' ),
        'Export'                    => array( 'Export' ),
        'Fewestrevisions'           => array( 'FewestRevisions' ),
@@ -446,7 +448,7 @@ $specialPageAliases = array(
        'PermanentLink'             => array( 'PermanentLink', 'PermaLink' ),
        'Popularpages'              => array( 'PopularPages' ),
        'Preferences'               => array( 'Preferences' ),
-       'Prefixindex'               => array( 'PrefixIndex' ) ,
+       'Prefixindex'               => array( 'PrefixIndex' ),
        'Protectedpages'            => array( 'ProtectedPages' ),
        'Protectedtitles'           => array( 'ProtectedTitles' ),
        'Randompage'                => array( 'Random', 'RandomPage' ),
index 88afbe7..da3eb7a 100644 (file)
@@ -371,7 +371,7 @@ $datePreferenceMigrationMap = array(
  * overridden.
  */
 $dateFormats = array(
-    # Please be cautious not to delete the invisible RLM from the beginning of the strings.
+       # Please be cautious not to delete the invisible RLM from the beginning of the strings.
        'mdy time' => '‏H:i',
        'mdy date' => '‏n/j/Y میلادی',
        'mdy both' => '‏n/j/Y میلادی، ساعت H:i',
index ac16028..3836ad9 100644 (file)
 $fallback = 'fr';
 
 $bookstoreList = array(
-    'Amazon.fr'    => 'http://www.amazon.fr/exec/obidos/ISBN=$1',
-    'alapage.fr'   => 'http://www.alapage.com/mx/?tp=F&type=101&l_isbn=$1&donnee_appel=ALASQ&devise=&',
-    'fnac.com'     => 'http://www3.fnac.com/advanced/book.do?isbn=$1',
-    'chapitre.com' => 'http://www.chapitre.com/frame_rec.asp?isbn=$1',
+       'Amazon.fr'    => 'http://www.amazon.fr/exec/obidos/ISBN=$1',
+       'alapage.fr'   => 'http://www.alapage.com/mx/?tp=F&type=101&l_isbn=$1&donnee_appel=ALASQ&devise=&',
+       'fnac.com'     => 'http://www3.fnac.com/advanced/book.do?isbn=$1',
+       'chapitre.com' => 'http://www.chapitre.com/frame_rec.asp?isbn=$1',
 );
 
 $namespaceNames = array(
index 947e6b1..38e5b0a 100644 (file)
@@ -35,8 +35,8 @@ $namespaceAliases = array(
 );
 
 $namespaceGenderAliases = array(
-        NS_USER => array( 'male' => 'Wužiwar', 'female' => 'Wužiwarka' ),
-        NS_USER_TALK => array( 'male' => 'Diskusija_z_wužiwarjom', 'female' => 'Diskusija_z_wužiwarku' ),
+       NS_USER => array( 'male' => 'Wužiwar', 'female' => 'Wužiwarka' ),
+       NS_USER_TALK => array( 'male' => 'Diskusija_z_wužiwarjom', 'female' => 'Diskusija_z_wužiwarku' ),
 );
 
 $datePreferences = array(
index 3fcc4cc..a33efef 100644 (file)
@@ -106,8 +106,8 @@ $namespaceAliases = array(
 
        # Aliases to renamed kk-arab namespaces
        'مەدياۋيكي'        => NS_MEDIAWIKI,
-       'مەدياۋيكي_تالقىلاۋى'  => NS_MEDIAWIKI_TALK ,
-       'ٷلگٸ'        => NS_TEMPLATE ,
+       'مەدياۋيكي_تالقىلاۋى'  => NS_MEDIAWIKI_TALK,
+       'ٷلگٸ'        => NS_TEMPLATE,
        'ٷلگٸ_تالقىلاۋى'    => NS_TEMPLATE_TALK,
        'ٴۇلگٴى'              => NS_TEMPLATE,
        'ٴۇلگٴى_تالقىلاۋى'    => NS_TEMPLATE_TALK,
index 3e1b7ab..680c2ea 100644 (file)
@@ -77,8 +77,8 @@ $namespaceAliases = array(
 
        # Aliases to renamed kk-arab namespaces
        'مەدياۋيكي'        => NS_MEDIAWIKI,
-       'مەدياۋيكي_تالقىلاۋى'  => NS_MEDIAWIKI_TALK ,
-       'ٷلگٸ'        => NS_TEMPLATE ,
+       'مەدياۋيكي_تالقىلاۋى'  => NS_MEDIAWIKI_TALK,
+       'ٷلگٸ'        => NS_TEMPLATE,
        'ٷلگٸ_تالقىلاۋى'    => NS_TEMPLATE_TALK,
        'ٴۇلگٴى'              => NS_TEMPLATE,
        'ٴۇلگٴى_تالقىلاۋى'    => NS_TEMPLATE_TALK,
index 76aff5b..b7f8c6f 100644 (file)
@@ -72,8 +72,8 @@ $namespaceAliases = array(
 
        # Aliases to renamed kk-arab namespaces
        'مەدياۋيكي'        => NS_MEDIAWIKI,
-       'مەدياۋيكي_تالقىلاۋى'  => NS_MEDIAWIKI_TALK ,
-       'ٷلگٸ'        => NS_TEMPLATE ,
+       'مەدياۋيكي_تالقىلاۋى'  => NS_MEDIAWIKI_TALK,
+       'ٷلگٸ'        => NS_TEMPLATE,
        'ٷلگٸ_تالقىلاۋى'    => NS_TEMPLATE_TALK,
        'ٴۇلگٴى'              => NS_TEMPLATE,
        'ٴۇلگٴى_تالقىلاۋى'    => NS_TEMPLATE_TALK,
index 23cf2ba..ef0d72c 100644 (file)
@@ -206,6 +206,6 @@ $magicWords = array(
 );
 
 $imageFiles = array(
-    'button-italic'   => 'ksh/button_S_italic.png',
+       'button-italic'   => 'ksh/button_S_italic.png',
 );
 
index d5437da..85c0c26 100644 (file)
@@ -126,9 +126,9 @@ $defaultDateFormat = 'zh';
  * overridden.
  */
 $dateFormats = array(
-        'zh time' => 'H時i分',
-        'zh date' => 'Y年n月j日 (l)',
-        'zh both' => 'Y年n月j日 (D) H時i分',
+       'zh time' => 'H時i分',
+       'zh date' => 'Y年n月j日 (l)',
+       'zh both' => 'Y年n月j日 (D) H時i分',
 );
 
 $digitTransformTable = array(
index fdb33e4..49268f6 100644 (file)
@@ -70,7 +70,7 @@ $dateFormats = array(
 );
 
 $bookstoreList = array(
-        'Koninklijke Bibliotheek' => 'http://opc4.kb.nl/DB=1/SET=5/TTL=1/CMD?ACT=SRCH&IKT=1007&SRT=RLV&TRM=$1'
+       'Koninklijke Bibliotheek' => 'http://opc4.kb.nl/DB=1/SET=5/TTL=1/CMD?ACT=SRCH&IKT=1007&SRT=RLV&TRM=$1'
 );
 
 #!!# Translation <b>HLEERSTE:</b> is used more than once for <a href="#mw-sp-magic-lcfirst">lcfirst</a> and <a href="#mw-sp-magic-ucfirst">ucfirst</a>.
index 5eaccf6..3c65610 100644 (file)
@@ -180,5 +180,5 @@ $magicWords = array(
 );
 
 $linkTrail = '/^((?:[a-z]|а|æ|б|в|г|д|е|ё|ж|з|и|й|к|л|м|н|о|п|р|с|т|у|ф|х|ц|ч|ш|щ|ъ|ы|ь|э|ю|я|“|»)+)(.*)$/sDu';
-$fallback8bitEncoding =  'windows-1251';
+$fallback8bitEncoding = 'windows-1251';
 
index 017b4d0..839a5de 100644 (file)
@@ -51,7 +51,7 @@ $namespaceNames = array(
 );
 
 $namespaceAliases = array(
-        # Aliases for Latin script namespaces
+       # Aliases for Latin script namespaces
        "Medija"                  => NS_MEDIA,
        "Posebno"                 => NS_SPECIAL,
        "Razgovor"                => NS_TALK,
index b359c26..0d64526 100644 (file)
@@ -304,7 +304,7 @@ $magicWords = array(
 );
 
 $linkTrail = '/^([a-zåäöéÅÄÖÉ]+)(.*)$/sDu';
-$separatorTransformTable =  array(
+$separatorTransformTable = array(
        ',' => "\xc2\xa0", // @bug 2749
        '.' => ','
 );
index bc26d31..49a8891 100644 (file)
@@ -34,18 +34,18 @@ $datePreferences = false;
 $defaultDateFormat = 'dmy';
 
 $dateFormats = array(
-        'mdy time' => 'H:i',
-        'mdy date' => 'M j, Y',
-        'mdy both' => 'H:i, M j, Y',
-        'dmy time' => 'H:i',
-        'dmy date' => 'j M Y',
-        'dmy both' => 'j M Y, H:i',
-        'ymd time' => 'H:i',
-        'ymd date' => 'Y M j',
-        'ymd both' => 'H:i, Y M j',
-        'ISO 8601 time' => 'xnH:xni:xns',
-        'ISO 8601 date' => 'xnY-xnm-xnd',
-        'ISO 8601 both' => 'xnY-xnm-xnd"T"xnH:xni:xns',
+       'mdy time' => 'H:i',
+       'mdy date' => 'M j, Y',
+       'mdy both' => 'H:i, M j, Y',
+       'dmy time' => 'H:i',
+       'dmy date' => 'j M Y',
+       'dmy both' => 'j M Y, H:i',
+       'ymd time' => 'H:i',
+       'ymd date' => 'Y M j',
+       'ymd both' => 'H:i, Y M j',
+       'ISO 8601 time' => 'xnH:xni:xns',
+       'ISO 8601 date' => 'xnY-xnm-xnd',
+       'ISO 8601 both' => 'xnY-xnm-xnd"T"xnH:xni:xns',
 );
 
 $namespaceNames = array(
index 09b5590..8846f79 100644 (file)
@@ -45,18 +45,18 @@ $datePreferences = false;
 $defaultDateFormat = 'dmy';
 
 $dateFormats = array(
-        'mdy time' => 'H:i',
-        'mdy date' => 'M j, Y',
-        'mdy both' => 'H:i, M j, Y',
-        'dmy time' => 'H:i',
-        'dmy date' => 'j M Y',
-        'dmy both' => 'j M Y, H:i',
-        'ymd time' => 'H:i',
-        'ymd date' => 'Y M j',
-        'ymd both' => 'H:i, Y M j',
-        'ISO 8601 time' => 'xnH:xni:xns',
-        'ISO 8601 date' => 'xnY-xnm-xnd',
-        'ISO 8601 both' => 'xnY-xnm-xnd"T"xnH:xni:xns',
+       'mdy time' => 'H:i',
+       'mdy date' => 'M j, Y',
+       'mdy both' => 'H:i, M j, Y',
+       'dmy time' => 'H:i',
+       'dmy date' => 'j M Y',
+       'dmy both' => 'j M Y, H:i',
+       'ymd time' => 'H:i',
+       'ymd date' => 'Y M j',
+       'ymd both' => 'H:i, Y M j',
+       'ISO 8601 time' => 'xnH:xni:xns',
+       'ISO 8601 date' => 'xnY-xnm-xnd',
+       'ISO 8601 both' => 'xnY-xnm-xnd"T"xnH:xni:xns',
 );
 
 $magicWords = array(
index 1790f48..1dd1a89 100644 (file)
--- a/load.php
+++ b/load.php
@@ -23,7 +23,7 @@
  */
 
 // Bail if PHP is too low
-if ( !function_exists( 'version_compare' ) || version_compare( phpversion(), '5.3.2' ) < 0 ) {
+if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.3.2' ) < 0 ) {
        // We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+
        require dirname( __FILE__ ) . '/includes/PHPVersionError.php';
        wfPHPVersionError( 'load.php' );
index 5cb6f5f..30bb6ad 100644 (file)
@@ -51,7 +51,7 @@ installations.
        edit.php
        Edit a page to change its content
 
-       findhooks.php
+       findHooks.php
        Find hooks that aren't documented in docs/hooks.txt
 
        importDump.php
@@ -60,9 +60,6 @@ installations.
        importImages.php
        Import images into the wiki
 
-       importTextFile.php
-       Import the contents of a text file into a wiki page
-
        moveBatch.php
        Move a batch of pages
 
diff --git a/maintenance/archives/patch-il_from_namespace.sql b/maintenance/archives/patch-il_from_namespace.sql
new file mode 100644 (file)
index 0000000..4c858f4
--- /dev/null
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/imagelinks
+  ADD COLUMN il_from_namespace int NOT NULL default 0;
+
+CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_to,il_from_namespace,il_from);
\ No newline at end of file
diff --git a/maintenance/archives/patch-pl_from_namespace.sql b/maintenance/archives/patch-pl_from_namespace.sql
new file mode 100644 (file)
index 0000000..2f7ff04
--- /dev/null
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/pagelinks
+       ADD COLUMN pl_from_namespace int NOT NULL default 0;
+
+CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from_namespace,pl_from);
diff --git a/maintenance/archives/patch-tl_from_namespace.sql b/maintenance/archives/patch-tl_from_namespace.sql
new file mode 100644 (file)
index 0000000..8d6c76b
--- /dev/null
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/templatelinks
+       ADD COLUMN tl_from_namespace int NOT NULL default 0;
+
+CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from_namespace,tl_from);
index b81f9fd..ce38dad 100644 (file)
@@ -41,7 +41,10 @@ class BenchmarkParse extends Maintenance {
                parent::__construct();
                $this->addDescription( 'Benchmark parse operation' );
                $this->addArg( 'title', 'The name of the page to parse' );
-               $this->addOption( 'cold', 'Don\'t repeat the parse operation to warm the cache' );
+               $this->addOption( 'warmup', 'Repeat the parse operation this number of times to warm the cache',
+                       false, true );
+               $this->addOption( 'loops', 'Number of times to repeat parse operation post-warmup',
+                       false, true );
                $this->addOption( 'page-time',
                        'Use the version of the page which was current at the given time',
                        false, true );
@@ -81,22 +84,30 @@ class BenchmarkParse extends Maintenance {
                        exit( 1 );
                }
 
-               if ( !$this->hasOption( 'cold' ) ) {
+               $warmup = $this->getOption( 'warmup', 1 );
+               for ( $i = 0; $i < $warmup; $i++ ) {
                        $this->runParser( $revision );
                }
 
+               $loops = $this->getOption( 'loops', 1 );
+               if ( $loops < 1 ) {
+                       $this->error( 'Invalid number of loops specified', true );
+               }
                $startUsage = getrusage();
                $startTime = microtime( true );
-               $this->runParser( $revision );
+               for ( $i = 0; $i < $loops; $i++ ) {
+                       $this->runParser( $revision );
+               }
                $endUsage = getrusage();
                $endTime = microtime( true );
 
                printf( "CPU time = %.3f s, wall clock time = %.3f s\n",
                        // CPU time
-                       $endUsage['ru_utime.tv_sec'] + $endUsage['ru_utime.tv_usec'] * 1e-6
-                       - $startUsage['ru_utime.tv_sec'] - $startUsage['ru_utime.tv_usec'] * 1e-6,
+                       $endUsage['ru_utime.tv_sec'] + $endUsage['ru_utime.tv_usec'] * 1e-6
+                       - $startUsage['ru_utime.tv_sec'] - $startUsage['ru_utime.tv_usec'] * 1e-6 ) / $loops,
                        // Wall clock time
-                       $endTime - $startTime );
+                       ( $endTime - $startTime ) / $loops
+               );
        }
 
        /**
index 93fe660..98441b6 100644 (file)
@@ -79,7 +79,7 @@ class CompareParserCache extends Maintenance {
 
                                $this->output( "Found cache entry found for '{$title->getPrefixedText()}'..." );
                                $oldHtml = trim( preg_replace( '#<!-- .+-->#Us', '', $parserOutputOld->getText() ) );
-                               $newHtml = trim( preg_replace( '#<!-- .+-->#Us', '',$parserOutputNew->getText() ) );
+                               $newHtml = trim( preg_replace( '#<!-- .+-->#Us', '', $parserOutputNew->getText() ) );
                                $diff = wfDiff( $oldHtml, $newHtml );
                                if ( strlen( $diff ) ) {
                                        $this->output( "differences found:\n\n$diff\n\n" );
index 11a81eb..221ebe3 100644 (file)
@@ -140,7 +140,7 @@ class ConvertLinks extends Maintenance {
                                        $this->logPerformance = false;
                                }
                        }
-                       $baseTime = $startTime = $this->getMicroTime();
+                       $baseTime = $startTime = microtime( true );
                        # Create a title -> cur_id map
                        $this->output( "Loading IDs from $cur table...\n" );
                        $this->performanceLog( $fh, "Reading $numRows rows from cur table...\n" );
@@ -161,7 +161,7 @@ class ConvertLinks extends Maintenance {
                                        if ( ( $curRowsRead % $curReadReportInterval ) == 0 ) {
                                                $this->performanceLog(
                                                        $fh,
-                                                       $curRowsRead . " " . ( $this->getMicroTime() - $baseTime ) . "\n"
+                                                       $curRowsRead . " " . ( microtime( true ) - $baseTime ) . "\n"
                                                );
                                                $this->output( "\t$curRowsRead rows of $cur table read.\n" );
                                        }
@@ -172,7 +172,7 @@ class ConvertLinks extends Maintenance {
                        $this->output( "Finished loading IDs.\n\n" );
                        $this->performanceLog(
                                $fh,
-                               "Took " . ( $this->getMicroTime() - $baseTime ) . " seconds to load IDs.\n\n"
+                               "Took " . ( microtime( true ) - $baseTime ) . " seconds to load IDs.\n\n"
                        );
 
                        # --------------------------------------------------------------------
@@ -181,7 +181,7 @@ class ConvertLinks extends Maintenance {
                        # convert, and write to the new table.
                        $this->createTempTable();
                        $this->performanceLog( $fh, "Resetting timer.\n\n" );
-                       $baseTime = $this->getMicroTime();
+                       $baseTime = microtime( true );
                        $this->output( "Processing $numRows rows from $links table...\n" );
                        $this->performanceLog( $fh, "Processing $numRows rows from $links table...\n" );
                        $this->performanceLog( $fh, "rows inserted vs seconds elapsed:\n" );
@@ -226,7 +226,7 @@ class ConvertLinks extends Maintenance {
                                                $this->output( " done. Total $totalTuplesInserted tuples inserted.\n" );
                                                $this->performanceLog(
                                                        $fh,
-                                                       $totalTuplesInserted . " " . ( $this->getMicroTime() - $baseTime ) . "\n"
+                                                       $totalTuplesInserted . " " . ( microtime( true ) - $baseTime ) . "\n"
                                                );
                                        }
                                }
@@ -239,7 +239,7 @@ class ConvertLinks extends Maintenance {
                        );
                        $this->performanceLog(
                                $fh,
-                               "Total execution time: " . ( $this->getMicroTime() - $startTime ) . " seconds.\n"
+                               "Total execution time: " . ( microtime( true ) - $startTime ) . " seconds.\n"
                        );
                        if ( $this->logPerformance ) {
                                fclose( $fh );
@@ -300,12 +300,6 @@ class ConvertLinks extends Maintenance {
                        fwrite( $fh, $text );
                }
        }
-
-       private function getMicroTime() { # return time in seconds, with microsecond accuracy
-               list( $usec, $sec ) = explode( " ", microtime() );
-
-               return ( (float)$usec + (float)$sec );
-       }
 }
 
 $maintClass = "ConvertLinks";
index f555113..81bc06e 100644 (file)
@@ -1,10 +1,10 @@
-ænglisc
-ævar
 &add
 &amp
 &bar
+&img
 &sim
 &url
+&wap
 ABNF
 API
 Aacute
@@ -366,6 +366,7 @@ abusive
 ac
 acad
 accel
+acceptbilling
 acceptlang
 accessdenied
 accesskey
@@ -430,6 +431,7 @@ ai
 aifc
 aiff
 aiprop
+aisort
 ajaxwatch
 al
 alefsym
@@ -441,6 +443,7 @@ allcategories
 alldata
 alle
 allexamples
+allfileusages
 allhidden
 allimages
 allimit
@@ -458,6 +461,7 @@ allpagesbadtitle
 allpagesprefix
 allpagesredirect
 allpagessubmit
+allredirects
 allrev
 alltitles
 alltransclusions
@@ -470,6 +474,7 @@ alreadyexists
 alreadyrolled
 alunique
 am
+analyticsconfig
 anchor
 anchorclose
 anchorencode
@@ -589,6 +594,7 @@ autogen
 autogenerated
 autohide
 autoload
+autoload
 autoloader
 autoloaders
 autoloading
@@ -683,6 +689,7 @@ bgcolor
 bgzip
 bidi
 bigdelete
+bingbot
 binhex
 bitdepth
 bitfield
@@ -829,12 +836,14 @@ capitalizeallnouns
 captchaid
 captchas
 captchaword
+carriersnoips
 cascade
 cascadeable
 cascadeon
 cascadeprotected
 cascadeprotectedwarning
 cascading
+cascadinglevels
 cascadingness
 categories
 categories's
@@ -1107,6 +1116,7 @@ defaultcontentmodel
 defaultmessagetext
 defaultmissing
 defaultns
+defaultoptions
 defaultsort
 defaultval
 deferr
@@ -1167,6 +1177,7 @@ devangari
 devel
 df
 dflt
+dflts
 dhtml
 diams
 didn
@@ -1233,6 +1244,7 @@ domainpart
 domainparts
 domas
 doms
+dont
 dotdotcount
 dotm
 dotsc
@@ -1317,7 +1329,9 @@ eimissingparam
 eititle
 el
 elapsedreal
+elastica
 elemname
+elems
 elink
 eltitle
 email
@@ -1436,6 +1450,7 @@ externaldberror
 externaldiff
 externaledit
 externaleditor
+externalimages
 externallinks
 externalstore
 extet
@@ -1445,6 +1460,7 @@ extlinks
 extracts
 extradata
 extrafields
+extralanglink
 extraq
 extratags
 exturlusage
@@ -1515,6 +1531,7 @@ filepage
 filepath
 filerenameerror
 filerepo
+filerepoinfo
 filerevert
 filerevisions
 files
@@ -1553,6 +1570,7 @@ flagtype
 flatlist
 flds
 float
+flrevs
 fmttime
 fname
 fnof
@@ -1588,6 +1606,7 @@ found
 founder
 fr
 frac
+frameborder
 frameless
 framesets
 frasl
@@ -1624,12 +1643,15 @@ gadgetcategories
 gadgets
 gaid
 gaifilterredir
+gaifrom
 gallerybox
 gallerycaption
 gallerytext
 gapdir
 gapfilterredir
+gapfrom
 gaplimit
+gapnamespace
 gapprefix
 garber
 gblblock
@@ -1643,6 +1665,7 @@ general
 generatexml
 generator
 geocoordinate
+geodata
 geosearch
 gerrit
 getcookie
@@ -1681,6 +1704,7 @@ globe
 gmail
 gmdate
 goodtitle
+googlebot
 gopher
 graymap
 grayscale
@@ -1845,6 +1869,7 @@ image
 imagegetsize
 imageinfo
 imageinvalidfilename
+imagelimits
 imagelinks
 imagemagick
 imagemaxsize
@@ -1857,6 +1882,7 @@ imagesize
 imagetype
 imagetypemismatch
 imageusage
+imagewhitelistenabled
 imagick
 imgmultigo
 imgmultigoto
@@ -1928,6 +1954,7 @@ interwiki
 interwikimap
 interwikipage
 interwikis
+interwikisearchinfo
 interwikisource
 intnull
 intoken
@@ -1975,6 +2002,8 @@ ipchain
 ipedits
 iphash
 ipinrange
+ipset
+ipsets
 ipusers
 iquest
 irc
@@ -1986,12 +2015,14 @@ isconnected
 iscur
 isin
 isip
+islocal
 ismap
 isminor
 ismodsince
 ismulti
 isnew
 ispermalink
+isroot
 isself
 isset
 istainted
@@ -2037,6 +2068,7 @@ jslint
 jsmimetype
 jsminplus
 json
+jsonconfig
 jsonfm
 jsparse
 jstext
@@ -2055,6 +2087,7 @@ keyname
 keynames
 keytype
 khash
+kikongo
 kludgy
 knownnamespace
 konqueror
@@ -2070,11 +2103,13 @@ langcode
 langcodes
 langconversion
 langlinks
+langname
 langprop
 langs
 language
 languagelinks
 languages
+languageselection
 languageshtml
 laquo
 large
@@ -2135,6 +2170,7 @@ link
 linkarr
 linkcolour
 linkprefix
+linkprefixcharset
 links
 linkstoimage
 linktbl
@@ -2170,6 +2206,7 @@ localdayname
 localdow
 locale
 localhour
+localinterwiki
 localmonth
 localmonthabbrev
 localmonthname
@@ -2236,7 +2273,6 @@ ltitle
 ltrimmed
 lurl
 lysator
-möller
 macr
 magicarr
 magicfile
@@ -2290,12 +2326,14 @@ maxwidth
 mazeland
 mbresponse
 mbstring
+mccmnc
 mckey
 mcklmqw
 mcrypt
 mcvalue
 md
 mdash
+mdot
 medialink
 mediaqueries
 mediatype
@@ -2380,6 +2418,7 @@ mkdir
 mms
 mobile
 mobileformat
+mobilelanding
 mobileview
 modified
 modifiedarticleprotection
@@ -2437,6 +2476,7 @@ msgsmall
 msgtext
 msie
 msmetafile
+msnbot
 mssql
 msvideo
 msword
@@ -2481,10 +2521,13 @@ mysqldump
 mytalk
 mytext
 mywatchlist
+möller
 nabla
 name
 namehidden
 nameinlowercase
+namelookup
+namemsg
 names
 namespace
 namespacealiases
@@ -2780,6 +2823,7 @@ noto
 notoc
 notoggle
 notoken
+notpatrollable
 notransform
 notreviewable
 notrustworthy
@@ -2881,6 +2925,7 @@ oldtitle
 oldtitlemsg
 oline
 oname
+onerror
 onkeyup
 online
 onload
@@ -2891,6 +2936,7 @@ onlyquery
 onsubmit
 onthisday
 ontop
+onuser
 openbasedir
 opendoc
 opendocument
@@ -3110,12 +3156,14 @@ pptm
 pptx
 precaching
 precompiled
+preemptively
 preferences
 preferencestoken
 prefill
 prefilled
 prefix
 prefixindex
+prefixsearch
 prefixsearchdisabled
 prefs
 prefsection
@@ -3131,6 +3179,7 @@ preprocessing
 preprocessors
 presentationml
 presep
+pretransfer
 prevchar
 prevdiff
 previd
@@ -3194,6 +3243,7 @@ protecttoken
 proto
 protocol
 protocols
+protorel
 protos
 proxied
 proxyblocker
@@ -3216,6 +3266,7 @@ purged
 qabardjajəbza
 qbar
 qbsettings
+qlow
 qmoicj
 qp
 quasit
@@ -3234,6 +3285,7 @@ querytype
 question
 queuefull
 quickbar
+quicksorts
 quicktemplate
 quicktime
 qunit
@@ -3329,6 +3381,7 @@ redirectable
 redirectcreated
 redirectedfrom
 redirections
+redirector
 redirectpagesub
 redirectparams
 redirects
@@ -3343,6 +3396,7 @@ redis
 redlink
 redlinks
 redocument
+redux
 reedyboy
 reenables
 reencode
@@ -3380,6 +3434,8 @@ remstudent
 renameuser
 renaming
 renderable
+renderesibanner
+renderwarning
 renormalized
 repeating
 repl
@@ -3565,6 +3621,7 @@ selflink
 selfmove
 semiglobal
 semiprotected
+semiprotectedlevels
 semiprotectedpagewarning
 sendemail
 sendmail
@@ -3686,6 +3743,7 @@ smil
 smtp
 snippet
 sodipodi
+softredirect
 softtabstop
 solaris
 somecontent
@@ -3746,6 +3804,7 @@ startsortkey
 startsortkeyprefix
 starttime
 starttimestamp
+starttransfer
 stash
 stashfailed
 stashimageinfo
@@ -3895,8 +3954,8 @@ talkpagetext
 talkspace
 talkspacee
 talkto
-taraškievica
 tarask
+taraškievica
 target
 tb
 tbase
@@ -3963,6 +4022,7 @@ thumbheight
 thumbhtml
 thumbimage
 thumbinner
+thumblimits
 thumbmime
 thumbnail
 thumbnailing
@@ -4090,6 +4150,7 @@ udpprofile
 ufffd
 ugrave
 ui
+uids
 uint
 ulimit
 ulink
@@ -4115,6 +4176,8 @@ undel
 undelete
 undeleted
 undeletion
+undismissable
+undismissible
 undo
 undoafter
 undofailure
@@ -4156,6 +4219,7 @@ unprotect
 unprotectedarticle
 unprotection
 unprotectthispage
+unreadcount
 unredacted
 unrequest
 unrequested
@@ -4211,6 +4275,7 @@ uploadscripted
 uploadsource
 uploadstash
 uploadvirus
+uploadwarning
 uppercased
 upsih
 urandom
@@ -4504,7 +4569,6 @@ xmldoublequote
 xmlfm
 xmlimport
 xmlns
-xmlsafe
 xmlselect
 xor
 xpinstall
@@ -4517,6 +4581,7 @@ xxxxx
 yacute
 yaml
 yamlfm
+yandex
 year
 yes
 youhavenewmessages
@@ -4538,10 +4603,22 @@ yourvariant
 yourwiki
 yuml
 yyyymmddhhiiss
+zerobanner
+zerobar
+zerobutton
+zeroconfig
+zerodontask
+zerodot
+zeroinfo
+zeroportal
 zhdaemon
 zhengzhu
 zhtable
 zijdel
 zlib
 zoffset
+zrma
 zwnj
+ænglisc
+ævar
+świerkosz
index 47e6a89..28a0545 100644 (file)
@@ -77,17 +77,6 @@ if ( defined( 'MW_CONFIG_CALLBACK' ) ) {
        # Use a callback function to configure MediaWiki
        call_user_func( MW_CONFIG_CALLBACK );
 } else {
-       if ( file_exists( "$IP/../wmf-config/wikimedia-mode" ) ) {
-               // Load settings, using wikimedia-mode if needed
-               // @todo FIXME: Replace this hack with general farm-friendly code
-               # @todo FIXME: Wikimedia-specific stuff needs to go away to an ext
-               # Maybe a hook?
-               // @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
-               global $cluster;
-               $cluster = 'pmtpa';
-               // @codingStandardsIgnoreEnd
-               require "$IP/../wmf-config/wgConf.php";
-       }
        // Require the configuration (probably LocalSettings.php)
        require $maintenance->loadSettings();
 }
index 6bdb15d..75ec12b 100644 (file)
@@ -54,8 +54,6 @@ class EditCLI extends Maintenance {
                $noRC = $this->hasOption( 'no-rc' );
 
                $wgUser = User::newFromName( $userName );
-               $context = RequestContext::getMain();
-               $context->setUser( $wgUser );
                if ( !$wgUser ) {
                        $this->error( "Invalid username", true );
                }
@@ -67,7 +65,6 @@ class EditCLI extends Maintenance {
                if ( !$title ) {
                        $this->error( "Invalid title", true );
                }
-               $context->setTitle( $title );
 
                if ( $this->hasOption( 'nocreate' ) && !$title->exists() ) {
                        $this->error( "Page does not exist", true );
index 1c3f037..94ca604 100644 (file)
@@ -27,7 +27,7 @@ require_once __DIR__ . '/Maintenance.php';
 /**
  * Maintenance script to delete archived (non-current) files from storage.
  *
- * @TODO: Maybe add some simple logging
+ * @todo Maybe add some simple logging
  *
  * @ingroup Maintenance
  * @since 1.22
index a678a92..9568284 100644 (file)
@@ -96,7 +96,6 @@ class FixDoubleRedirects extends Maintenance {
                foreach ( $res as $row ) {
                        $titleA = Title::makeTitle( $row->pa_namespace, $row->pa_title );
                        $titleB = Title::makeTitle( $row->pb_namespace, $row->pb_title );
-                       RequestContext::getMain()->setTitle( $titleA );
 
                        $processedTitles .= "* [[$titleA]]\n";
 
index 1f7cbf5..1fedefb 100644 (file)
@@ -182,7 +182,7 @@ TEXT;
        function handleUpload( $revision ) {
                if ( $this->uploads ) {
                        if ( $this->skippedNamespace( $revision ) ) {
-                               return;
+                               return false;
                        }
                        $this->uploadCount++;
                        // $this->report();
@@ -196,6 +196,8 @@ TEXT;
                                return $dbw->deadlockLoop( array( $revision, 'importUpload' ) );
                        }
                }
+
+               return false;
        }
 
        function handleLogItem( $rev ) {
diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php
deleted file mode 100644 (file)
index f73dd1c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-/**
- * Create or edit pages using the contents of a text file.
- *
- * 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
- * @author Rob Church <robchur@gmail.com>
- */
-
-$options = array( 'help', 'nooverwrite', 'norc' );
-$optionsWithArgs = array( 'title', 'user', 'comment' );
-require_once __DIR__ . '/commandLine.inc';
-echo "Import Text File\n\n";
-
-if ( count( $args ) < 1 || isset( $options['help'] ) ) {
-       showHelp();
-} else {
-
-       $filename = $args[0];
-       echo "Using {$filename}...";
-       if ( is_file( $filename ) ) {
-
-               $title = isset( $options['title'] ) ? $options['title'] : titleFromFilename( $filename );
-               $title = Title::newFromText( $title );
-
-               if ( is_object( $title ) ) {
-
-                       echo "\nUsing title '" . $title->getPrefixedText() . "'...";
-                       if ( !$title->exists() || !isset( $options['nooverwrite'] ) ) {
-                               RequestContext::getMain()->setTitle( $title );
-
-                               $text = file_get_contents( $filename );
-                               $user = isset( $options['user'] ) ? $options['user'] : 'Maintenance script';
-                               $user = User::newFromName( $user );
-
-                               if ( is_object( $user ) ) {
-
-                                       echo "\nUsing username '" . $user->getName() . "'...";
-                                       $wgUser =& $user;
-                                       $comment = isset( $options['comment'] ) ? $options['comment'] : 'Importing text file';
-                                       $flags = 0 | ( isset( $options['norc'] ) ? EDIT_SUPPRESS_RC : 0 );
-
-                                       echo "\nPerforming edit...";
-                                       $page = WikiPage::factory( $title );
-                                       $content = ContentHandler::makeContent( $text, $title );
-                                       $page->doEditContent( $content, $comment, $flags, false, $user );
-                                       echo "done.\n";
-                               } else {
-                                       echo "invalid username.\n";
-                               }
-                       } else {
-                               echo "page exists.\n";
-                       }
-               } else {
-                       echo "invalid title.\n";
-               }
-       } else {
-               echo "does not exist.\n";
-       }
-}
-
-function titleFromFilename( $filename ) {
-       $parts = explode( '/', $filename );
-       $parts = explode( '.', $parts[count( $parts ) - 1] );
-
-       return $parts[0];
-}
-
-function showHelp() {
-       print <<<EOF
-USAGE: php importTextFile.php <options> <filename>
-
-<filename> : Path to the file containing page content to import
-
-Options:
-
---title <title>
-       Title for the new page; default is to use the filename as a base
---user <user>
-       User to be associated with the edit
---comment <comment>
-       Edit summary
---nooverwrite
-       Don't overwrite existing content
---norc
-       Don't update recent changes
---help
-       Show this information
-
-EOF;
-}
index 5a3e00c..3b29452 100644 (file)
@@ -21,7 +21,7 @@
  * @ingroup Maintenance
  */
 
-if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) {
+if ( !function_exists( 'version_compare' ) || ( version_compare( PHP_VERSION, '5.3.2' ) < 0 ) ) {
        require_once dirname( __FILE__ ) . '/../includes/PHPVersionError.php';
        wfPHPVersionError( 'cli' );
 }
@@ -85,8 +85,8 @@ class CommandLineInstaller extends Maintenance {
                        true
                );
                $this->addOption( 'confpath', "Path to write LocalSettings.php to ($IP)", false, true );
+               $this->addOption( 'dbschema', 'The schema for the MediaWiki DB in PostgreSQL/Microsoft SQL Server (mediawiki)', false, true );
                /*
-               $this->addOption( 'dbschema', 'The schema for the MediaWiki DB in pg (mediawiki)', false, true );
                $this->addOption( 'namespace', 'The project namespace (same as the "name" argument)', false, true );
                */
                $this->addOption( 'env-checks', "Run environment checks only, don't change anything" );
index 2bb5e6b..db6c315 100644 (file)
@@ -365,7 +365,7 @@ class UcdXmlReader {
                $xml = $this->open();
                $this->callback = $callback;
 
-               while ( $xml->name !== 'repertoire' && $xml->next() ) ;
+               while ( $xml->name !== 'repertoire' && $xml->next() );
 
                while ( $xml->read() ) {
                        if ( $xml->nodeType == XMLReader::ELEMENT ) {
@@ -389,7 +389,7 @@ class UcdXmlReader {
                if ( !$this->xml ) {
                        throw new MWException( __METHOD__ . ": unable to open {$this->fileName}" );
                }
-               while ( $this->xml->name !== 'ucd' && $this->xml->read() ) ;
+               while ( $this->xml->name !== 'ucd' && $this->xml->read() );
                $this->xml->read();
 
                return $this->xml;
@@ -450,7 +450,7 @@ class UcdXmlReader {
                }
 
                $xml = $this->open();
-               while ( $xml->name !== 'blocks' && $xml->read() ) ;
+               while ( $xml->name !== 'blocks' && $xml->read() );
 
                while ( $xml->read() ) {
                        if ( $xml->nodeType == XMLReader::ELEMENT ) {
index da49e55..a97d2e1 100644 (file)
@@ -78,7 +78,7 @@ class McTest extends Maintenance {
                        $set = 0;
                        $incr = 0;
                        $get = 0;
-                       $time_start = $this->microtime_float();
+                       $time_start = microtime( true );
                        for ( $i = 1; $i <= $iterations; $i++ ) {
                                if ( $mcc->set( "test$i", $i ) ) {
                                        $set++;
@@ -95,21 +95,11 @@ class McTest extends Maintenance {
                                        $get++;
                                }
                        }
-                       $exectime = $this->microtime_float() - $time_start;
+                       $exectime = microtime( true ) - $time_start;
 
                        $this->output( " set: $set   incr: $incr   get: $get time: $exectime", $server );
                }
        }
-
-       /**
-        * Return microtime() as a float
-        * @return float
-        */
-       private function microtime_float() {
-               list( $usec, $sec ) = explode( " ", microtime() );
-
-               return ( (float)$usec + (float)$sec );
-       }
 }
 
 $maintClass = "McTest";
diff --git a/maintenance/nextJobDB.php b/maintenance/nextJobDB.php
deleted file mode 100644 (file)
index d172363..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-/**
- * Pick a database that has pending jobs
- *
- * 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';
-
-/**
- * Maintenance script that picks a database that has pending jobs.
- *
- * @ingroup Maintenance
- */
-class NextJobDB extends Maintenance {
-       public function __construct() {
-               parent::__construct();
-               $this->mDescription = "Pick a database that has pending jobs";
-               $this->addOption( 'type', "Search by job type", false, true );
-               $this->addOption( 'types', "Space separated list of job types to search for", false, true );
-       }
-
-       public function execute() {
-               global $wgJobTypesExcludedFromDefaultQueue;
-
-               // job type required/picked
-               if ( $this->hasOption( 'types' ) ) {
-                       $types = explode( ' ', $this->getOption( 'types' ) );
-               } elseif ( $this->hasOption( 'type' ) ) {
-                       $types = array( $this->getOption( 'type' ) );
-               } else {
-                       $types = false;
-               }
-
-               // Handle any required periodic queue maintenance
-               $this->executeReadyPeriodicTasks();
-
-               // Get all the queues with jobs in them
-               $pendingDBs = JobQueueAggregator::singleton()->getAllReadyWikiQueues();
-               if ( !count( $pendingDBs ) ) {
-                       return; // no DBs with jobs or cache is both empty and locked
-               }
-
-               $candidates = array(); // list of (type, db)
-               // Flatten the tree of candidates into a flat list so that a random
-               // item can be selected, weighing each queue (type/db tuple) equally.
-               foreach ( $pendingDBs as $type => $dbs ) {
-                       if (
-                               ( is_array( $types ) && in_array( $type, $types ) ) ||
-                               ( $types === false && !in_array( $type, $wgJobTypesExcludedFromDefaultQueue ) )
-                       ) {
-                               foreach ( $dbs as $db ) {
-                                       $candidates[] = array( $type, $db );
-                               }
-                       }
-               }
-               if ( !count( $candidates ) ) {
-                       return; // no jobs for this type
-               }
-
-               list( $type, $db ) = $candidates[mt_rand( 0, count( $candidates ) - 1 )];
-
-               if ( $this->hasOption( 'types' ) ) {
-                       $this->output( $db . " " . $type . "\n" );
-               } else {
-                       $this->output( $db . "\n" );
-               }
-       }
-
-       /**
-        * Do all ready periodic jobs for all databases every 5 minutes (and .1% of the time)
-        * @return int
-        */
-       private function executeReadyPeriodicTasks() {
-               global $wgLocalDatabases, $wgMemc;
-
-               $count = 0;
-               $memcKey = 'jobqueue:periodic:lasttime';
-               $timestamp = (int)$wgMemc->get( $memcKey ); // UNIX timestamp or 0
-               if ( ( time() - $timestamp ) > 300 || mt_rand( 0, 999 ) == 0 ) { // 5 minutes
-                       if ( $wgMemc->add( "$memcKey:rebuild", 1, 1800 ) ) { // lock
-                               foreach ( $wgLocalDatabases as $db ) {
-                                       $count += JobQueueGroup::singleton( $db )->executeReadyPeriodicTasks();
-                               }
-                               $wgMemc->set( $memcKey, time() );
-                               $wgMemc->delete( "$memcKey:rebuild" ); // unlock
-                       }
-               }
-
-               return $count;
-       }
-}
-
-$maintClass = "NextJobDb";
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/populateBacklinkNamespace.php b/maintenance/populateBacklinkNamespace.php
new file mode 100644 (file)
index 0000000..271a3f6
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Optional upgrade script to populate *_from_namespace fields
+ *
+ * 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';
+
+/**
+ * Maintenance script to populate *_from_namespace fields
+ *
+ * @ingroup Maintenance
+ */
+class PopulateBacklinkNamespace extends LoggedUpdateMaintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Populate the *_from_namespace fields";
+       }
+
+       protected function getUpdateKey() {
+               return 'populate *_from_namespace';
+       }
+
+       protected function updateSkippedMessage() {
+               return '*_from_namespace column of backlink tables already populated.';
+       }
+
+       public function doDBUpdates() {
+               $force = $this->getOption( 'force' );
+
+               $db = $this->getDB( DB_MASTER );
+
+               $this->output( "Updating *_from_namespace fields in links tables.\n" );
+
+               $start = $db->selectField( 'page', 'MIN(page_id)', false, __METHOD__ );
+               if ( !$start ) {
+                       $this->output( "Nothing to do." );
+                       return false;
+               }
+               $end = $db->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
+
+               # Do remaining chunk
+               $end += $this->mBatchSize - 1;
+               $blockStart = $start;
+               $blockEnd = $start + $this->mBatchSize - 1;
+               while ( $blockEnd <= $end ) {
+                       $this->output( "...doing page_id from $blockStart to $blockEnd\n" );
+                       $cond = "page_id BETWEEN $blockStart AND $blockEnd";
+                       $res = $db->select( 'page', array( 'page_id', 'page_namespace' ), $cond, __METHOD__ );
+                       foreach ( $res as $row ) {
+                               $db->update( 'pagelinks',
+                                       array( 'pl_from_namespace' => $row->page_namespace ),
+                                       array( 'pl_from' => $row->page_id ),
+                                       __METHOD__
+                               );
+                               $db->update( 'templatelinks',
+                                       array( 'tl_from_namespace' => $row->page_namespace ),
+                                       array( 'tl_from' => $row->page_id ),
+                                       __METHOD__
+                               );
+                               $db->update( 'imagelinks',
+                                       array( 'il_from_namespace' => $row->page_namespace ),
+                                       array( 'il_from' => $row->page_id ),
+                                       __METHOD__
+                               );
+                       }
+                       $blockStart += $this->mBatchSize - 1;
+                       $blockEnd += $this->mBatchSize - 1;
+                       wfWaitForSlaves();
+               }
+               return true;
+       }
+}
+
+$maintClass = "PopulateBacklinkNamespace";
+require_once RUN_MAINTENANCE_IF_MAIN;
index cf35fe8..400050e 100644 (file)
@@ -206,6 +206,7 @@ CREATE INDEX redirect_ns_title ON redirect (rd_namespace,rd_title,rd_from);
 
 CREATE TABLE pagelinks (
   pl_from       INTEGER   NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+  pl_from_namespace INTEGER NOT NULL DEFAULT 0,
   pl_namespace  SMALLINT  NOT NULL,
   pl_title      TEXT      NOT NULL
 );
@@ -214,6 +215,7 @@ CREATE INDEX pagelinks_title ON pagelinks (pl_title);
 
 CREATE TABLE templatelinks (
   tl_from       INTEGER  NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+  tl_from_namespace INTEGER NOT NULL DEFAULT 0,
   tl_namespace  SMALLINT NOT NULL,
   tl_title      TEXT     NOT NULL
 );
@@ -222,6 +224,7 @@ CREATE INDEX templatelinks_from          ON templatelinks (tl_from);
 
 CREATE TABLE imagelinks (
   il_from  INTEGER  NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+  il_from_namespace INTEGER NOT NULL DEFAULT 0,
   il_to    TEXT     NOT NULL
 );
 CREATE UNIQUE INDEX il_from ON imagelinks (il_to,il_from);
index f0b6ec7..4ce9474 100644 (file)
@@ -160,7 +160,7 @@ class PurgeChangedPages extends Maintenance {
         * If this returns an empty array for a non-empty query result, then all the rows
         * had the same column value and the query should be repeated with a higher LIMIT.
         *
-        * @TODO: move this elsewhere
+        * @todo move this elsewhere
         *
         * @param ResultWrapper $res Query result sorted by $column (ascending)
         * @param string $column
index ca9572f..1b35292 100755 (executable)
@@ -9,12 +9,12 @@ then
        exit 1
 fi
 
-TARGET_REPO=$(cd $(dirname $0)/../..; pwd)
+TARGET_REPO=$(cd "$(dirname $0)/../.."; pwd)
 TARGET_DIR=resources/lib/oojs-ui
 UI_REPO=$1
 
 function oojsuihash() {
-       grep "OOjs UI v" $TARGET_REPO/$TARGET_DIR/oojs-ui.js \
+       grep "OOjs UI v" "$TARGET_REPO/$TARGET_DIR/oojs-ui.js" \
                | head -n 1 \
                | grep -Eo '\([a-z0-9]+\)' \
                | sed 's/^(//' \
@@ -22,19 +22,19 @@ function oojsuihash() {
 }
 
 function oojsuitag() {
-       grep "OOjs UI v" $TARGET_REPO/$TARGET_DIR/oojs-ui.js \
+       grep "OOjs UI v" "$TARGET_REPO/$TARGET_DIR/oojs-ui.js" \
                | head -n 1 \
                | grep -Eo '\bv[0-9a-z.-]+\b'
 }
 
 function oojsuiversion() {
-       grep "OOjs UI v" $TARGET_REPO/$TARGET_DIR/oojs-ui.js \
+       grep "OOjs UI v" "$TARGET_REPO/$TARGET_DIR/oojs-ui.js" \
                | head -n 1 \
                | grep -Eo '\bv[0-9a-z.-]+\b.*$'
 }
 
 # Prepare working tree
-cd $TARGET_REPO &&
+cd "$TARGET_REPO" &&
 git reset $TARGET_DIR && git checkout $TARGET_DIR && git fetch origin &&
 git checkout -B upstream-oojsui origin/master || exit 1
 
@@ -48,10 +48,10 @@ then
 fi
 if [ "$OLDHASH" == "" ]
 then
-       OLDHASH=$(git rev-parse $OLDTAG)
+       OLDHASH=$(git rev-parse "$OLDTAG")
        if [ $? != 0 ]
        then
-               echo Could not find OOjs UI version
+               echo "Could not find OOjs UI version"
                cd -
                exit 1
        fi
@@ -72,13 +72,13 @@ NEWCHANGESDISPLAY=$(git log $OLDHASH.. --oneline --no-merges --reverse --color=a
 
 # Copy files
 # - Exclude the default non-svg stylesheet
-rsync --recursive --delete --force --exclude 'oojs-ui.css' ./dist/ $TARGET_REPO/$TARGET_DIR || exit 1
+rsync --recursive --delete --force --exclude 'oojs-ui.css' --exclude 'oojs-ui*.rtl.css' ./dist/ "$TARGET_REPO/$TARGET_DIR" || exit 1
 
 # Read the new version
 NEWVERSION=$(oojsuiversion)
 
 # Generate commit
-cd $TARGET_REPO
+cd "$TARGET_REPO"
 COMMITMSG=$(cat <<END
 Update OOjs UI to $NEWVERSION
 
index 2c50002..21e847b 100755 (executable)
@@ -7,12 +7,12 @@ then
        exit 1
 fi
 
-REPO_DIR=$(cd $(dirname $0)/../..; pwd) # Root dir of the git repo working tree
-TARGET_DIR=resources/lib/oojs # Destination relative to the root of the repo
-NPM_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'update-oojs'` # e.g. /tmp/update-oojs.rI0I5Vir
+REPO_DIR=$(cd "$(dirname $0)/../.."; pwd) # Root dir of the git repo working tree
+TARGET_DIR="resources/lib/oojs" # Destination relative to the root of the repo
+NPM_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-oojs') # e.g. /tmp/update-oojs.rI0I5Vir
 
 # Prepare working tree
-cd $REPO_DIR &&
+cd "$REPO_DIR" &&
 git reset $TARGET_DIR && git checkout $TARGET_DIR && git fetch origin &&
 git checkout -B upstream-oojs origin/master || exit 1
 
@@ -20,7 +20,7 @@ git checkout -B upstream-oojs origin/master || exit 1
 cd $NPM_DIR
 if [ -n "$1" ]
 then
-       npm install oojs@$1 || exit 1
+       npm install "oojs@$1" || exit 1
 else
        npm install oojs || exit 1
 fi
@@ -33,10 +33,10 @@ then
 fi
 
 # Copy file(s)
-rsync --recursive --delete --force ./node_modules/oojs/dist $REPO_DIR/$TARGET_DIR || exit 1
+rsync --recursive --delete --force ./node_modules/oojs/dist "$REPO_DIR/$TARGET_DIR" || exit 1
 
 # Clean up temporary area
-rm -rf $NPM_DIR
+rm -rf "$NPM_DIR"
 
 # Generate commit
 cd $REPO_DIR || exit 1
index 9b86e1b..e56640f 100644 (file)
@@ -86,7 +86,7 @@ class RunJobs extends Maintenance {
 
                $jobsRun = 0; // counter
                $flags = JobQueueGroup::USE_CACHE;
-               $lastTime = time(); // time since last slave check
+               $lastTime = microtime( true ); // time since last slave check
                do {
                        $backoffs = array_filter( $backoffs, $backoffExpireFunc );
                        $blacklist = $noThrottle ? array() : array_keys( $backoffs );
@@ -101,8 +101,6 @@ class RunJobs extends Maintenance {
                                ++$jobsRun;
                                $this->runJobsLog( $job->toString() . " STARTING" );
 
-                               // Set timer to stop the job if too much CPU time is used
-                               set_time_limit( $maxTime ? : 0 );
                                // Run the job...
                                wfProfileIn( __METHOD__ . '-' . get_class( $job ) );
                                $t = microtime( true );
@@ -117,8 +115,6 @@ class RunJobs extends Maintenance {
                                }
                                $timeMs = intval( ( microtime( true ) - $t ) * 1000 );
                                wfProfileOut( __METHOD__ . '-' . get_class( $job ) );
-                               // Disable the timer
-                               set_time_limit( 0 );
 
                                // Mark the job as done on success or when the job cannot be retried
                                if ( $status !== false || !$job->allowRetries() ) {
@@ -131,8 +127,11 @@ class RunJobs extends Maintenance {
                                        $this->runJobsLog( $job->toString() . " t=$timeMs good" );
                                }
 
-                               // Back off of certain jobs for a while
+                               // Back off of certain jobs for a while (for throttling and for errors)
                                $ttw = $this->getBackoffTimeToWait( $job );
+                               if ( $status === false && mt_rand( 0, 49 ) == 0 ) {
+                                       $ttw = max( $ttw, 30 );
+                               }
                                if ( $ttw > 0 ) {
                                        $jType = $job->getType();
                                        $backoffs[$jType] = isset( $backoffs[$jType] ) ? $backoffs[$jType] : 0;
@@ -147,10 +146,10 @@ class RunJobs extends Maintenance {
                                }
 
                                // Don't let any of the main DB slaves get backed up
-                               $timePassed = time() - $lastTime;
+                               $timePassed = microtime( true ) - $lastTime;
                                if ( $timePassed >= 5 || $timePassed < 0 ) {
-                                       wfWaitForSlaves();
-                                       $lastTime = time();
+                                       wfWaitForSlaves( $lastTime );
+                                       $lastTime = microtime( true );
                                }
                                // Don't let any queue slaves/backups fall behind
                                if ( $jobsRun > 0 && ( $jobsRun % 100 ) == 0 ) {
index 6f200b2..4b9a5e2 100644 (file)
@@ -473,6 +473,8 @@ CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
 CREATE TABLE /*_*/pagelinks (
   -- Key to the page_id of the page containing the link.
   pl_from int unsigned NOT NULL default 0,
+  -- Namespace for this page
+  pl_from_namespace int NOT NULL default 0,
 
   -- Key to page_namespace/page_title of the target page.
   -- The target page may or may not exist, and due to renames
@@ -483,7 +485,8 @@ CREATE TABLE /*_*/pagelinks (
 ) /*$wgDBTableOptions*/;
 
 CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title);
-CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from);
+CREATE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from);
+CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from_namespace,pl_from);
 
 
 --
@@ -492,6 +495,8 @@ CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,p
 CREATE TABLE /*_*/templatelinks (
   -- Key to the page_id of the page containing the link.
   tl_from int unsigned NOT NULL default 0,
+  -- Namespace for this page
+  tl_from_namespace int NOT NULL default 0,
 
   -- Key to page_namespace/page_title of the target page.
   -- The target page may or may not exist, and due to renames
@@ -502,7 +507,8 @@ CREATE TABLE /*_*/templatelinks (
 ) /*$wgDBTableOptions*/;
 
 CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title);
-CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from);
+CREATE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from);
+CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from_namespace,tl_from);
 
 
 --
@@ -513,6 +519,8 @@ CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_tit
 CREATE TABLE /*_*/imagelinks (
   -- Key to page_id of the page containing the image / media link.
   il_from int unsigned NOT NULL default 0,
+  -- Namespace for this page
+  il_from_namespace int NOT NULL default 0,
 
   -- Filename of target image.
   -- This is also the page_title of the file's description page;
@@ -521,7 +529,8 @@ CREATE TABLE /*_*/imagelinks (
 ) /*$wgDBTableOptions*/;
 
 CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to);
-CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from);
+CREATE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from);
+CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_to,il_from_namespace,il_from);
 
 
 --
index a51564a..046d73c 100755 (executable)
@@ -26,7 +26,7 @@
  * @ingroup Maintenance
  */
 
-if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) {
+if ( !function_exists( 'version_compare' ) || ( version_compare( PHP_VERSION, '5.3.2' ) < 0 ) ) {
        require dirname( __FILE__ ) . '/../includes/PHPVersionError.php';
        wfPHPVersionError( 'cli' );
 }
index 56c1308..a6cebc3 100644 (file)
  * @file
  */
 
+// Bail if PHP is too low
+if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.3.2' ) < 0 ) {
+       // We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+
+       require dirname( dirname( __FILE__ ) ) . '/includes/PHPVersionError.php';
+       wfPHPVersionError( 'mw-config/index.php' );
+}
+
 define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' );
 define( 'MEDIAWIKI_INSTALL', true );
 
@@ -37,7 +44,7 @@ function wfInstallerMain() {
 
        if ( !$installer->startSession() ) {
 
-               if( $installer->request->getVal( "css" ) ) {
+               if ( $installer->request->getVal( "css" ) ) {
                        // Do not display errors on css pages
                        $installer->outputCss();
                        exit;
index 4f854fb..09e64c2 100644 (file)
@@ -497,6 +497,7 @@ return array(
                ),
                'skinStyles' => array(
                        'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.menu.css',
+                       'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.menu.css',
                ),
                'group' => 'jquery.ui',
        ),
@@ -578,6 +579,7 @@ return array(
                ),
                'skinStyles' => array(
                        'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.spinner.css',
+                       'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.spinner.css',
                ),
                'group' => 'jquery.ui',
        ),
@@ -602,6 +604,7 @@ return array(
                ),
                'skinStyles' => array(
                        'default' => 'resources/lib/jquery.ui/themes/smoothness/jquery.ui.tooltip.css',
+                       'vector' => 'resources/src/jquery.ui-themes/vector/jquery.ui.tooltip.css',
                ),
                'group' => 'jquery.ui',
        ),
@@ -865,6 +868,7 @@ return array(
                'dependencies' => array(
                        'jquery.hidpi',
                ),
+               'skipFunction' => 'resources/src/mediawiki.hidpi-skip.js',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        'mediawiki.hlist' => array(
@@ -1442,18 +1446,16 @@ return array(
        /* MediaWiki UI */
 
        'mediawiki.ui' => array(
-               'skinStyles' => array(
-                       'default' => 'resources/src/mediawiki.ui/default.less',
-                       'vector' => 'resources/src/mediawiki.ui/vector.less',
+               'styles' => array(
+                       'resources/src/mediawiki.ui/default.less',
                ),
                'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
        ),
        // Lightweight module for button styles
        'mediawiki.ui.button' => array(
-               'skinStyles' => array(
-                       'default' => 'resources/src/mediawiki.ui/components/default/buttons.less',
-                       'vector' => 'resources/src/mediawiki.ui/components/vector/buttons.less',
+               'styles' => array(
+                       'resources/src/mediawiki.ui/components/buttons.less',
                ),
                'position' => 'top',
                'targets' => array( 'desktop', 'mobile' ),
@@ -1495,15 +1497,15 @@ return array(
                        'minerva' => 'resources/lib/oojs-ui/oojs-ui-agora.css',
                ),
                'messages' => array(
-                       'ooui-dialog-action-close',
                        'ooui-outline-control-move-down',
                        'ooui-outline-control-move-up',
                        'ooui-outline-control-remove',
                        'ooui-toolbar-more',
-                       'ooui-dialog-confirm-title',
-                       'ooui-dialog-confirm-default-prompt',
-                       'ooui-dialog-confirm-default-ok',
-                       'ooui-dialog-confirm-default-cancel'
+                       'ooui-dialog-message-accept',
+                       'ooui-dialog-message-reject',
+                       'ooui-dialog-process-dismiss',
+                       'ooui-dialog-process-error',
+                       'ooui-dialog-process-retry',
                ),
                'dependencies' => array(
                        'es5-shim',
index 02048c0..4595994 100644 (file)
@@ -366,7 +366,6 @@ var spliceWorksWithEmptyObject = (function () {
     ArrayPrototype.splice.call(obj, 0, 0, 1);
     return obj.length === 1;
 }());
-var omittingSecondSpliceArgIsNoop = [1].splice(0).length === 0;
 defineProperties(ArrayPrototype, {
     splice: function splice(start, deleteCount) {
         if (arguments.length === 0) { return []; }
@@ -375,14 +374,14 @@ defineProperties(ArrayPrototype, {
         if (arguments.length > 0 && typeof deleteCount !== 'number') {
             args = _Array_slice_.call(arguments);
             if (args.length < 2) {
-                args.push(toInteger(deleteCount));
+                args.push(this.length - start);
             } else {
                 args[1] = toInteger(deleteCount);
             }
         }
         return array_splice.apply(this, args);
     }
-}, !omittingSecondSpliceArgIsNoop || !spliceWorksWithEmptyObject);
+}, !spliceWorksWithEmptyObject);
 
 // ES5 15.4.4.12
 // http://es5.github.com/#x15.4.4.13
@@ -674,7 +673,7 @@ defineProperties(ArrayPrototype, {
 // ES5 15.4.4.14
 // http://es5.github.com/#x15.4.4.14
 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
-var hasFirefox2IndexOfBug = [0, 1].indexOf(1, 2) !== -1;
+var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
 defineProperties(ArrayPrototype, {
     indexOf: function indexOf(sought /*, fromIndex */ ) {
         var self = splitString && isString(this) ? this.split('') : toObject(this),
@@ -703,7 +702,7 @@ defineProperties(ArrayPrototype, {
 // ES5 15.4.4.15
 // http://es5.github.com/#x15.4.4.15
 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
-var hasFirefox2LastIndexOfBug = [0, 1].lastIndexOf(0, -3) !== -1;
+var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1;
 defineProperties(ArrayPrototype, {
     lastIndexOf: function lastIndexOf(sought /*, fromIndex */) {
         var self = splitString && isString(this) ? this.split('') : toObject(this),
@@ -1082,7 +1081,7 @@ if (!Date.now) {
 // http://es5.github.com/#x15.7.4.5
 var hasToFixedBugs = NumberPrototype.toFixed && (
   (0.00008).toFixed(3) !== '0.000'
-  || (0.9).toFixed(0) === '0'
+  || (0.9).toFixed(0) !== '1'
   || (1.255).toFixed(2) !== '1.25'
   || (1000000000000000128).toFixed(0) !== "1000000000000000128"
 );
index 6d5974a..95001fb 100644 (file)
@@ -1,5 +1,6 @@
+/*jshint eqnull:true */
 /*!
- * jQuery Cookie Plugin
+ * jQuery Cookie Plugin v1.2
  * https://github.com/carhartl/jquery-cookie
  *
  * Copyright 2011, Klaus Hartl
@@ -7,41 +8,65 @@
  * http://www.opensource.org/licenses/mit-license.php
  * http://www.opensource.org/licenses/GPL-2.0
  */
-(function($) {
-    $.cookie = function(key, value, options) {
-
-        // key and at least value given, set cookie...
-        if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) {
-            options = $.extend({}, options);
-
-            if (value === null || value === undefined) {
-                options.expires = -1;
-            }
-
-            if (typeof options.expires === 'number') {
-                var days = options.expires, t = options.expires = new Date();
-                t.setDate(t.getDate() + days);
-            }
-
-            value = String(value);
-
-            return (document.cookie = [
-                encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
-                options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
-                options.path    ? '; path=' + options.path : '',
-                options.domain  ? '; domain=' + options.domain : '',
-                options.secure  ? '; secure' : ''
-            ].join(''));
-        }
-
-        // key and possibly options given, get cookie...
-        options = value || {};
-        var decode = options.raw ? function(s) { return s; } : decodeURIComponent;
-
-        var pairs = document.cookie.split('; ');
-        for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) {
-            if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined
-        }
-        return null;
-    };
-})(jQuery);
+(function ($, document, undefined) {
+
+       var pluses = /\+/g;
+
+       function raw(s) {
+               return s;
+       }
+
+       function decoded(s) {
+               return decodeURIComponent(s.replace(pluses, ' '));
+       }
+
+       $.cookie = function (key, value, options) {
+
+               // key and at least value given, set cookie...
+               if (value !== undefined && !/Object/.test(Object.prototype.toString.call(value))) {
+                       options = $.extend({}, $.cookie.defaults, options);
+
+                       if (value === null) {
+                               options.expires = -1;
+                       }
+
+                       if (typeof options.expires === 'number') {
+                               var days = options.expires, t = options.expires = new Date();
+                               t.setDate(t.getDate() + days);
+                       }
+
+                       value = String(value);
+
+                       return (document.cookie = [
+                               encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
+                               options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+                               options.path    ? '; path=' + options.path : '',
+                               options.domain  ? '; domain=' + options.domain : '',
+                               options.secure  ? '; secure' : ''
+                       ].join(''));
+               }
+
+               // key and possibly options given, get cookie...
+               options = value || $.cookie.defaults || {};
+               var decode = options.raw ? raw : decoded;
+               var cookies = document.cookie.split('; ');
+               for (var i = 0, parts; (parts = cookies[i] && cookies[i].split('=')); i++) {
+                       if (decode(parts.shift()) === key) {
+                               return decode(parts.join('='));
+                       }
+               }
+
+               return null;
+       };
+
+       $.cookie.defaults = {};
+
+       $.removeCookie = function (key, options) {
+               if ($.cookie(key, options) !== null) {
+                       $.cookie(key, null, options);
+                       return true;
+               }
+               return false;
+       };
+
+})(jQuery, document);
index 34f8972..eb13f59 100644 (file)
@@ -8,11 +8,12 @@
                        "Mido",
                        "OsamaK",
                        "زكريا",
-                       "مشعل الحربي"
+                       "مشعل الحربي",
+                       "ترجمان05"
                ]
        },
-       "ooui-dialog-action-close": "أغلق",
        "ooui-outline-control-move-down": "انقل العنصر للأسفل",
        "ooui-outline-control-move-up": "انقل العنصر للأعلى",
-       "ooui-toolbar-more": "مزيد"
+       "ooui-toolbar-more": "مزيد",
+       "ooui-dialog-process-retry": "حاول مرة أخرى"
 }
index eb39dac..87d7688 100644 (file)
@@ -6,13 +6,13 @@
                        "Xuacu"
                ]
        },
-       "ooui-dialog-action-close": "Zarrar",
        "ooui-outline-control-move-down": "Mover abaxo l'elementu",
        "ooui-outline-control-move-up": "Mover arriba l'elementu",
        "ooui-outline-control-remove": "Desaniciar elementu",
        "ooui-toolbar-more": "Más",
-       "ooui-dialog-confirm-title": "Confirmar",
-       "ooui-dialog-confirm-default-prompt": "¿Tas seguru?",
-       "ooui-dialog-confirm-default-ok": "Aceutar",
-       "ooui-dialog-confirm-default-cancel": "Encaboxar"
+       "ooui-dialog-message-accept": "Aceutar",
+       "ooui-dialog-message-reject": "Encaboxar",
+       "ooui-dialog-process-error": "Daqué funcionó mal",
+       "ooui-dialog-process-dismiss": "Descartar",
+       "ooui-dialog-process-retry": "Vuelvi a intentalo"
 }
index 3ff9763..4555c11 100644 (file)
@@ -7,11 +7,12 @@
                        "Pginer",
                        "QuimGil",
                        "SMP",
-                       "Vriullop"
+                       "Vriullop",
+                       "Toniher"
                ]
        },
-       "ooui-dialog-action-close": "Tanca",
        "ooui-outline-control-move-down": "Baixa element",
        "ooui-outline-control-move-up": "Puja element",
-       "ooui-toolbar-more": "Més"
+       "ooui-toolbar-more": "Més",
+       "ooui-dialog-process-dismiss": "Descarta"
 }
index ca6d5b4..a75cf0b 100644 (file)
                        "ශ්වෙත"
                ]
        },
-       "ooui-dialog-action-close": "Zavřít",
        "ooui-outline-control-move-down": "Přesunout položku dolů",
        "ooui-outline-control-move-up": "Přesunout položku nahoru",
        "ooui-outline-control-remove": "Odstranit položku",
        "ooui-toolbar-more": "Další",
-       "ooui-dialog-confirm-title": "Potvrzení",
-       "ooui-dialog-confirm-default-prompt": "Opravdu?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Storno"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Storno",
+       "ooui-dialog-process-error": "Něco se pokazilo",
+       "ooui-dialog-process-dismiss": "Zavřít",
+       "ooui-dialog-process-retry": "Zkusit znovu"
 }
index 97ed48c..546689b 100644 (file)
                        "Tomabrafix"
                ]
        },
-       "ooui-dialog-action-close": "Schließen",
        "ooui-outline-control-move-down": "Element nach unten verschieben",
        "ooui-outline-control-move-up": "Element nach oben verschieben",
        "ooui-outline-control-remove": "Element entfernen",
        "ooui-toolbar-more": "Mehr",
-       "ooui-dialog-confirm-title": "Bestätigen",
-       "ooui-dialog-confirm-default-prompt": "Bist du sicher?",
-       "ooui-dialog-confirm-default-ok": "Okay",
-       "ooui-dialog-confirm-default-cancel": "Abbrechen"
+       "ooui-dialog-message-accept": "Okay",
+       "ooui-dialog-message-reject": "Abbrechen",
+       "ooui-dialog-process-error": "Etwas ist schief gelaufen",
+       "ooui-dialog-process-dismiss": "Ausblenden",
+       "ooui-dialog-process-retry": "Erneut versuchen"
 }
index 2498a76..602efc8 100644 (file)
             "Amir E. Aharoni"
         ]
     },
-    "ooui-dialog-action-close": "Close",
     "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-dialog-confirm-title": "Confirm",
-    "ooui-dialog-confirm-default-prompt": "Are you sure?",
-    "ooui-dialog-confirm-default-ok": "OK",
-    "ooui-dialog-confirm-default-cancel": "Cancel"
+    "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"
 }
index 76485ea..7660d4a 100644 (file)
                        "PoLuX124",
                        "Ralgis",
                        "Thehelpfulone",
-                       "Gloria sah"
+                       "Gloria sah",
+                       "Macofe"
                ]
        },
-       "ooui-dialog-action-close": "Cerrar",
        "ooui-outline-control-move-down": "Bajar elemento",
        "ooui-outline-control-move-up": "Subir elemento",
        "ooui-outline-control-remove": "Eliminar elemento",
        "ooui-toolbar-more": "Más",
-       "ooui-dialog-confirm-title": "Confirmar",
-       "ooui-dialog-confirm-default-prompt": "¿Está seguro?",
-       "ooui-dialog-confirm-default-ok": "Aceptar",
-       "ooui-dialog-confirm-default-cancel": "Cancelar"
+       "ooui-dialog-message-accept": "Aceptar",
+       "ooui-dialog-message-reject": "Cancelar",
+       "ooui-dialog-process-error": "Algo salió mal",
+       "ooui-dialog-process-dismiss": "Descartar",
+       "ooui-dialog-process-retry": "Intentar de nuevo"
 }
index 164685c..ac3af74 100644 (file)
@@ -5,13 +5,13 @@
                        "Pikne"
                ]
        },
-       "ooui-dialog-action-close": "Sule",
        "ooui-outline-control-move-down": "Liiguta üksust allapoole",
        "ooui-outline-control-move-up": "Liiguta üksust ülespoole",
        "ooui-outline-control-remove": "Eemalda üksus",
        "ooui-toolbar-more": "Veel",
-       "ooui-dialog-confirm-title": "Kinnitus",
-       "ooui-dialog-confirm-default-prompt": "Kas oled kindel?",
-       "ooui-dialog-confirm-default-ok": "Sobib",
-       "ooui-dialog-confirm-default-cancel": "Loobu"
+       "ooui-dialog-message-accept": "Sobib",
+       "ooui-dialog-message-reject": "Loobu",
+       "ooui-dialog-process-error": "Midagi läks valesti",
+       "ooui-dialog-process-dismiss": "Hülga",
+       "ooui-dialog-process-retry": "Proovi uuesti"
 }
index ec051ac..b0ec803 100644 (file)
                        "Armin1392"
                ]
        },
-       "ooui-dialog-action-close": "بستن",
        "ooui-outline-control-move-down": "انتقال مورد به پایین",
        "ooui-outline-control-move-up": "انتقال مورد به بالا",
        "ooui-outline-control-remove": "حذف مورد",
        "ooui-toolbar-more": "بیشتر",
-       "ooui-dialog-confirm-title": "تأیید",
-       "ooui-dialog-confirm-default-prompt": "آیا مطمئن هستید؟",
-       "ooui-dialog-confirm-default-ok": "تأیید",
-       "ooui-dialog-confirm-default-cancel": "لغو"
+       "ooui-dialog-message-accept": "تأیید",
+       "ooui-dialog-message-reject": "لغو",
+       "ooui-dialog-process-error": "مشکلی وجود دارد",
+       "ooui-dialog-process-dismiss": "نپذیرفتن",
+       "ooui-dialog-process-retry": "دوباره امتحان کن"
 }
index 8e8b81e..efaabed 100644 (file)
                        "VezonThunder"
                ]
        },
-       "ooui-dialog-action-close": "Sulje",
        "ooui-outline-control-move-down": "Siirrä kohdetta alaspäin",
        "ooui-outline-control-move-up": "Siirrä kohdetta ylöspäin",
        "ooui-outline-control-remove": "Poista kohde",
        "ooui-toolbar-more": "Lisää",
-       "ooui-dialog-confirm-title": "Vahvista",
-       "ooui-dialog-confirm-default-prompt": "Oletko varma?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Peruuta"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Peruuta",
+       "ooui-dialog-process-error": "Jokin meni pieleen",
+       "ooui-dialog-process-dismiss": "Hylkää",
+       "ooui-dialog-process-retry": "Yritä uudelleen"
 }
index 6b8871a..8ff5475 100644 (file)
                        "Trizek",
                        "Urhixidur",
                        "Verdy p",
-                       "Wyz"
+                       "Wyz",
+                       "SnowedEarth"
                ]
        },
-       "ooui-dialog-action-close": "Fermer",
        "ooui-outline-control-move-down": "Faire descendre l’élément",
        "ooui-outline-control-move-up": "Faire monter l’élément",
        "ooui-outline-control-remove": "Supprimer l’élément",
        "ooui-toolbar-more": "Plus",
-       "ooui-dialog-confirm-title": "Confirmer",
-       "ooui-dialog-confirm-default-prompt": "Êtes-vous sûr ?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Annuler"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Annuler",
+       "ooui-dialog-process-error": "Quelque chose a mal tourné",
+       "ooui-dialog-process-dismiss": "Rejeter",
+       "ooui-dialog-process-retry": "Réessayez"
 }
diff --git a/resources/lib/oojs-ui/i18n/gd.json b/resources/lib/oojs-ui/i18n/gd.json
new file mode 100644 (file)
index 0000000..6a83c9c
--- /dev/null
@@ -0,0 +1,13 @@
+{
+       "@metadata": {
+               "authors": [
+                       "GunChleoc"
+               ]
+       },
+       "ooui-outline-control-move-down": "Gluais nì sìos",
+       "ooui-outline-control-move-up": "Gluais nì suas",
+       "ooui-outline-control-remove": "Thoir air falbh an nì",
+       "ooui-toolbar-more": "Barrachd",
+       "ooui-dialog-message-accept": "Ceart ma-thà",
+       "ooui-dialog-message-reject": "Sguir dheth"
+}
index a4b6787..eac992f 100644 (file)
@@ -6,13 +6,13 @@
                        "Toliño"
                ]
        },
-       "ooui-dialog-action-close": "Pechar",
        "ooui-outline-control-move-down": "Mover o elemento abaixo",
        "ooui-outline-control-move-up": "Mover o elemento arriba",
        "ooui-outline-control-remove": "Eliminar o elemento",
        "ooui-toolbar-more": "Máis",
-       "ooui-dialog-confirm-title": "Confirmar",
-       "ooui-dialog-confirm-default-prompt": "Está seguro?",
-       "ooui-dialog-confirm-default-ok": "Aceptar",
-       "ooui-dialog-confirm-default-cancel": "Cancelar"
+       "ooui-dialog-message-accept": "Aceptar",
+       "ooui-dialog-message-reject": "Cancelar",
+       "ooui-dialog-process-error": "Algo foi mal",
+       "ooui-dialog-process-dismiss": "Agochar",
+       "ooui-dialog-process-retry": "Inténteo de novo"
 }
index 26660f9..bbaf4c1 100644 (file)
                        "קיפודנחש"
                ]
        },
-       "ooui-dialog-action-close": "סגירה",
        "ooui-outline-control-move-down": "להזיז את הפריט מטה",
        "ooui-outline-control-move-up": "להזיז את הפריט מעלה",
        "ooui-outline-control-remove": "להסיר את הפריט",
        "ooui-toolbar-more": "עוד",
-       "ooui-dialog-confirm-title": "אישור",
-       "ooui-dialog-confirm-default-prompt": "באמת?",
-       "ooui-dialog-confirm-default-ok": "אישור",
-       "ooui-dialog-confirm-default-cancel": "ביטול"
+       "ooui-dialog-message-accept": "אישור",
+       "ooui-dialog-message-reject": "ביטול",
+       "ooui-dialog-process-error": "משהו השתבש",
+       "ooui-dialog-process-dismiss": "לוותר",
+       "ooui-dialog-process-retry": "לנסות שוב"
 }
index 0f423b3..6069625 100644 (file)
@@ -5,15 +5,14 @@
                        "Einstein2",
                        "Misibacsi",
                        "ViDam",
-                       "Tacsipacsi"
+                       "Tacsipacsi",
+                       "Csega"
                ]
        },
-       "ooui-dialog-action-close": "Bezár",
        "ooui-outline-control-move-down": "Elem mozgatása lefelé",
        "ooui-outline-control-move-up": "Elem mozgatása felfelé",
        "ooui-outline-control-remove": "Elem eltávolítása",
        "ooui-toolbar-more": "Tovább...",
-       "ooui-dialog-confirm-title": "Megerősítés",
-       "ooui-dialog-confirm-default-prompt": "Biztos vagy benne?",
-       "ooui-dialog-confirm-default-cancel": "Mégse"
+       "ooui-dialog-message-reject": "Mégse",
+       "ooui-dialog-process-retry": "Próbáld újra"
 }
index f1c9ced..b374b6f 100644 (file)
@@ -4,13 +4,13 @@
                        "McDutchie"
                ]
        },
-       "ooui-dialog-action-close": "Clauder",
        "ooui-outline-control-move-down": "Displaciar elemento in basso",
        "ooui-outline-control-move-up": "Displaciar elemento in alto",
        "ooui-outline-control-remove": "Remover elemento",
        "ooui-toolbar-more": "Plus",
-       "ooui-dialog-confirm-title": "Confirmation",
-       "ooui-dialog-confirm-default-prompt": "Es tu secur?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Cancellar"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Cancellar",
+       "ooui-dialog-process-error": "Qualcosa ha vadite mal",
+       "ooui-dialog-process-dismiss": "Clauder",
+       "ooui-dialog-process-retry": "Reprobar"
 }
index 5d9e3bb..81a91ed 100644 (file)
@@ -4,13 +4,13 @@
                        "Lam-ang"
                ]
        },
-       "ooui-dialog-action-close": "Irekep",
        "ooui-outline-control-move-down": "Ipababa ti banag",
        "ooui-outline-control-move-up": "Ipangato ti banag",
        "ooui-outline-control-remove": "Ikkaten ti banag",
        "ooui-toolbar-more": "Adu pay",
-       "ooui-dialog-confirm-title": "Pasingkedan",
-       "ooui-dialog-confirm-default-prompt": "Siguradoka kadi?",
-       "ooui-dialog-confirm-default-ok": "Sige",
-       "ooui-dialog-confirm-default-cancel": "Ukasen"
+       "ooui-dialog-message-accept": "Sige",
+       "ooui-dialog-message-reject": "Ukasen",
+       "ooui-dialog-process-error": "Adda madi a napasamak",
+       "ooui-dialog-process-dismiss": "Pugsayen",
+       "ooui-dialog-process-retry": "Padasen manen"
 }
index 162fa8c..3d4e049 100644 (file)
                        "Ontsed"
                ]
        },
-       "ooui-dialog-action-close": "Chiudi",
        "ooui-outline-control-move-down": "Sposta in basso",
        "ooui-outline-control-move-up": "Sposta in alto",
        "ooui-outline-control-remove": "Rimuovi elemento",
        "ooui-toolbar-more": "Altro",
-       "ooui-dialog-confirm-title": "Conferma",
-       "ooui-dialog-confirm-default-prompt": "Sei sicuro?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Annulla"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Annulla",
+       "ooui-dialog-process-error": "Qualcosa è andato storto",
+       "ooui-dialog-process-dismiss": "Nascondi",
+       "ooui-dialog-process-retry": "Riprova"
 }
index e2e12ab..1cbcb8a 100644 (file)
                        "Викиней"
                ]
        },
-       "ooui-dialog-action-close": "Zoumaachen",
        "ooui-outline-control-move-down": "Element erof réckelen",
        "ooui-outline-control-move-up": "Element erop réckelen",
        "ooui-outline-control-remove": "Element ewechhuelen",
        "ooui-toolbar-more": "Méi",
-       "ooui-dialog-confirm-title": "Confirméieren",
-       "ooui-dialog-confirm-default-prompt": "Sidd Dir sécher?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Ofbriechen"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Ofbriechen",
+       "ooui-dialog-process-error": "Et ass eppes schif gaang",
+       "ooui-dialog-process-dismiss": "Verwerfen",
+       "ooui-dialog-process-retry": "Nach eng Kéier probéieren"
 }
index 8b0bee4..32fc9fe 100644 (file)
@@ -8,8 +8,10 @@
                        "PeterisP"
                ]
        },
-       "ooui-dialog-action-close": "Aizvērt",
        "ooui-outline-control-move-down": "Pārvietot vienumu uz leju",
        "ooui-outline-control-move-up": "Pārvietot vienumu uz augšu",
-       "ooui-toolbar-more": "Vairāk"
+       "ooui-toolbar-more": "Vairāk",
+       "ooui-dialog-message-accept": "Labi",
+       "ooui-dialog-message-reject": "Atcelt",
+       "ooui-dialog-process-retry": "Mēģināt vēlreiz"
 }
index 90685ea..d628034 100644 (file)
@@ -6,13 +6,13 @@
                        "Iwan Novirion"
                ]
        },
-       "ooui-dialog-action-close": "Затвори",
        "ooui-outline-control-move-down": "Помести надолу",
        "ooui-outline-control-move-up": "Помести нагоре",
        "ooui-outline-control-remove": "Отстрани ставка",
        "ooui-toolbar-more": "Повеќе",
-       "ooui-dialog-confirm-title": "Потврди",
-       "ooui-dialog-confirm-default-prompt": "Дали сте сигурни?",
-       "ooui-dialog-confirm-default-ok": "ОК",
-       "ooui-dialog-confirm-default-cancel": "Откажи"
+       "ooui-dialog-message-accept": "ОК",
+       "ooui-dialog-message-reject": "Откажи",
+       "ooui-dialog-process-error": "Нешто не е во ред",
+       "ooui-dialog-process-dismiss": "Тргни",
+       "ooui-dialog-process-retry": "Обиди се пак"
 }
index 35e7ee4..c62782e 100644 (file)
@@ -5,9 +5,13 @@
                        "Tumsaa"
                ]
        },
-       "ooui-dialog-action-close": "Cufi",
        "ooui-outline-control-move-down": "Gad buusi",
        "ooui-outline-control-move-up": "Ol baasi",
        "ooui-outline-control-remove": "Balleessi",
-       "ooui-toolbar-more": "Dabalata"
+       "ooui-toolbar-more": "Dabalata",
+       "ooui-dialog-message-accept": "Tole",
+       "ooui-dialog-message-reject": "Dhiisi",
+       "ooui-dialog-process-error": "Dogoggorri wayii ummameera",
+       "ooui-dialog-process-dismiss": "Didi",
+       "ooui-dialog-process-retry": "Itti deebi'ii yaali"
 }
index bea0c3a..7978673 100644 (file)
                        "Andrzej aa"
                ]
        },
-       "ooui-dialog-action-close": "Zamknij",
        "ooui-outline-control-move-down": "Przenieś niżej",
        "ooui-outline-control-move-up": "Przenieś wyżej",
        "ooui-outline-control-remove": "Usuń element",
        "ooui-toolbar-more": "Więcej",
-       "ooui-dialog-confirm-title": "Potwierdź",
-       "ooui-dialog-confirm-default-prompt": "Jesteś pewien?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Anuluj"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Anuluj",
+       "ooui-dialog-process-error": "Coś poszło nie tak",
+       "ooui-dialog-process-dismiss": "Ukryj",
+       "ooui-dialog-process-retry": "Spróbuj ponownie"
 }
index e9ad6de..5cb3e3d 100644 (file)
                        "SandroHc"
                ]
        },
-       "ooui-dialog-action-close": "Fechar",
        "ooui-outline-control-move-down": "Mover item para baixo",
        "ooui-outline-control-move-up": "Mover item para cima",
        "ooui-outline-control-remove": "Remover elemento",
        "ooui-toolbar-more": "Mais",
-       "ooui-dialog-confirm-title": "Confirmar",
-       "ooui-dialog-confirm-default-prompt": "Tem a certeza?",
-       "ooui-dialog-confirm-default-ok": "Aceitar",
-       "ooui-dialog-confirm-default-cancel": "Cancelar"
+       "ooui-dialog-message-accept": "Aceitar",
+       "ooui-dialog-message-reject": "Cancelar",
+       "ooui-dialog-process-error": "Algo correu mal",
+       "ooui-dialog-process-dismiss": "Ignorar",
+       "ooui-dialog-process-retry": "Tentar novamente"
 }
index 87198e5..9b3bb60 100644 (file)
                        "Sayak Sarkar",
                        "Shirayuki",
                        "Siebrand",
-                       "Trevor Parscal"
+                       "Trevor Parscal",
+                       "Liuxinyu970226"
                ]
        },
-       "ooui-dialog-action-close": "Label text for button to exit from dialog.\n\n{{Identical|Close}}",
        "ooui-outline-control-move-down": "Tool tip for a button that moves items in a list down one place",
        "ooui-outline-control-move-up": "Tool tip for a button that moves items in a list up one place",
        "ooui-outline-control-remove": "Tool tip for a button that removes items from a list.\n{{Identical|Remove item}}",
        "ooui-toolbar-more": "Label for the toolbar group that contains a list of all other available tools.\n{{Identical|More}}",
-       "ooui-dialog-confirm-title": "Title of the generic dialog used to confirm things.\n{{Identical|Confirm}}",
-       "ooui-dialog-confirm-default-prompt": "The default prompt of a confirmation dialog.\n{{Identical|Are you sure?}}",
-       "ooui-dialog-confirm-default-ok": "The default OK button text on a confirmation dialog.\n{{Identical|OK}}",
-       "ooui-dialog-confirm-default-cancel": "The default cancel button text on a confirmation dialog.\n{{Identical|Cancel}}"
+       "ooui-dialog-message-accept": "Default label for the accept button of a message dialog\n{{Identical|OK}}",
+       "ooui-dialog-message-reject": "Default label for the reject button of a message dialog\n{{Identical|Cancel}}",
+       "ooui-dialog-process-error": "Title for process dialog error description",
+       "ooui-dialog-process-dismiss": "Label for process dialog dismiss error button, visible when describing errors\n{{Identical|Dismiss}}",
+       "ooui-dialog-process-retry": "Label for process dialog retry action button, visible when describing recoverable errors\n{{Identical|Try again}}"
 }
index 0181514..06e0f1d 100644 (file)
@@ -8,13 +8,13 @@
                        "Gloria sah"
                ]
        },
-       "ooui-dialog-action-close": "Închide",
        "ooui-outline-control-move-down": "Mută elementul mai jos",
        "ooui-outline-control-move-up": "Mută elementul mai sus",
        "ooui-outline-control-remove": "Elimină elementul",
        "ooui-toolbar-more": "Mai mult",
-       "ooui-dialog-confirm-title": "Confirmare",
-       "ooui-dialog-confirm-default-prompt": "Sunteți sigur(ă)?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Revocare"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Revocare",
+       "ooui-dialog-process-error": "Ceva nu a funcționat",
+       "ooui-dialog-process-dismiss": "Renunțare",
+       "ooui-dialog-process-retry": "Reîncearcă"
 }
index 435f20c..efd1062 100644 (file)
                        "Умар"
                ]
        },
-       "ooui-dialog-action-close": "Закрыть",
        "ooui-outline-control-move-down": "Переместить элемент вниз",
        "ooui-outline-control-move-up": "Переместить элемент вверх",
        "ooui-outline-control-remove": "Удалить пункт",
        "ooui-toolbar-more": "Ещё",
-       "ooui-dialog-confirm-title": "Подтвердить",
-       "ooui-dialog-confirm-default-prompt": "Вы уверены?",
-       "ooui-dialog-confirm-default-ok": "ОК",
-       "ooui-dialog-confirm-default-cancel": "Отмена"
+       "ooui-dialog-message-accept": "ОК",
+       "ooui-dialog-message-reject": "Отмена",
+       "ooui-dialog-process-error": "Что-то пошло не так",
+       "ooui-dialog-process-dismiss": "Закрыть",
+       "ooui-dialog-process-retry": "Попробовать ещё раз"
 }
index 44dfd60..ec18019 100644 (file)
@@ -4,16 +4,16 @@
                        "Euriditi",
                        "Kushtrim",
                        "Elioqoshi",
-                       "GretaDoci"
+                       "GretaDoci",
+                       "Gertakapllani"
                ]
        },
-       "ooui-dialog-action-close": "Mbylle",
        "ooui-outline-control-move-down": "Zhvendose artikullin më poshtë",
        "ooui-outline-control-move-up": "Zhvendose artikullin më lart",
        "ooui-outline-control-remove": "Hiq artikullin",
        "ooui-toolbar-more": "Më tepër...",
-       "ooui-dialog-confirm-title": "Konfirmo",
-       "ooui-dialog-confirm-default-prompt": "A jeni i sigurt?",
-       "ooui-dialog-confirm-default-ok": "Në rregull",
-       "ooui-dialog-confirm-default-cancel": "Anullo"
+       "ooui-dialog-message-accept": "Në rregull",
+       "ooui-dialog-message-reject": "Anullo",
+       "ooui-dialog-process-error": "Diçka shkoi keq",
+       "ooui-dialog-process-retry": "Provo përsëri"
 }
index 308ed84..d653356 100644 (file)
@@ -6,13 +6,13 @@
                        "Милан Јелисавчић"
                ]
        },
-       "ooui-dialog-action-close": "Затвори",
        "ooui-outline-control-move-down": "Премести ставку на доле",
        "ooui-outline-control-move-up": "Премести ставку на горе",
        "ooui-outline-control-remove": "Уклони ставку",
        "ooui-toolbar-more": "Више",
-       "ooui-dialog-confirm-title": "Потврди",
-       "ooui-dialog-confirm-default-prompt": "Јесте ли сигурни?",
-       "ooui-dialog-confirm-default-ok": "У реду",
-       "ooui-dialog-confirm-default-cancel": "Откажи"
+       "ooui-dialog-message-accept": "У реду",
+       "ooui-dialog-message-reject": "Откажи",
+       "ooui-dialog-process-error": "Нешто је пошло наопако",
+       "ooui-dialog-process-dismiss": "Одбаци",
+       "ooui-dialog-process-retry": "Покушај поново"
 }
index fbd03de..40305d0 100644 (file)
                        "Lokal Profil"
                ]
        },
-       "ooui-dialog-action-close": "Stäng",
        "ooui-outline-control-move-down": "Flytta ned objekt",
        "ooui-outline-control-move-up": "Flytta upp objekt",
        "ooui-outline-control-remove": "Ta bort objekt",
        "ooui-toolbar-more": "Mer",
-       "ooui-dialog-confirm-title": "Bekräfta",
-       "ooui-dialog-confirm-default-prompt": "Är du säker?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Avbryt"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Avbryt",
+       "ooui-dialog-process-error": "Något gick fel",
+       "ooui-dialog-process-dismiss": "Stäng",
+       "ooui-dialog-process-retry": "Försök igen"
 }
index 2bdac54..11aeed4 100644 (file)
@@ -21,5 +21,9 @@
        "ooui-outline-control-move-down": "Перемістити елемент униз",
        "ooui-outline-control-move-up": "Перемістити елемент вгору",
        "ooui-outline-control-remove": "Видалити елемент",
-       "ooui-toolbar-more": "Більше"
+       "ooui-toolbar-more": "Більше",
+       "ooui-dialog-confirm-title": "Підтвердити",
+       "ooui-dialog-confirm-default-prompt": "Ви впевнені?",
+       "ooui-dialog-confirm-default-ok": "Готово",
+       "ooui-dialog-confirm-default-cancel": "Скасувати"
 }
index 9cc4543..205cbe8 100644 (file)
@@ -6,13 +6,13 @@
                        "Minh Nguyen"
                ]
        },
-       "ooui-dialog-action-close": "Đóng",
        "ooui-outline-control-move-down": "Chuyển mục xuống",
        "ooui-outline-control-move-up": "Chuyển mục lên",
        "ooui-outline-control-remove": "Xóa khoản",
        "ooui-toolbar-more": "Thêm",
-       "ooui-dialog-confirm-title": "Xác nhận",
-       "ooui-dialog-confirm-default-prompt": "Bạn có chắc chắn?",
-       "ooui-dialog-confirm-default-ok": "OK",
-       "ooui-dialog-confirm-default-cancel": "Hủy bỏ"
+       "ooui-dialog-message-accept": "OK",
+       "ooui-dialog-message-reject": "Hủy bỏ",
+       "ooui-dialog-process-error": "Đã bị trục trặc",
+       "ooui-dialog-process-dismiss": "Bỏ qua",
+       "ooui-dialog-process-retry": "Thử lại"
 }
index 01a22d1..a850fce 100644 (file)
@@ -6,13 +6,13 @@
                        "十弌"
                ]
        },
-       "ooui-dialog-action-close": "שליסן",
        "ooui-outline-control-move-down": "רוקן עלעמענט אראפ",
        "ooui-outline-control-move-up": "רוקן עלעמענט ארויף",
        "ooui-outline-control-remove": "אַראָפנעמען איינס",
        "ooui-toolbar-more": "נאך",
-       "ooui-dialog-confirm-title": "באַשטעטיקן",
-       "ooui-dialog-confirm-default-prompt": "איר זענט זיכער?",
-       "ooui-dialog-confirm-default-ok": "יאָ",
-       "ooui-dialog-confirm-default-cancel": "אַנולירן"
+       "ooui-dialog-message-accept": "יאָ",
+       "ooui-dialog-message-reject": "אַנולירן",
+       "ooui-dialog-process-error": "עפעס איז דורכגעפאלן",
+       "ooui-dialog-process-dismiss": "צומאַכן",
+       "ooui-dialog-process-retry": "פרובירט נאכאמאל"
 }
index 8d1c09f..50df67a 100644 (file)
                        "乌拉跨氪"
                ]
        },
-       "ooui-dialog-action-close": "关闭",
        "ooui-outline-control-move-down": "下移项",
        "ooui-outline-control-move-up": "上移项",
        "ooui-outline-control-remove": "删除项",
        "ooui-toolbar-more": "更多",
-       "ooui-dialog-confirm-title": "确认",
-       "ooui-dialog-confirm-default-prompt": "您确定吗?",
-       "ooui-dialog-confirm-default-ok": "好",
-       "ooui-dialog-confirm-default-cancel": "取消"
+       "ooui-dialog-message-accept": "好",
+       "ooui-dialog-message-reject": "取消",
+       "ooui-dialog-process-error": "发生一些错误",
+       "ooui-dialog-process-dismiss": "解除",
+       "ooui-dialog-process-retry": "重试"
 }
index 255658b..05fb20d 100644 (file)
                        "Cwlin0416"
                ]
        },
-       "ooui-dialog-action-close": "關閉",
        "ooui-outline-control-move-down": "項目下移",
        "ooui-outline-control-move-up": "項目上移",
        "ooui-outline-control-remove": "移除項目",
        "ooui-toolbar-more": "更多",
-       "ooui-dialog-confirm-title": "確認",
-       "ooui-dialog-confirm-default-prompt": "您確定嗎?",
-       "ooui-dialog-confirm-default-ok": "確定",
-       "ooui-dialog-confirm-default-cancel": "取消"
+       "ooui-dialog-message-accept": "確定",
+       "ooui-dialog-message-reject": "取消",
+       "ooui-dialog-process-error": "發生不明錯誤",
+       "ooui-dialog-process-dismiss": "放棄",
+       "ooui-dialog-process-retry": "再試一次"
 }
diff --git a/resources/lib/oojs-ui/images/anchor.svg b/resources/lib/oojs-ui/images/anchor.svg
new file mode 100644 (file)
index 0000000..417bc96
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+        width="15px" height="8px" viewBox="0 0 15 8" style="enable-background:new 0 0 15 8;" xml:space="preserve">
+<g id="anchor">
+       <polygon id="outline" style="fill-rule:evenodd;clip-rule:evenodd;fill:#808080;" points="7.609,2.499 2.096,8 13.125,8"/>
+       <polygon id="fill" style="fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;" points="7.609,3 2.598,8 12.622,8"/>
+</g>
+</svg>
index df78186..ff52c32 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="apply" style="opacity:0.75;">
-       <polygon id="check" style="fill-rule:evenodd;clip-rule:evenodd;" points="19.062,5.139 17.418,4 8.867,16.357 5.413,12.903 4,14.316 9.021,19.338"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="apply" opacity=".75">
+        <path id="check" fill-rule="evenodd" clip-rule="evenodd" d="M19.062 5.139l-1.644-1.139-8.551 12.357-3.454-3.454-1.413 1.413 5.021 5.022z"/>
+    </g>
 </svg>
index 2620e76..b25d5b7 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="apply" style="opacity:0.75;">
-       <path d="M13,8 L11,8 L11,11 L8,11 L8,13 L11,13 L11,16 L13,16 L13,13 L16,13 L16,11 L13,11 z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="apply" opacity=".75">
+        <path d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
+    </g>
 </svg>
index 3e87cab..223b7fc 100644 (file)
@@ -1,17 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="settings" style="opacity:0.75;">
-       <path id="gear" style="fill-rule:evenodd;clip-rule:evenodd;" d="M20.869,13.476C20.948,12.994,21,12.504,21,12
-               s-0.052-0.994-0.131-1.476l-2.463-0.259c-0.149-0.556-0.367-1.082-0.648-1.57l1.558-1.924c-0.576-0.806-1.281-1.511-2.087-2.087
-               l-1.924,1.558c-0.488-0.281-1.015-0.499-1.57-0.648l-0.259-2.463C12.994,3.052,12.504,3,12,3s-0.994,0.052-1.476,0.131
-               l-0.259,2.463C9.71,5.743,9.184,5.961,8.695,6.242L6.771,4.685C5.966,5.261,5.261,5.966,4.685,6.771l1.558,1.924
-               c-0.281,0.488-0.499,1.015-0.648,1.57l-2.463,0.259C3.052,11.006,3,11.496,3,12s0.052,0.994,0.131,1.476l2.463,0.259
-               c0.149,0.556,0.367,1.082,0.648,1.57l-1.558,1.924c0.576,0.806,1.281,1.511,2.087,2.087l1.924-1.558
-               c0.488,0.281,1.015,0.499,1.57,0.648l0.259,2.463C11.006,20.948,11.496,21,12,21s0.994-0.052,1.476-0.131l0.259-2.463
-               c0.556-0.149,1.082-0.367,1.57-0.648l1.924,1.558c0.806-0.576,1.511-1.281,2.087-2.087l-1.558-1.924
-               c0.281-0.488,0.499-1.015,0.648-1.57L20.869,13.476z M12,15.998c-2.209,0-3.998-1.789-3.998-3.998S9.791,8.002,12,8.002
-               S15.998,9.791,15.998,12S14.209,15.998,12,15.998z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="settings" opacity=".75">
+        <path id="gear" d="M20.869 13.476c.079-.482.131-.972.131-1.476s-.052-.994-.131-1.476l-2.463-.259c-.149-.556-.367-1.082-.648-1.57l1.558-1.924c-.576-.806-1.281-1.511-2.087-2.087l-1.924 1.558c-.488-.281-1.015-.499-1.57-.648l-.259-2.463c-.482-.079-.972-.131-1.476-.131s-.994.052-1.476.131l-.259 2.463c-.555.149-1.081.367-1.57.648l-1.924-1.557c-.805.576-1.51 1.281-2.086 2.086l1.558 1.924c-.281.488-.499 1.015-.648 1.57l-2.463.259c-.08.482-.132.972-.132 1.476s.052.994.131 1.476l2.463.259c.149.556.367 1.082.648 1.57l-1.558 1.924c.576.806 1.281 1.511 2.087 2.087l1.924-1.558c.488.281 1.015.499 1.57.648l.259 2.463c.482.079.972.131 1.476.131s.994-.052 1.476-.131l.259-2.463c.556-.149 1.082-.367 1.57-.648l1.924 1.558c.806-.576 1.511-1.281 2.087-2.087l-1.558-1.924c.281-.488.499-1.015.648-1.57l2.463-.259zm-8.869 2.522c-2.209 0-3.998-1.789-3.998-3.998s1.789-3.998 3.998-3.998 3.998 1.789 3.998 3.998-1.789 3.998-3.998 3.998z" fill-rule="evenodd" clip-rule="evenodd"/>
+    </g>
 </svg>
index 886a7c0..fb25766 100644 (file)
@@ -1,10 +1,8 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="alert" style="opacity:0.75;">
-       <rect id="point" x="11" y="16" style="fill-rule:evenodd;clip-rule:evenodd;" width="2" height="2"/>
-       <polygon id="stroke" style="fill-rule:evenodd;clip-rule:evenodd;" points="13.516,10 10.516,10 11,15 13,15"/>
-       <path id="triangle" d="M12.017,5.974L19.536,19H4.496L12.017,5.974 M12.017,3.5c-0.544,0-1.088,0.357-1.5,1.071L2.532,18.402 C1.707,19.831,2.382,21,4.032,21H20c1.65,0,2.325-1.169,1.5-2.599L13.517,4.572C13.104,3.857,12.561,3.5,12.017,3.5L12.017,3.5z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="alert" opacity=".75">
+        <path id="point" fill-rule="evenodd" clip-rule="evenodd" d="M11 16h2v2h-2z"/>
+        <path id="stroke" fill-rule="evenodd" clip-rule="evenodd" d="M13.516 10h-3l.484 5h2z"/>
+        <path id="triangle" d="M12.017 5.974l7.519 13.026h-15.04l7.521-13.026m0-2.474c-.544 0-1.088.357-1.5 1.071l-7.985 13.831c-.825 1.429-.15 2.598 1.5 2.598h15.968c1.65 0 2.325-1.169 1.5-2.599l-7.983-13.829c-.413-.715-.956-1.072-1.5-1.072z"/>
+    </g>
 </svg>
index 5b343a5..88a6a40 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="arched-arrow-ltr" style="opacity:0.75;">
-       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M19.925,14.937l-2.391-6.901l-1.48,2.329 c-0.964-0.845-2.699-1.85-5.513-1.823c-4.887,0.046-6.524,4.244-6.524,4.244s2.753-2.639,6.925-1.949 c1.729,0.286,3.007,1.206,3.675,1.791l-1.474,2.319L19.925,14.937z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="arched-arrow-ltr" opacity=".75">
+        <path id="arrow" d="M19.925 14.937l-2.391-6.901-1.48 2.329c-.964-.845-2.699-1.85-5.513-1.823-4.887.046-6.524 4.244-6.524 4.244s2.753-2.639 6.925-1.949c1.729.286 3.007 1.206 3.675 1.791l-1.474 2.319 6.782-.01z" fill-rule="evenodd" clip-rule="evenodd"/>
+    </g>
 </svg>
index bb5f10e..50541d2 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="arched-arrow-rtl" style="opacity:0.75;">
-       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M13.401,8.542c-2.814-0.027-4.549,0.978-5.513,1.823 l-1.48-2.329l-2.391,6.901l6.782,0.009l-1.474-2.319c0.668-0.584,1.945-1.504,3.675-1.791c4.172-0.69,6.925,1.949,6.925,1.949 S18.288,8.588,13.401,8.542z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="arched-arrow-rtl" opacity=".75">
+        <path id="arrow" d="M13.401 8.542c-2.814-.027-4.549.978-5.513 1.823l-1.48-2.329-2.391 6.901 6.782.009-1.474-2.319c.668-.584 1.945-1.504 3.675-1.791 4.172-.69 6.925 1.949 6.925 1.949s-1.637-4.197-6.524-4.243z" fill-rule="evenodd" clip-rule="evenodd"/>
+    </g>
 </svg>
index e67cd6c..8d4a1f8 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="check">
-    <path d="M7.105,13.473 L8.527,12.05 L10.428,13.952 L15.238,7 L16.895,8.148 L10.635,17 z" fill="#000000"/>
-  </g>
-  <defs/>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
+    <g id="check">
+        <path d="M7.105 13.473l1.422-1.423 1.901 1.902 4.81-6.952 1.657 1.148-6.26 8.852z"/>
+    </g>
 </svg>
index d83eb02..484a104 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="clear" style="opacity:0.75;">
-       <path id="circle_with_strike" style="fill-rule:evenodd;clip-rule:evenodd;" d="M11.999,5.022c-3.853,0-6.977,3.124-6.977,6.978 c0,3.853,3.124,6.978,6.977,6.978c3.854,0,6.979-3.125,6.979-6.978C18.978,8.146,15.853,5.022,11.999,5.022z M6.886,12 c0-1.092,0.572-3.25,0.93-2.929l7.113,7.113c0.488,0.525-1.837,0.931-2.93,0.931C9.174,17.114,6.886,14.824,6.886,12z M16.184,14.929L9.07,7.816c-0.445-0.483,1.837-0.931,2.929-0.931c2.827,0,5.115,2.289,5.115,5.114 C17.114,13.092,16.75,15.542,16.184,14.929z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="clear" opacity=".75">
+        <path id="circle_with_strike" d="M11.999 5.022c-3.853 0-6.977 3.124-6.977 6.978 0 3.853 3.124 6.978 6.977 6.978 3.854 0 6.979-3.125 6.979-6.978 0-3.854-3.125-6.978-6.979-6.978zm-5.113 6.978c0-1.092.572-3.25.93-2.929l7.113 7.113c.488.525-1.837.931-2.93.931-2.825-.001-5.113-2.291-5.113-5.115zm9.298 2.929l-7.114-7.113c-.445-.483 1.837-.931 2.929-.931 2.827 0 5.115 2.289 5.115 5.114 0 1.093-.364 3.543-.93 2.93z" fill-rule="evenodd" clip-rule="evenodd"/>
+    </g>
 </svg>
index a0118c2..15278e9 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="close" style="opacity:0.75;">
-       <polygon id="x" style="fill-rule:evenodd;clip-rule:evenodd;" points="18.717,6.697 17.303,5.283 12,10.586 6.697,5.283 5.283,6.697 10.586,12 5.283,17.303 6.697,18.717 12,13.414 17.303,18.717 18.717,17.303 13.414,12            "/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="close" opacity=".75">
+        <path id="x" fill-rule="evenodd" clip-rule="evenodd" d="M18.717 6.697l-1.414-1.414-5.303 5.303-5.303-5.303-1.414 1.414 5.303 5.303-5.303 5.303 1.414 1.414 5.303-5.303 5.303 5.303 1.414-1.414-5.303-5.303z"/>
+    </g>
 </svg>
index 6f1ed53..a45ab1e 100644 (file)
@@ -1,14 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-        width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
-<g id="code" opacity="0.75">
-       <path id="left-bracket" d="M4,12v-1h1c1,0,1,0,1-1V7.614C6,7.1,6.024,6.718,6.073,6.472C6.127,6.22,6.212,6.009,6.33,5.839
-               C6.534,5.56,6.803,5.364,7.138,5.255C7.473,5.14,8.01,5,8.973,5H10v1H9.248c-0.457,0-0.77,0.191-0.936,0.408
-               C8.145,6.623,8,6.853,8,7.476v1.857c0,0.729-0.041,1.18-0.244,1.493c-0.2,0.307-0.562,0.529-1.09,0.667
-               c0.535,0.155,0.9,0.385,1.096,0.688C7.961,12.484,8,12.938,8,13.665v1.862c0,0.619,0.145,0.848,0.312,1.062
-               c0.166,0.22,0.479,0.407,0.936,0.407L10,17l0,0v1H8.973c-0.963,0-1.5-0.133-1.835-0.248c-0.335-0.109-0.604-0.307-0.808-0.591
-               c-0.118-0.165-0.203-0.374-0.257-0.625C6.024,16.283,6,15.9,6,15.387V13c0-1,0-1-1-1H4z"/>
-       <use transform="matrix(-1,0,0,1,24,0)" id="right-bracket" x="0" y="0" width="24" height="24" xlink:href="#left-bracket" />
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+    <g id="code" opacity=".75">
+        <path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1v-2.386c0-.514.024-.896.073-1.142.054-.252.139-.463.257-.633.204-.279.473-.475.808-.584.335-.115.872-.255 1.835-.255h1.027v1h-.752c-.457 0-.77.191-.936.408-.167.215-.312.445-.312 1.068v1.857c0 .729-.041 1.18-.244 1.493-.2.307-.562.529-1.09.667.535.155.9.385 1.096.688.199.303.238.757.238 1.484v1.862c0 .619.145.848.312 1.062.166.22.479.407.936.407l.752.004v1h-1.027c-.963 0-1.5-.133-1.835-.248-.335-.109-.604-.307-.808-.591-.118-.165-.203-.374-.257-.625-.049-.253-.073-.636-.073-1.149v-2.387c0-1 0-1-1-1h-1z"/>
+        <use transform="matrix(-1 0 0 1 24 0)" id="right-bracket" width="24" height="24" xlink:href="#left-bracket"/>
+    </g>
 </svg>
index a89cebf..97bdc50 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="collapse" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="6.697,15.714 12,10.412 17.303,15.714 18.717,14.3 12,7.583 5.283,14.3"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="collapse" opacity=".75">
+        <path id="arrow" fill-rule="evenodd" clip-rule="evenodd" d="M6.697 15.714l5.303-5.302 5.303 5.302 1.414-1.414-6.717-6.717-6.717 6.717z"/>
+    </g>
 </svg>
index e052935..ebb038e 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="comment" style="opacity:0.75;">
-       <path id="speech_bubble" style="fill-rule:evenodd;clip-rule:evenodd;" d="M15,6H9C7.343,6,6,7.344,6,9v4c0,1.656,1.343,3,3,3v3 l3-3h3c1.657,0,3-1.344,3-3V9C18,7.344,16.657,6,15,6z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="comment" opacity=".75">
+        <path id="speech_bubble" d="M15 6h-6c-1.657 0-3 1.344-3 3v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3v-4c0-1.656-1.343-3-3-3z" fill-rule="evenodd" clip-rule="evenodd"/>
+    </g>
 </svg>
index b542f5f..81c2ec0 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="expand" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="17.303,8.283 12,13.586 6.697,8.283 5.283,9.697 12,16.414 18.717,9.697"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="expand" opacity=".75">
+        <path id="arrow" fill-rule="evenodd" clip-rule="evenodd" d="M17.303 8.283l-5.303 5.303-5.303-5.303-1.414 1.414 6.717 6.717 6.717-6.717z"/>
+    </g>
 </svg>
index c68bdda..09117e1 100644 (file)
@@ -1,12 +1,10 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="help" style="opacity:0.75;">
-       <path id="circle" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12.001,2.085c-5.478,0-9.916,4.438-9.916,9.916 c0,5.476,4.438,9.914,9.916,9.914c5.476,0,9.914-4.438,9.914-9.914C21.915,6.523,17.477,2.085,12.001,2.085z M12.002,20.085 c-4.465,0-8.084-3.619-8.084-8.083c0-4.465,3.619-8.084,8.084-8.084c4.464,0,8.083,3.619,8.083,8.084 C20.085,16.466,16.466,20.085,12.002,20.085z"/>
-       <g id="question_mark">
-               <path id="top" style="fill-rule:evenodd;clip-rule:evenodd;" d="M11.766,6.688c-2.5,0-3.219,2.188-3.219,2.188l1.411,0.854 c0,0,0.298-0.791,0.901-1.229c0.516-0.375,1.625-0.625,2.219,0.125c0.701,0.885-0.17,1.587-1.078,2.719 C11.047,12.531,11,15,11,15h1.969c0,0,0.135-2.318,1.041-3.381c0.603-0.707,1.443-1.338,1.443-2.494S14.266,6.688,11.766,6.688z"/>
-               <rect id="bottom" x="11" y="16" style="fill-rule:evenodd;clip-rule:evenodd;" width="2" height="2"/>
-       </g>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="help" opacity=".75" fill-rule="evenodd" clip-rule="evenodd">
+        <path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/>
+        <g id="question_mark">
+            <path id="top" 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.719-.953 1.186-1 3.655-1 3.655h1.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.437z"/>
+            <path id="bottom" d="M11 16h2v2h-2z"/>
+        </g>
+    </g>
 </svg>
index 40c0ae3..a89e257 100644 (file)
@@ -1,9 +1,7 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="history" style="opacity:0.75;">
-       <path id="clock_hands" style="fill-rule:evenodd;clip-rule:evenodd;" d="M17.26,15.076c0,0-2.385-1.935-4.005-3.062 c0.72-2.397,1.702-6.559,1.702-6.559s-4.35,5.363-4.877,6.699c-0.463,1.168,1.459,2.209,2.346,1.678 C14.326,14.383,17.26,15.076,17.26,15.076z"/>
-       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12.086,2.085c-5.478,0-9.916,4.438-9.916,9.916 c0,1.783,0.476,3.454,1.301,4.898l-2.223,2.04h5.688v-5.219l-2.066,1.896c-0.55-1.088-0.866-2.312-0.866-3.615 c0-4.465,3.619-8.084,8.084-8.084c4.464,0,8.083,3.619,8.083,8.084c0,4.464-3.619,8.083-8.083,8.083 c-1.145,0-2.228-0.247-3.213-0.678l-0.833,1.634c1.235,0.557,2.602,0.874,4.045,0.874c5.476,0,9.914-4.438,9.914-9.914 C22,6.523,17.562,2.085,12.086,2.085z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="history" opacity=".75" fill-rule="evenodd" clip-rule="evenodd">
+        <path id="clock_hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.559 1.702-6.559s-4.35 5.363-4.877 6.699c-.463 1.168 1.459 2.209 2.346 1.678 1.9.551 4.834 1.244 4.834 1.244z"/>
+        <path id="arrow" d="M12.086 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 1.783.476 3.454 1.301 4.898l-2.223 2.04h5.688v-5.219l-2.066 1.896c-.55-1.088-.866-2.312-.866-3.615 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083-1.145 0-2.228-.247-3.213-.678l-.833 1.634c1.235.557 2.602.874 4.045.874 5.476 0 9.914-4.438 9.914-9.914-.001-5.477-4.439-9.915-9.915-9.915z"/>
+    </g>
 </svg>
index 8c5672a..22ad9be 100644 (file)
@@ -1,10 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="help" opacity="0.75">
-    <path d="M11.499,17 C8.463,17 6,14.536 6,11.5 C6,8.463 8.462,6 11.499,6 C14.536,6 17,8.462 17,11.5 C17,14.536 14.536,17 11.499,17 z M11.501,5 C7.91,5 5,7.91 5,11.5 C5,15.09 7.91,18 11.501,18 C15.089,18 18,15.089 18,11.5 C18,7.911 15.089,5 11.501,5 z" fill="#000000"/>
-    <path d="M12,10 L12,14 L13,14 L13,15 L10,15 L10,14 L11,14 L11,11 L10,11 L10,10 z" fill="#000000"/>
-    <path d="M11,8 L12,8 L12,9 L11,9 z" fill="#000000"/>
-  </g>
-  <defs/>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
+    <g id="help" opacity=".75">
+        <path d="M11.499 17c-3.036 0-5.499-2.464-5.499-5.5 0-3.037 2.462-5.5 5.499-5.5 3.037 0 5.501 2.462 5.501 5.5 0 3.036-2.464 5.5-5.501 5.5zm.002-12c-3.591 0-6.501 2.91-6.501 6.5s2.91 6.5 6.501 6.5c3.588 0 6.499-2.911 6.499-6.5s-2.911-6.5-6.499-6.5zM12 10v4h1v1h-3v-1h1v-3h-1v-1zM11 8h1v1h-1z"/>
+    </g>
 </svg>
index dadf69c..7d8a1ef 100644 (file)
@@ -1,15 +1,8 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="link" style="opacity:0.75;">
-       <path id="right" d="M19.188,12.001c0,1.1-0.891,2.015-1.988,2.015l-4.195-0.015C13.543,15.089,13.968,16,15.002,16h3
-               C19.658,16,21,13.657,21,12s-1.342-4-2.998-4h-3c-1.034,0-1.459,0.911-1.998,1.999l4.195-0.015
-               C18.297,9.984,19.188,10.901,19.188,12.001z"/>
-       <path id="center" d="M8,12c0,0.535,0.42,1,0.938,1h6.109c0.518,0,0.938-0.465,0.938-1c0-0.534-0.42-1-0.938-1H8.938
-               C8.42,11,8,11.466,8,12z"/>
-       <path id="left" d="M4.816,11.999c0-1.1,0.891-2.015,1.988-2.015L11,9.999C10.461,8.911,10.036,8,9.002,8h-3
-               c-1.656,0-2.998,2.343-2.998,4s1.342,4,2.998,4h3c1.034,0,1.459-0.911,1.998-1.999l-4.195,0.015
-               C5.707,14.016,4.816,13.099,4.816,11.999z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="link" opacity=".75">
+        <path id="right" d="M19.188 12.001c0 1.1-.891 2.015-1.988 2.015l-4.195-.015c.538 1.088.963 1.999 1.997 1.999h3c1.656 0 2.998-2.343 2.998-4s-1.342-4-2.998-4h-3c-1.034 0-1.459.911-1.998 1.999l4.195-.015c1.098 0 1.989.917 1.989 2.017z"/>
+        <path id="center" d="M8 12c0 .535.42 1 .938 1h6.109c.518 0 .938-.465.938-1 0-.534-.42-1-.938-1h-6.109c-.518 0-.938.466-.938 1z"/>
+        <path id="left" d="M4.816 11.999c0-1.1.891-2.015 1.988-2.015l4.196.015c-.539-1.088-.964-1.999-1.998-1.999h-3c-1.656 0-2.998 2.343-2.998 4s1.342 4 2.998 4h3c1.034 0 1.459-.911 1.998-1.999l-4.195.015c-1.098 0-1.989-.917-1.989-2.017z"/>
+    </g>
 </svg>
index 657fab2..75866f6 100644 (file)
@@ -1,10 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="menu" style="opacity:0.75;">
-       <path id="lines" d="M6,15h12c0.553,0,1,0.447,1,1v1c0,0.553-0.447,1-1,1H6c-0.553,0-1-0.447-1-1v-1C5,15.447,5.447,15,6,15z M5,11v1
-               c0,0.553,0.447,1,1,1h12c0.553,0,1-0.447,1-1v-1c0-0.553-0.447-1-1-1H6C5.447,10,5,10.447,5,11z M5,6v1c0,0.553,0.447,1,1,1h12
-               c0.553,0,1-0.447,1-1V6c0-0.553-0.447-1-1-1H6C5.447,5,5,5.447,5,6z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="menu" opacity=".75">
+        <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-12c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1z"/>
+    </g>
 </svg>
index a378a5d..3c19c4f 100644 (file)
@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="move-ltr" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="8.935,7.181 14.237,12.483 8.935,17.786
-               10.349,19.2 17.065,12.483 10.349,5.767"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="move-ltr" opacity=".75">
+        <path id="arrow" fill-rule="evenodd" clip-rule="evenodd" d="M8.935 7.181l5.302 5.302-5.302 5.303 1.414 1.414 6.716-6.717-6.716-6.716z"/>
+    </g>
 </svg>
index c0b334b..d9f35c1 100644 (file)
@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="move-rtl" style="opacity:0.75;">
-       <polygon id="arrow_9_" style="fill-rule:evenodd;clip-rule:evenodd;" points="15.065,17.786 9.763,12.483 15.065,7.181
-               13.651,5.767 6.935,12.483 13.651,19.2"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="move-rtl" opacity=".75">
+        <path id="arrow_9_" fill-rule="evenodd" clip-rule="evenodd" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.414-1.414-6.716 6.716 6.716 6.717z"/>
+    </g>
 </svg>
index 078ce10..cd4c0f7 100644 (file)
@@ -1,12 +1,8 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="picture" style="opacity:0.75;">
-       <path id="frame" style="fill-rule:evenodd;clip-rule:evenodd;" d="M18,4H6C4,3.993,3,4.993,3,6.993L3.014,16C3,18,4,18.988,6,19h12
-               c2-0.012,2.994-1,3-3.006V6.993C20.994,4.993,20,3.993,18,4z M19,17H5V6h14V17z"/>
-       <polygon id="mountains" style="fill-rule:evenodd;clip-rule:evenodd;" points="6,13.5 9.5,10 11.828,12.312 10.516,13.406
-               11.391,14.438 15.5,11 18,13 18,16 6,16"/>
-       <polygon id="sky" style="fill-rule:evenodd;clip-rule:evenodd;" points="6,12 9.516,7.844 12.562,11.016 15.5,9 18,11 18,7 6,7"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="picture" opacity=".75" fill-rule="evenodd" clip-rule="evenodd">
+        <path id="frame" d="M18 4h-12c-2-.007-3 .993-3 2.993l.014 9.007c-.014 2 .986 2.988 2.986 3h12c2-.012 2.994-1 3-3.006v-9.001c-.006-2-1-3-3-2.993zm1 13h-14v-11h14v11z"/>
+        <path id="mountains" d="M6 13.5l3.5-3.5 2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12z"/>
+        <path id="sky" d="M6 12l3.516-4.156 3.046 3.172 2.938-2.016 2.5 2v-4h-12z"/>
+    </g>
 </svg>
index b95e7d3..5dd607b 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="remove-item">
-    <path d="M8,11 L16,11 L16,13 L8,13 z" fill="#000000"/>
-  </g>
-  <defs/>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
+    <g id="remove-item">
+        <path d="M8 11h8v2h-8z"/>
+    </g>
 </svg>
index 17c8d39..06c89d7 100644 (file)
@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="remove" style="opacity:0.75;">
-       <path id="trash_can" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12,10h-1v6h1V10z M10,10H9v6h1V10z M14,10h-1v6h1V10z
-                M14,6V5H9v1H6v3h1v7.966l1,1.031v-0.074V18h6.984L15,17.982v0.015l1-1.031V9h1V6H14z M15,17H8V9h7V17z M16,8H7V7h9V8z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="remove" opacity=".75">
+        <path id="trash_can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z" fill-rule="evenodd" clip-rule="evenodd"/>
+    </g>
 </svg>
index 37feda4..ff7144c 100644 (file)
@@ -1,13 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="search" style="opacity:0.75;">
-       <path id="magnifying_glass" d="M16.021,15.96l-2.374-2.375c-0.048-0.047-0.105-0.079-0.169-0.099c0.403-0.566,0.643-1.26,0.643-2.009
-               C14.12,9.557,12.563,8,10.644,8c-1.921,0-3.478,1.557-3.478,3.478c0,1.92,1.557,3.477,3.478,3.477c0.749,0,1.442-0.239,2.01-0.643
-               c0.019,0.063,0.051,0.121,0.098,0.169l2.375,2.374c0.19,0.189,0.543,0.143,0.79-0.104S16.21,16.15,16.021,15.96z M10.644,13.69
-               c-1.221,0-2.213-0.991-2.213-2.213c0-1.221,0.992-2.213,2.213-2.213c1.222,0,2.213,0.992,2.213,2.213
-               C12.856,12.699,11.865,13.69,10.644,13.69z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="search" opacity=".75">
+        <path id="magnifying_glass" d="M16.021 15.96l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
+    </g>
 </svg>
index 1464a79..cbc4efc 100644 (file)
@@ -1,16 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="settings" opacity="0.75">
-    <path d="M3,4 L6,4 L6,6 L3,6 z" fill="#000000"/>
-    <path d="M12,4 L21,4 L21,6 L12,6 z" fill="#000000"/>
-    <path d="M8,3 L10,3 C10.552,3 11,3.448 11,4 L11,6 C11,6.552 10.552,7 10,7 L8,7 C7.448,7 7,6.552 7,6 L7,4 C7,3.448 7.448,3 8,3 z" fill="#000000"/>
-    <path d="M3,11 L12,11 L12,13 L3,13 z" fill="#000000"/>
-    <path d="M18,11 L21,11 L21,13 L18,13 z" fill="#000000"/>
-    <path d="M14,10 L16,10 C16.552,10 17,10.448 17,11 L17,13 C17,13.552 16.552,14 16,14 L14,14 C13.448,14 13,13.552 13,13 L13,11 C13,10.448 13.448,10 14,10 z" fill="#000000"/>
-    <path d="M3,18 L9,18 L9,20 L3,20 z" fill="#000000"/>
-    <path d="M15,18 L21,18 L21,20 L15,20 z" fill="#000000"/>
-    <path d="M11,17 L13,17 C13.552,17 14,17.448 14,18 L14,20 C14,20.552 13.552,21 13,21 L11,21 C10.448,21 10,20.552 10,20 L10,18 C10,17.448 10.448,17 11,17 z" fill="#000000"/>
-  </g>
-  <defs/>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
+    <g id="settings" opacity=".75">
+        <path d="M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z"/>
+    </g>
 </svg>
index d21e5e3..496e7fc 100644 (file)
@@ -1,11 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="tag" style="opacity:0.75;">
-       <path d="M18.748,11.717c0.389,0.389,0.389,1.025,0,1.414l-4.949,4.95c-0.389,0.389-1.025,0.389-1.414,0l-6.01-6.01
-               c-0.389-0.389-0.707-1.157-0.707-1.707L5.667,6c0-0.55,0.45-1,1-1h4.364c0.55,0,1.318,0.318,1.707,0.707L18.748,11.717z
-                M8.104,7.456C7.525,8.032,7.526,8.97,8.103,9.549c0.578,0.577,1.516,0.577,2.095,0.001c0.576-0.578,0.576-1.517,0-2.095
-               C9.617,6.879,8.68,6.878,8.104,7.456z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="tag" opacity=".75">
+        <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
+    </g>
 </svg>
index 621cf2c..ad12773 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="window" style="opacity:0.75;">
-       <rect id="title" x="7" y="10" width="10" height="1"/>
-       <path id="window" d="M16,19H8c-2.206,0-4-1.794-4-4V9c0-2.206,1.794-4,4-4h8c2.206,0,4,1.794,4,4v6C20,17.206,18.206,19,16,19z
-                M8,7C6.897,7,6,7.897,6,9v6c0,1.103,0.897,2,2,2h8c1.103,0,2-0.897,2-2V9c0-1.103-0.897-2-2-2H8z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+    <g id="window" opacity=".75">
+        <path id="title" d="M7 10h10v1h-10z"/>
+        <path id="window" d="M16 19h-8c-2.206 0-4-1.794-4-4v-6c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zm-8-12c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2v-6c0-1.103-.897-2-2-2h-8z"/>
+    </g>
 </svg>
index e549b17..7cfde44 100644 (file)
@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12">
-  <g id="deprecated" opacity="0.75">
-    <path d="M6,12 C2.686,12 -0,9.314 -0,6 C-0,2.686 2.686,-0 6,-0 C9.314,-0 12,2.686 12,6 C12,9.314 9.314,12 6,12 z M5,7 L7,7 L7,2 L5,2 z M5,10 L7,10 L7,8 L5,8 z"/>
-  </g>
-  <defs/>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+    <g id="deprecated" opacity=".75">
+        <path d="M6 12c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2v-5h-2zm0 3h2v-2h-2z"/>
+    </g>
 </svg>
index 89c21e3..d345ec0 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12">
-<g id="down" style="opacity:0.75;">
-       <polygon id="arrow" points="2,3 5.5,9 9,3"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+    <g id="down" opacity=".75">
+        <path id="arrow" d="M2 3l3.5 6 3.5-6z"/>
+    </g>
 </svg>
index ad87640..5092d88 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12">
-<g id="ltr" opacity="0.75">
-       <path id="arrow" d="M3,9 L3,2 L9,5.5 z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+    <g id="ltr" opacity=".75">
+        <path id="arrow" d="M3 9v-7l6 3.5z"/>
+    </g>
 </svg>
index 010b24e..8d39de8 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12">
-<g id="rtl" opacity="0.75">
-       <path id="arrow" d="M3,5.5 L9,9 L9,2 z"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+    <g id="rtl" opacity=".75">
+        <path id="arrow" d="M3 5.5l6 3.5v-7z"/>
+    </g>
 </svg>
index bbc2b3c..78e0115 100644 (file)
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12">
-<g id="up" style="opacity:0.75;">
-       <polygon id="arrow" points="5.5,2 2,8 9,8"/>
-</g>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+    <g id="up" opacity=".75">
+        <path id="arrow" d="M5.5 2l-3.5 6h7z"/>
+    </g>
 </svg>
index d8b36b1..45035f4 100644 (file)
@@ -1,11 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12">
-  <g id="required" opacity="0.75">
-    <path d="M5,1 L7,1 L7,11 L5,11 z"/>
-    <path d="M9.83,2.634 L10.83,4.366 L2.17,9.366 L1.17,7.634 z"/>
-    <path d="M1.17,4.366 L2.17,2.634 L10.83,7.634 L9.83,9.366 z"/>
-  </g>
-  <defs/>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+    <g id="required" opacity=".75">
+        <path d="M5 1h2v10h-2zM9.83 2.634l1 1.732-8.66 5-1-1.732zM1.17 4.366l1-1.732 8.66 5-1 1.732z"/>
+    </g>
 </svg>
diff --git a/resources/lib/oojs-ui/images/tail.svg b/resources/lib/oojs-ui/images/tail.svg
deleted file mode 100644 (file)
index 4df8bb2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-        width="15px" height="8px" viewBox="0 0 15 8" style="enable-background:new 0 0 15 8;" xml:space="preserve">
-<g id="tail">
-       <polygon id="outline" style="fill-rule:evenodd;clip-rule:evenodd;fill:#808080;" points="7.609,2.499 2.096,8 13.125,8"/>
-       <polygon id="fill" style="fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;" points="7.609,3 2.598,8 12.622,8"/>
-</g>
-</svg>
index 3e0bfb9..ae5383c 100644 (file)
 /*!
- * OOjs UI v0.1.0-pre (a63f03882e)
+ * OOjs UI v0.1.0-pre (9cd400e3d5)
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-06-27T23:51:18Z
+ * Date: 2014-07-22T21:59:46Z
  */
-.oo-ui-dialog-content .oo-ui-window-closeButton {
+.oo-ui-dialog-content > .oo-ui-window-head,
+.oo-ui-dialog-content > .oo-ui-window-body,
+.oo-ui-dialog-content > .oo-ui-window-foot {
   position: absolute;
-  top: 0;
+  right: 0;
   left: 0;
+  overflow: hidden;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
 }
 
-.oo-ui-dialog-content .oo-ui-window-icon {
-  margin-left: 3.35em;
+.oo-ui-dialog-content > .oo-ui-window-head {
+  top: 0;
+  z-index: 1;
 }
 
-.oo-ui-dialog-content .oo-ui-window-body {
-  position: absolute;
-  top: 3.35em;
-  right: 0;
+.oo-ui-dialog-content > .oo-ui-window-body {
+  top: 0;
   bottom: 0;
-  left: 0;
-  overflow-y: auto;
+  z-index: 2;
 }
 
-.oo-ui-dialog-content .oo-ui-window-foot {
-  position: absolute;
-  top: 0;
-  right: 0;
-  height: 3.35em;
+.oo-ui-dialog-content > .oo-ui-window-foot {
+  bottom: 0;
+  z-index: 1;
 }
 
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-button {
-  height: 100%;
+.oo-ui-dialog-content > .oo-ui-window-overlay {
+  z-index: 3;
 }
 
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-button .oo-ui-labeledElement-label {
-  display: inline-block;
-  width: 0;
-  text-indent: -9999px;
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+  background-color: rgba(255, 255, 255, 0.5);
+  opacity: 0;
+  -webkit-transition: opacity 250ms ease-in-out;
+     -moz-transition: opacity 250ms ease-in-out;
+      -ms-transition: opacity 250ms ease-in-out;
+       -o-transition: opacity 250ms ease-in-out;
+          transition: opacity 250ms ease-in-out;
 }
 
-.oo-ui-dialog-medium .oo-ui-window-frame {
-  top: 0;
-  bottom: 0;
-  background-color: white;
+.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
+  top: 1em;
+  bottom: 1em;
+  background-color: #fff;
+  -webkit-transform: translate3d(0, -200%, 0);
+     -moz-transform: translate3d(0, -200%, 0);
+      -ms-transform: translate3d(0, -200%, 0);
+       -o-transform: translate3d(0, -200%, 0);
+          transform: translate3d(0, -200%, 0);
+  -webkit-transition: transform 250ms ease-in-out;
+     -moz-transition: transform 250ms ease-in-out;
+      -ms-transition: transform 250ms ease-in-out;
+       -o-transition: transform 250ms ease-in-out;
+          transition: transform 250ms ease-in-out;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
+  opacity: 1;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
+  -webkit-transform: translate3d(0, 0, 0);
+     -moz-transform: translate3d(0, 0, 0);
+      -ms-transform: translate3d(0, 0, 0);
+       -o-transform: translate3d(0, 0, 0);
+          transform: translate3d(0, 0, 0);
+}
+
+.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
+  border: solid 1px #ccc;
+  border-radius: 0.5em;
+  box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
+}
+
+.oo-ui-messageDialog-title,
+.oo-ui-messageDialog-message {
+  display: block;
+  padding-top: 0.5em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-title {
+  font-size: 1.5em;
+  line-height: 1em;
+  color: #000;
+}
+
+.oo-ui-messageDialog-message {
+  font-size: 0.9em;
+  line-height: 1.25em;
+  color: #666;
+}
+
+.oo-ui-messageDialog-message-verbose {
+  font-size: 1.1em;
+  line-height: 1.5em;
+  text-align: left;
 }
 
-.oo-ui-window-head {
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+  border-right: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
+  border-right-width: 0;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+  border-bottom: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
+  border-bottom-width: 0;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 2em;
+  line-height: 3.4em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-content .oo-ui-window-head {
   height: 3.35em;
   border-bottom: 1px solid #dddddd;
   -webkit-box-sizing: border-box;
           box-sizing: border-box;
 }
 
-.oo-ui-window-body {
-  padding: 2em 3.35em;
+.oo-ui-processDialog-content .oo-ui-window-body {
+  top: 3.35em;
+  padding: 2em 0;
 }
 
-.oo-ui-window-icon {
-  width: 3.35em;
+.oo-ui-processDialog-navigation {
+  position: relative;
   height: 3.35em;
-  background-size: 2em auto;
-  border-left: 1px solid #dddddd;
+  padding: 0 1em;
+}
+
+.oo-ui-processDialog-location {
+  height: 3.35em;
+  padding: 0.25em 0;
+  text-align: center;
+  cursor: default;
+}
+
+.oo-ui-processDialog-title {
+  font-weight: bold;
+  line-height: 1.85em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonedElement-button {
+  min-width: 1.85em;
+  min-height: 1.85em;
+  padding-top: 0.75em;
+  padding-bottom: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 1em;
+  line-height: 1.85em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconedElement-icon {
+  position: absolute;
+  margin-top: -0.125em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em 0 0.75em 0.75em;
+  border: solid 1px #ccc;
+  border-radius: 0.25em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  padding: 0;
+  vertical-align: middle;
+}
+
+.oo-ui-processDialog-actions-safe.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  margin: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  /* Adjust for border so text aligns with title */
+
+  margin: -1px;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
 }
 
-.oo-ui-window-title {
-  line-height: 3.35em;
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  left: 0.5em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-left: 2.25em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  right: 0.5em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-right: 2.25em;
+}
+
+.oo-ui-processDialog > .oo-ui-window-frame {
+  min-height: 5em;
+}
+
+.oo-ui-processDialog-errors {
+  padding: 3em 3em 1.5em 3em;
+  text-align: center;
+  background-color: rgba(255, 255, 255, 0.9);
+}
+
+.oo-ui-processDialog-errors .oo-ui-buttonWidget {
+  margin: 2em 1em 2em 1em;
+}
+
+.oo-ui-processDialog-errors-title {
+  margin-bottom: 2em;
+  font-size: 1.5em;
+  color: #000;
+}
+
+.oo-ui-processDialog-error {
+  padding: 1em;
+  margin: 1em;
+  text-align: left;
+  background-color: #fff7f7;
+  border: solid 1px #ff9e9e;
+  border-radius: 0.25em;
 }
 
 .oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
   padding: 0;
 }
 
+.oo-ui-lookupWidget-menu {
+  background-color: #fff;
+}
+
 .oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
   color: #ffffff;
   background: #347bff;
diff --git a/resources/lib/oojs-ui/oojs-ui-agora.rtl.css b/resources/lib/oojs-ui/oojs-ui-agora.rtl.css
new file mode 100644 (file)
index 0000000..fef9ba5
--- /dev/null
@@ -0,0 +1,420 @@
+/*!
+ * OOjs UI v0.1.0
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2014 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2014-07-22T21:39:24Z
+ */
+.oo-ui-dialog-content > .oo-ui-window-head,
+.oo-ui-dialog-content > .oo-ui-window-body,
+.oo-ui-dialog-content > .oo-ui-window-foot {
+  position: absolute;
+  left: 0;
+  right: 0;
+  overflow: hidden;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-dialog-content > .oo-ui-window-head {
+  top: 0;
+  z-index: 1;
+}
+
+.oo-ui-dialog-content > .oo-ui-window-body {
+  top: 0;
+  bottom: 0;
+  z-index: 2;
+}
+
+.oo-ui-dialog-content > .oo-ui-window-foot {
+  bottom: 0;
+  z-index: 1;
+}
+
+.oo-ui-dialog-content > .oo-ui-window-overlay {
+  z-index: 3;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+  background-color: rgba(255, 255, 255, 0.5);
+  opacity: 0;
+  -webkit-transition: opacity 250ms ease-in-out;
+     -moz-transition: opacity 250ms ease-in-out;
+      -ms-transition: opacity 250ms ease-in-out;
+       -o-transition: opacity 250ms ease-in-out;
+          transition: opacity 250ms ease-in-out;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
+  top: 1em;
+  bottom: 1em;
+  background-color: #fff;
+  -webkit-transform: translate3d(0, -200%, 0);
+     -moz-transform: translate3d(0, -200%, 0);
+      -ms-transform: translate3d(0, -200%, 0);
+       -o-transform: translate3d(0, -200%, 0);
+          transform: translate3d(0, -200%, 0);
+  -webkit-transition: transform 250ms ease-in-out;
+     -moz-transition: transform 250ms ease-in-out;
+      -ms-transition: transform 250ms ease-in-out;
+       -o-transition: transform 250ms ease-in-out;
+          transition: transform 250ms ease-in-out;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
+  opacity: 1;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
+  -webkit-transform: translate3d(0, 0, 0);
+     -moz-transform: translate3d(0, 0, 0);
+      -ms-transform: translate3d(0, 0, 0);
+       -o-transform: translate3d(0, 0, 0);
+          transform: translate3d(0, 0, 0);
+}
+
+.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
+  border: solid 1px #ccc;
+  border-radius: 0.5em;
+  box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
+}
+
+.oo-ui-messageDialog-title,
+.oo-ui-messageDialog-message {
+  display: block;
+  padding-top: 0.5em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-title {
+  font-size: 1.5em;
+  line-height: 1em;
+  color: #000;
+}
+
+.oo-ui-messageDialog-message {
+  font-size: 0.9em;
+  line-height: 1.25em;
+  color: #666;
+}
+
+.oo-ui-messageDialog-message-verbose {
+  font-size: 1.1em;
+  line-height: 1.5em;
+  text-align: right;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+  border-left: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
+  border-left-width: 0;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+  border-bottom: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
+  border-bottom-width: 0;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 2em;
+  line-height: 3.4em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-content .oo-ui-window-head {
+  height: 3.35em;
+  border-bottom: 1px solid #dddddd;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-processDialog-content .oo-ui-window-body {
+  top: 3.35em;
+  padding: 2em 0;
+}
+
+.oo-ui-processDialog-navigation {
+  position: relative;
+  height: 3.35em;
+  padding: 0 1em;
+}
+
+.oo-ui-processDialog-location {
+  height: 3.35em;
+  padding: 0.25em 0;
+  text-align: center;
+  cursor: default;
+}
+
+.oo-ui-processDialog-title {
+  font-weight: bold;
+  line-height: 1.85em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonedElement-button {
+  min-width: 1.85em;
+  min-height: 1.85em;
+  padding-top: 0.75em;
+  padding-bottom: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 1em;
+  line-height: 1.85em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconedElement-icon {
+  position: absolute;
+  margin-top: -0.125em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em 0.75em 0.75em 0;
+  border: solid 1px #ccc;
+  border-radius: 0.25em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  padding: 0;
+  vertical-align: middle;
+}
+
+.oo-ui-processDialog-actions-safe.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  margin: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  /* Adjust for border so text aligns with title */
+
+  margin: -1px;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  right: 0.5em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-right: 2.25em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  left: 0.5em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-left: 2.25em;
+}
+
+.oo-ui-processDialog > .oo-ui-window-frame {
+  min-height: 5em;
+}
+
+.oo-ui-processDialog-errors {
+  padding: 3em 3em 1.5em 3em;
+  text-align: center;
+  background-color: rgba(255, 255, 255, 0.9);
+}
+
+.oo-ui-processDialog-errors .oo-ui-buttonWidget {
+  margin: 2em 1em 2em 1em;
+}
+
+.oo-ui-processDialog-errors-title {
+  margin-bottom: 2em;
+  font-size: 1.5em;
+  color: #000;
+}
+
+.oo-ui-processDialog-error {
+  padding: 1em;
+  margin: 1em;
+  text-align: right;
+  background-color: #fff7f7;
+  border: solid 1px #ff9e9e;
+  border-radius: 0.25em;
+}
+
+.oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  width: 3.35em;
+  height: 3.35em;
+  background-size: 2em auto;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
+  padding: 0 0 1em;
+}
+
+.oo-ui-optionWidget {
+  padding: 0.8em 3.35em 0.8em 1em;
+  font-weight: bold;
+  border-bottom: 1px solid #dddddd;
+}
+
+.oo-ui-optionWidget.oo-ui-indicatedElement .oo-ui-labeledElement-label {
+  padding-left: 1.5em;
+}
+
+.oo-ui-optionWidget-level-0 {
+  padding-right: 3.5em;
+}
+
+.oo-ui-optionWidget-level-0 .oo-ui-iconedElement-icon {
+  right: 1em;
+}
+
+.oo-ui-optionWidget-level-1 {
+  padding-right: 5em;
+}
+
+.oo-ui-optionWidget-level-1 .oo-ui-iconedElement-icon {
+  right: 2.5em;
+}
+
+.oo-ui-optionWidget-level-2 {
+  padding-right: 6.5em;
+}
+
+.oo-ui-optionWidget-level-2 .oo-ui-iconedElement-icon {
+  right: 4em;
+}
+
+.oo-ui-buttonOptionWidget {
+  padding: 0;
+}
+
+.oo-ui-lookupWidget-menu {
+  background-color: #fff;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
+  color: #ffffff;
+  background: #347bff;
+}
+
+.oo-ui-menuSectionItemWidget {
+  font-weight: normal;
+  color: #777777;
+  border: none;
+}
+
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+  padding: .8em 1em;
+}
+
+/* Icons */
+
+.oo-ui-icon-check {
+  background: #347bff;
+  background-image: /* @embed */ url(themes/agora/images/icons/check.svg);
+}
\ No newline at end of file
index e651ff0..b5a6eee 100644 (file)
@@ -1,53 +1,16 @@
 /*!
- * OOjs UI v0.1.0-pre (a63f03882e)
+ * OOjs UI v0.1.0-pre (9cd400e3d5)
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-06-27T23:51:18Z
+ * Date: 2014-07-22T21:59:46Z
  */
-.oo-ui-dialog {
-  background-color: #fff;
-  background-color: rgba(255, 255, 255, 0.5);
-  /* Opening and closing animation */
-
-  opacity: 0;
-}
-
-.oo-ui-dialog > .oo-ui-window-frame {
-  -webkit-transform: scale(0.5);
-     -moz-transform: scale(0.5);
-      -ms-transform: scale(0.5);
-       -o-transform: scale(0.5);
-          transform: scale(0.5);
-}
-
-.oo-ui-dialog.oo-ui-window-setup,
-.oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
-  -webkit-transition: all 250ms ease-in-out;
-     -moz-transition: all 250ms ease-in-out;
-      -ms-transition: all 250ms ease-in-out;
-       -o-transition: all 250ms ease-in-out;
-          transition: all 250ms ease-in-out;
-}
-
-.oo-ui-dialog.oo-ui-window-ready {
-  opacity: 1;
-}
-
-.oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
-  -webkit-transform: scale(1);
-     -moz-transform: scale(1);
-      -ms-transform: scale(1);
-       -o-transform: scale(1);
-          transform: scale(1);
-}
-
-.oo-ui-dialog-content .oo-ui-window-head,
-.oo-ui-dialog-content .oo-ui-window-body,
-.oo-ui-dialog-content .oo-ui-window-foot {
+.oo-ui-dialog-content > .oo-ui-window-head,
+.oo-ui-dialog-content > .oo-ui-window-body,
+.oo-ui-dialog-content > .oo-ui-window-foot {
   position: absolute;
   right: 0;
   left: 0;
           box-sizing: border-box;
 }
 
-.oo-ui-dialog-content .oo-ui-window-head {
+.oo-ui-dialog-content .oo-ui-window-head {
   top: 0;
-  height: 3.8em;
-  padding: 0.5em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-title {
-  line-height: 2.8em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-icon {
-  width: 2.4em;
-  height: 2.8em;
-  line-height: 2.8em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-closeButton {
-  float: right;
-  margin: 0.25em 0.25em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-body {
-  top: 3.8em;
-  bottom: 4.8em;
-}
-
-.oo-ui-dialog-content-footless .oo-ui-window-body {
-  bottom: 0;
-}
-
-.oo-ui-dialog > .oo-ui-window-frame {
-  top: 1em;
-  bottom: 1em;
-  background-color: #fff;
-  border: solid 1px #ccc;
-  border-radius: 0.5em;
-  box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
-}
-
-.oo-ui-dialog-small > .oo-ui-window-frame {
-  width: 400px;
-  max-height: 230px;
-}
-
-.oo-ui-dialog-medium > .oo-ui-window-frame {
-  width: 600px;
-  max-height: 460px;
-}
-
-.oo-ui-dialog-large > .oo-ui-window-frame {
-  width: 800px;
-  max-height: 690px;
-}
-
-.oo-ui-dialog-content .oo-ui-window-head,
-.oo-ui-dialog-content .oo-ui-window-foot {
   z-index: 1;
 }
 
-.oo-ui-dialog-content .oo-ui-window-body {
+.oo-ui-dialog-content > .oo-ui-window-body {
+  top: 0;
+  bottom: 0;
   z-index: 2;
   box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
 }
 
-.oo-ui-dialog-content .oo-ui-window-foot {
+.oo-ui-dialog-content .oo-ui-window-foot {
   bottom: 0;
-  height: 4.8em;
-  padding: 1em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed {
-  margin: 0.125em 0.25em;
+  z-index: 1;
 }
 
-.oo-ui-dialog-content .oo-ui-window-overlay {
+.oo-ui-dialog-content .oo-ui-window-overlay {
   z-index: 3;
 }
 
   color: #000;
 }
 
-.oo-ui-window-body {
-  padding: 0 0.75em;
+.oo-ui-window-content {
+  background: transparent;
 }
 
-.oo-ui-window-icon {
-  width: 2em;
-  height: 2em;
-  margin-right: 0.5em;
-  line-height: 2em;
+.oo-ui-window-overlay {
+  font-family: sans-serif;
+  font-size: 1em;
+  line-height: 1.5em;
 }
 
-.oo-ui-window-title {
-  line-height: 2em;
-  color: #333;
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+  background-color: rgba(255, 255, 255, 0.5);
+  opacity: 0;
+  -webkit-transition: opacity 250ms ease-in-out;
+     -moz-transition: opacity 250ms ease-in-out;
+      -ms-transition: opacity 250ms ease-in-out;
+       -o-transition: opacity 250ms ease-in-out;
+          transition: opacity 250ms ease-in-out;
 }
 
-.oo-ui-window-overlay {
-  font-family: sans-serif;
-  font-size: 1em;
+.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
+  top: 1em;
+  bottom: 1em;
+  background-color: #fff;
+  -webkit-transform: scale(0.5);
+     -moz-transform: scale(0.5);
+      -ms-transform: scale(0.5);
+       -o-transform: scale(0.5);
+          transform: scale(0.5);
+  -webkit-transition: all 250ms ease-in-out;
+     -moz-transition: all 250ms ease-in-out;
+      -ms-transition: all 250ms ease-in-out;
+       -o-transition: all 250ms ease-in-out;
+          transition: all 250ms ease-in-out;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
+  opacity: 1;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
+  -webkit-transform: scale(1);
+     -moz-transform: scale(1);
+      -ms-transform: scale(1);
+       -o-transform: scale(1);
+          transform: scale(1);
+}
+
+.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
+  border: solid 1px #ccc;
+  border-radius: 0.5em;
+  box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
+}
+
+.oo-ui-messageDialog-content .oo-ui-window-body {
+  box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
+}
+
+.oo-ui-messageDialog-title,
+.oo-ui-messageDialog-message {
+  display: block;
+  padding-top: 0.5em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-title {
+  font-size: 1.5em;
+  line-height: 1em;
+  color: #000;
+}
+
+.oo-ui-messageDialog-message {
+  font-size: 0.9em;
+  line-height: 1.25em;
+  color: #666;
+}
+
+.oo-ui-messageDialog-message-verbose {
+  font-size: 1.1em;
   line-height: 1.5em;
+  text-align: left;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+  border-right: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
+  border-right-width: 0;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+  border-bottom: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
+  border-bottom-width: 0;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 2em;
+  line-height: 3.4em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
 }
 
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-content .oo-ui-window-head {
+  height: 3.4em;
+}
+
+.oo-ui-processDialog-content .oo-ui-window-body {
+  top: 3.4em;
+  box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
+}
+
+.oo-ui-processDialog-navigation {
+  position: relative;
+  height: 3.4em;
+  padding: 0 1em;
+}
+
+.oo-ui-processDialog-location {
+  height: 1.9em;
+  padding: 0.25em 0;
+  text-align: center;
+  cursor: default;
+}
+
+.oo-ui-processDialog-title {
+  font-weight: bold;
+  line-height: 1.9em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonedElement-button {
+  min-width: 1.9em;
+  min-height: 1.9em;
+  padding-top: 0.75em;
+  padding-bottom: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 1em;
+  line-height: 1.9em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconedElement-icon {
+  position: absolute;
+  margin-top: -0.125em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em 0 0.75em 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  padding: 0;
+  vertical-align: middle;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  /* Adjust for border so text aligns with title */
+
+  margin: -1px;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  left: 0.5em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-left: 2.25em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  right: 0.5em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-right: 2.25em;
+}
+
+.oo-ui-processDialog > .oo-ui-window-frame {
+  min-height: 5em;
+}
+
+.oo-ui-processDialog-errors {
+  padding: 3em 3em 1.5em 3em;
+  text-align: center;
+  background-color: rgba(255, 255, 255, 0.9);
+}
+
+.oo-ui-processDialog-errors .oo-ui-buttonWidget {
+  margin: 2em 1em 2em 1em;
+}
+
+.oo-ui-processDialog-errors-title {
+  margin-bottom: 2em;
+  font-size: 1.5em;
+  color: #000;
+}
+
+.oo-ui-processDialog-error {
+  padding: 1em;
+  margin: 1em;
+  text-align: left;
+  background-color: #fff7f7;
+  border: solid 1px #ff9e9e;
+  border-radius: 0.25em;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button {
   color: #333;
 }
 
-.oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
-.oo-ui-buttonedElement.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
   width: 1.9em;
   height: 1.9em;
   opacity: 0.8;
 }
 
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
   /* Don't animate opacities for now, causes wiggling in Chrome (bug 63020) */
 
   /*.oo-ui-transition(opacity 200ms);*/
 
 }
 
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-iconedElement-icon,
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-iconedElement-icon,
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-iconedElement-icon {
   opacity: 1;
 }
 
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-labeledElement-label,
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-labeledElement-label {
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-labeledElement-label,
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-labeledElement-label {
   color: #000;
 }
 
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
   color: #333;
 }
 
-.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement-frameless.oo-ui-flaggableElement-primary > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #087ecc;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-flaggableElement-constructive > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #76ab36;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-flaggableElement-destructive > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #d45353;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
   opacity: 0.2;
 }
 
-.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
   color: #ccc;
 }
 
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
   padding: 0.2em 0.8em;
   margin: 0.1em 0;
   text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
           transition: border-color 100ms ease-in-out;
 }
 
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:focus {
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:focus {
   border-color: #aaa;
 }
 
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
   color: black;
   background: #eeeeee;
   background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #dddddd), color-stop(100%, #ffffff));
   box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement-framed.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
   margin-right: -0.5em;
   margin-left: -0.5em;
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-iconedElement.oo-ui-labeledElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement-framed.oo-ui-iconedElement.oo-ui-labeledElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
   margin-right: 0.3em;
   margin-left: -0.5em;
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button {
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button {
   background: #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%);
   filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#eaf4fa', endColorstr='#b0d9ee');
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:focus {
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:focus {
   border-color: #9dc2d4;
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
   background: #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%);
   filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#b0d9ee', endColorstr='#eaf4fa');
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button {
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button {
   background: #daf0be;
   background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #f0fbe1), color-stop(100%, #c3e59a));
   background-image: -webkit-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
   filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f0fbe1', endColorstr='#c3e59a');
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:focus {
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:focus {
   border-color: #adcb89;
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
   background: #daf0be;
   background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #c3e59a), color-stop(100%, #f0fbe1));
   background-image: -webkit-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
   filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#c3e59a', endColorstr='#f0fbe1');
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-destructive .oo-ui-buttonedElement-button {
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-destructive .oo-ui-buttonedElement-button {
   color: #d45353;
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
   color: #333;
   background: #eee;
   border-color: #ccc;
   box-shadow: none;
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active:hover,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed:hover,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:focus,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active:focus,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed:focus {
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active:hover,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed:hover,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:focus,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active:focus,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed:focus {
   border-color: #ccc;
   box-shadow: none;
 }
   font-size: 1.5em;
 }
 
-.oo-ui-panelLayout {
-  position: absolute;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-}
-
 .oo-ui-panelLayout-padded {
-  padding: 2em;
+  padding: 1.25em;
 }
 
 .oo-ui-barToolGroup .oo-ui-tool {
   box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
 }
 
-.oo-ui-popupWidget-tailed .oo-ui-popupWidget-tail {
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
   width: 15px;
   height: 8px;
   margin-left: -7px;
-  background-image: /* @embed */ url(images/tail.svg);
+  background-image: /* @embed */ url(images/anchor.svg);
 }
 
 .oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
diff --git a/resources/lib/oojs-ui/oojs-ui-apex.rtl.css b/resources/lib/oojs-ui/oojs-ui-apex.rtl.css
new file mode 100644 (file)
index 0000000..3cbb677
--- /dev/null
@@ -0,0 +1,1103 @@
+/*!
+ * OOjs UI v0.1.0
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2014 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2014-07-22T21:39:24Z
+ */
+.oo-ui-dialog-content > .oo-ui-window-head,
+.oo-ui-dialog-content > .oo-ui-window-body,
+.oo-ui-dialog-content > .oo-ui-window-foot {
+  position: absolute;
+  left: 0;
+  right: 0;
+  overflow: hidden;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-dialog-content > .oo-ui-window-head {
+  top: 0;
+  z-index: 1;
+}
+
+.oo-ui-dialog-content > .oo-ui-window-body {
+  top: 0;
+  bottom: 0;
+  z-index: 2;
+  box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
+}
+
+.oo-ui-dialog-content > .oo-ui-window-foot {
+  bottom: 0;
+  z-index: 1;
+}
+
+.oo-ui-dialog-content > .oo-ui-window-overlay {
+  z-index: 3;
+}
+
+.oo-ui-frame-content {
+  font-family: sans-serif;
+  font-size: 0.8em;
+}
+
+.oo-ui-toolbar-bar {
+  background: #f8fbfd;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f1f7fb));
+  background-image: -webkit-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
+  background-image: -moz-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
+  background-image: -ms-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
+  background-image: -o-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
+  background-image: linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
+  border-bottom: solid 1px #ccc;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#f1f7fb');
+}
+
+.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
+  background: none;
+  border: none;
+}
+
+.oo-ui-toolbar-shadow {
+  bottom: -9px;
+  height: 9px;
+  background-image: /* @embed */ url(images/toolbar-shadow.png);
+  opacity: 0.125;
+  -webkit-transition: opacity 500ms ease-in-out;
+     -moz-transition: opacity 500ms ease-in-out;
+      -ms-transition: opacity 500ms ease-in-out;
+       -o-transition: opacity 500ms ease-in-out;
+          transition: opacity 500ms ease-in-out;
+}
+
+.oo-ui-toolGroup {
+  border: solid 1px transparent;
+  border-radius: 0.25em;
+  -webkit-transition: border-color 300ms ease-in-out;
+     -moz-transition: border-color 300ms ease-in-out;
+      -ms-transition: border-color 300ms ease-in-out;
+       -o-transition: border-color 300ms ease-in-out;
+          transition: border-color 300ms ease-in-out;
+}
+
+.oo-ui-toolGroup.oo-ui-widget-enabled:hover {
+  border-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-toolGroup.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-tool-title {
+  color: #000;
+}
+
+.oo-ui-window-content {
+  background: transparent;
+}
+
+.oo-ui-window-overlay {
+  font-family: sans-serif;
+  font-size: 1em;
+  line-height: 1.5em;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+  background-color: rgba(255, 255, 255, 0.5);
+  opacity: 0;
+  -webkit-transition: opacity 250ms ease-in-out;
+     -moz-transition: opacity 250ms ease-in-out;
+      -ms-transition: opacity 250ms ease-in-out;
+       -o-transition: opacity 250ms ease-in-out;
+          transition: opacity 250ms ease-in-out;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
+  top: 1em;
+  bottom: 1em;
+  background-color: #fff;
+  -webkit-transform: scale(0.5);
+     -moz-transform: scale(0.5);
+      -ms-transform: scale(0.5);
+       -o-transform: scale(0.5);
+          transform: scale(0.5);
+  -webkit-transition: all 250ms ease-in-out;
+     -moz-transition: all 250ms ease-in-out;
+      -ms-transition: all 250ms ease-in-out;
+       -o-transition: all 250ms ease-in-out;
+          transition: all 250ms ease-in-out;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
+  opacity: 1;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
+  -webkit-transform: scale(1);
+     -moz-transform: scale(1);
+      -ms-transform: scale(1);
+       -o-transform: scale(1);
+          transform: scale(1);
+}
+
+.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
+  border: solid 1px #ccc;
+  border-radius: 0.5em;
+  box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
+}
+
+.oo-ui-messageDialog-content .oo-ui-window-body {
+  box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
+}
+
+.oo-ui-messageDialog-title,
+.oo-ui-messageDialog-message {
+  display: block;
+  padding-top: 0.5em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-title {
+  font-size: 1.5em;
+  line-height: 1em;
+  color: #000;
+}
+
+.oo-ui-messageDialog-message {
+  font-size: 0.9em;
+  line-height: 1.25em;
+  color: #666;
+}
+
+.oo-ui-messageDialog-message-verbose {
+  font-size: 1.1em;
+  line-height: 1.5em;
+  text-align: right;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+  border-left: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
+  border-left-width: 0;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+  border-bottom: solid 1px #e5e5e5;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
+  border-bottom-width: 0;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 2em;
+  line-height: 3.4em;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-content .oo-ui-window-head {
+  height: 3.4em;
+}
+
+.oo-ui-processDialog-content .oo-ui-window-body {
+  top: 3.4em;
+  box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
+}
+
+.oo-ui-processDialog-navigation {
+  position: relative;
+  height: 3.4em;
+  padding: 0 1em;
+}
+
+.oo-ui-processDialog-location {
+  height: 1.9em;
+  padding: 0.25em 0;
+  text-align: center;
+  cursor: default;
+}
+
+.oo-ui-processDialog-title {
+  font-weight: bold;
+  line-height: 1.9em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonedElement-button {
+  min-width: 1.9em;
+  min-height: 1.9em;
+  padding-top: 0.75em;
+  padding-bottom: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  padding: 0 1em;
+  line-height: 1.9em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconedElement-icon,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconedElement-icon {
+  position: absolute;
+  margin-top: -0.125em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em 0.75em 0.75em 0;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  padding: 0;
+  vertical-align: middle;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed {
+  margin: 0.75em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  /* Adjust for border so text aligns with title */
+
+  margin: -1px;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:hover {
+  background-color: rgba(8, 126, 204, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary:active {
+  background-color: rgba(8, 126, 204, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-primary .oo-ui-labeledElement-label {
+  font-weight: bold;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:hover {
+  background-color: rgba(118, 171, 54, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-constructive:active {
+  background-color: rgba(118, 171, 54, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:hover {
+  background-color: rgba(212, 83, 83, 0.05);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggableElement-destructive:active {
+  background-color: rgba(212, 83, 83, 0.1);
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  right: 0.5em;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-right: 2.25em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon {
+  left: 0.5em;
+}
+
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconedElement .oo-ui-labeledElement-label {
+  padding-left: 2.25em;
+}
+
+.oo-ui-processDialog > .oo-ui-window-frame {
+  min-height: 5em;
+}
+
+.oo-ui-processDialog-errors {
+  padding: 3em 3em 1.5em 3em;
+  text-align: center;
+  background-color: rgba(255, 255, 255, 0.9);
+}
+
+.oo-ui-processDialog-errors .oo-ui-buttonWidget {
+  margin: 2em 1em 2em 1em;
+}
+
+.oo-ui-processDialog-errors-title {
+  margin-bottom: 2em;
+  font-size: 1.5em;
+  color: #000;
+}
+
+.oo-ui-processDialog-error {
+  padding: 1em;
+  margin: 1em;
+  text-align: right;
+  background-color: #fff7f7;
+  border: solid 1px #ff9e9e;
+  border-radius: 0.25em;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button {
+  color: #333;
+}
+
+.oo-ui-buttonedElement.oo-ui-indicatedElement > .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement.oo-ui-iconedElement > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  width: 1.9em;
+  height: 1.9em;
+  opacity: 0.8;
+}
+
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  /* Don't animate opacities for now, causes wiggling in Chrome (bug 63020) */
+
+  /*.oo-ui-transition(opacity 200ms);*/
+
+}
+
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button:hover > .oo-ui-iconedElement-icon,
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button:focus > .oo-ui-iconedElement-icon {
+  opacity: 1;
+}
+
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button:hover > .oo-ui-labeledElement-label,
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button:focus > .oo-ui-labeledElement-label {
+  color: #000;
+}
+
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #333;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-flaggableElement-primary > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #087ecc;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-flaggableElement-constructive > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #76ab36;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-flaggableElement-destructive > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #d45353;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  color: #ccc;
+}
+
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button {
+  padding: 0.2em 0.8em;
+  margin: 0.1em 0;
+  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
+  background: #eeeeee;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #dddddd));
+  background-image: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: -moz-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: -ms-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  border: 1px #c9c9c9 solid;
+  border-radius: 0.3em;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#dddddd');
+  -webkit-transition: border-color 100ms ease-in-out;
+     -moz-transition: border-color 100ms ease-in-out;
+      -ms-transition: border-color 100ms ease-in-out;
+       -o-transition: border-color 100ms ease-in-out;
+          transition: border-color 100ms ease-in-out;
+}
+
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button:focus {
+  border-color: #aaa;
+}
+
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+  color: black;
+  background: #eeeeee;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dddddd), color-stop(100%, #ffffff));
+  background-image: -webkit-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: -moz-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: -ms-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  border-color: #c9c9c9;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#dddddd', endColorstr='#ffffff');
+  box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-iconedElement > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  margin-left: -0.5em;
+  margin-right: -0.5em;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-iconedElement.oo-ui-labeledElement > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  margin-left: 0.3em;
+  margin-right: -0.5em;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary > .oo-ui-buttonedElement-button {
+  background: #cde7f4;
+  background-image: -webkit-gradient(linear, left top, left 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: -ms-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+  background-image: -o-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+  background-image: linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+  border: solid 1px #a6cee1;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#eaf4fa', endColorstr='#b0d9ee');
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary > .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary > .oo-ui-buttonedElement-button:focus {
+  border-color: #9dc2d4;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+  background: #cde7f4;
+  background-image: -webkit-gradient(linear, left top, left 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: -ms-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+  background-image: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+  background-image: linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+  border: solid 1px #a6cee1;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#b0d9ee', endColorstr='#eaf4fa');
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive > .oo-ui-buttonedElement-button {
+  background: #daf0be;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f0fbe1), color-stop(100%, #c3e59a));
+  background-image: -webkit-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+  background-image: -moz-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+  background-image: -ms-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+  background-image: -o-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+  background-image: linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+  border: solid 1px #b8d892;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f0fbe1', endColorstr='#c3e59a');
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive > .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive > .oo-ui-buttonedElement-button:focus {
+  border-color: #adcb89;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+  background: #daf0be;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #c3e59a), color-stop(100%, #f0fbe1));
+  background-image: -webkit-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+  background-image: -moz-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+  background-image: -ms-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+  background-image: -o-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+  background-image: linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+  border: solid 1px #b8d892;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#c3e59a', endColorstr='#f0fbe1');
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-destructive > .oo-ui-buttonedElement-button {
+  color: #d45353;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+  color: #333;
+  background: #eee;
+  border-color: #ccc;
+  opacity: 0.5;
+  box-shadow: none;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active:hover,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed:hover,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button:focus,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active:focus,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed:focus {
+  border-color: #ccc;
+  box-shadow: none;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
+  padding: 1.5em;
+}
+
+.oo-ui-bookletLayout-outlinePanel {
+  border-left: solid 1px #ddd;
+}
+
+.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
+  box-shadow: 0 0 0.25em rgba(0, 0, 0, 0.25);
+}
+
+.oo-ui-fieldLayout-disabled .oo-ui-labeledElement-label {
+  color: #ccc;
+}
+
+.oo-ui-fieldsetLayout {
+  border: none;
+}
+
+.oo-ui-fieldsetLayout > .oo-ui-labeledElement-label {
+  font-size: 1.5em;
+}
+
+.oo-ui-panelLayout-padded {
+  padding: 1.25em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool {
+  margin: -1px -1px -1px 0;
+  border: solid 1px transparent;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool:first-child {
+  border-bottom-right-radius: 0.25em;
+  border-top-right-radius: 0.25em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool:last-child {
+  margin-left: -1px;
+  border-top-left-radius: 0.25em;
+  border-bottom-left-radius: 0.25em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 0.8;
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled:hover {
+  border-color: rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-active.oo-ui-widget-enabled {
+  background: #f8fbfd;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
+  background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  border-color: rgba(0, 0, 0, 0.2);
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
+  box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
+  border-right-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 0.8;
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 1;
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
+  border-color: rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool {
+  margin: -1px 0;
+  border: solid 1px transparent;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
+  background: #f8fbfd;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
+  background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  border-color: rgba(0, 0, 0, 0.1);
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
+  box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
+  border-top-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
+  border-color: rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
+  border-color: rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 0.8;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 1;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
+  color: #ccc;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-listToolGroup.oo-ui-widget-disabled {
+  color: #ccc;
+}
+
+.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-indicatedElement-indicator,
+.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-menuToolGroup {
+  border-color: rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-menuToolGroup.oo-ui-widget-enabled:hover {
+  border-color: rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-menuToolGroup.oo-ui-popupToolGroup-active {
+  border-color: rgba(0, 0, 0, 0.25);
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
+  background-color: #e1f3ff;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
+  color: #ccc;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-menuToolGroup.oo-ui-widget-disabled {
+  color: #ccc;
+  border-color: rgba(0, 0, 0, 0.05);
+}
+
+.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-indicatedElement-indicator,
+.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator,
+.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
+  opacity: 0.8;
+}
+
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+  background-color: white;
+  border: solid 1px #ccc;
+  box-shadow: 0 0.25em 1em rgba(0, 0, 0, 0.25);
+}
+
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled {
+  background: #f8fbfd;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
+  background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+  border-bottom-left-radius: 0;
+  border-bottom-right-radius: 0;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
+  box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+}
+
+.oo-ui-optionWidget {
+  padding: 0.5em 3em 0.5em 2em;
+}
+
+.oo-ui-optionWidget-highlighted {
+  background-color: #e1f3ff;
+}
+
+.oo-ui-selectWidget-depressed .oo-ui-optionWidget-selected {
+  background-color: #a7dcff;
+}
+
+.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed {
+  background-color: #a7dcff;
+}
+
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+  color: #ccc;
+}
+
+.oo-ui-menuWidget {
+  margin-top: -1px;
+  background: #fff;
+  border: solid 1px #ccc;
+  border-radius: 0 0 0.25em 0.25em;
+  box-shadow: 0 0.15em 1em 0 rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-popupWidget-popup {
+  background-color: #fff;
+  border: solid 1px #ccc;
+  border-radius: 0.25em;
+  box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
+  width: 15px;
+  height: 8px;
+  margin-right: -7px;
+  background-image: /* @embed */ url(images/anchor.svg);
+}
+
+.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
+  -webkit-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
+     -moz-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
+      -ms-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
+       -o-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
+          transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
+}
+
+.oo-ui-popupWidget-body {
+  box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
+}
+
+.oo-ui-buttonGroupWidget {
+  display: inline-block;
+  white-space: nowrap;
+}
+
+.oo-ui-buttonOptionWidget {
+  padding: 0;
+}
+
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-pressed,
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-highlighted {
+  background-color: transparent;
+}
+
+.oo-ui-buttonSelectWidget {
+  border-radius: 0.3em;
+}
+
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonedElement-button {
+  margin-right: -1px;
+  border-radius: 0;
+}
+
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonedElement-button {
+  margin-right: 0;
+  border-bottom-right-radius: 0.3em;
+  border-top-right-radius: 0.3em;
+}
+
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonedElement-button {
+  border-top-left-radius: 0.3em;
+  border-bottom-left-radius: 0.3em;
+}
+
+.oo-ui-inlineMenuWidget-handle {
+  border: solid 1px rgba(0, 0, 0, 0.1);
+  border-radius: 0.25em;
+}
+
+.oo-ui-inlineMenuWidget-handle:hover {
+  border-color: rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-indicatedElement-indicator,
+.oo-ui-inlineMenuWidget-handle .oo-ui-iconedElement-icon {
+  opacity: 0.8;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
+  color: #ccc;
+  text-shadow: 0 1px 1px #fff;
+  background-color: #f3f3f3;
+  border-color: #ddd;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-indicatedElement-indicator {
+  opacity: 0.2;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
+  background-color: transparent;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted,
+.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted.oo-ui-optionWidget-selected {
+  background-color: #e1f3ff;
+}
+
+.oo-ui-menuSectionItemWidget {
+  padding: 0.33em 0.75em;
+  color: #888;
+}
+
+.oo-ui-outlineControlsWidget {
+  background-color: #fff;
+}
+
+.oo-ui-outlineControlsWidget > .oo-ui-iconedElement-icon {
+  opacity: 0.2;
+}
+
+.oo-ui-outlineItemWidget {
+  font-size: 1.1em;
+}
+
+.oo-ui-outlineItemWidget.oo-ui-indicatedElement .oo-ui-labeledElement-label {
+  padding-left: 1.5em;
+}
+
+.oo-ui-outlineItemWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator {
+  opacity: 0.5;
+}
+
+.oo-ui-outlineItemWidget-level-0 {
+  padding-right: 3.5em;
+}
+
+.oo-ui-outlineItemWidget-level-0 .oo-ui-iconedElement-icon {
+  right: 1em;
+}
+
+.oo-ui-outlineItemWidget-level-1 {
+  padding-right: 5em;
+}
+
+.oo-ui-outlineItemWidget-level-1 .oo-ui-iconedElement-icon {
+  right: 2.5em;
+}
+
+.oo-ui-outlineItemWidget-level-2 {
+  padding-right: 6.5em;
+}
+
+.oo-ui-outlineItemWidget-level-2 .oo-ui-iconedElement-icon {
+  right: 4em;
+}
+
+.oo-ui-selectWidget-depressed .oo-ui-outlineItemWidget.oo-ui-optionWidget-selected {
+  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
+  background-color: #a7dcff;
+}
+
+.oo-ui-outlineItemWidget.oo-ui-flaggableElement-important {
+  font-weight: bold;
+}
+
+.oo-ui-outlineItemWidget.oo-ui-flaggableElement-placeholder {
+  font-style: italic;
+}
+
+.oo-ui-outlineItemWidget.oo-ui-flaggableElement-empty .oo-ui-iconedElement-icon {
+  opacity: 0.5;
+}
+
+.oo-ui-outlineItemWidget.oo-ui-flaggableElement-empty .oo-ui-labeledElement-label {
+  color: #777;
+}
+
+.oo-ui-searchWidget-query {
+  box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-textInputWidget {
+  width: 20em;
+}
+
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+  padding: 0.5em;
+  font-family: sans-serif;
+  font-size: 1em;
+  background-color: #fff;
+  border: solid 1px #ccc;
+  border-radius: 0.25em;
+  box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
+  -webkit-transition: border-color 200ms, box-shadow 200ms;
+     -moz-transition: border-color 200ms, box-shadow 200ms;
+      -ms-transition: border-color 200ms, box-shadow 200ms;
+       -o-transition: border-color 200ms, box-shadow 200ms;
+          transition: border-color 200ms, box-shadow 200ms;
+}
+
+.oo-ui-textInputWidget-decorated input,
+.oo-ui-textInputWidget-decorated textarea {
+  padding-right: 2em;
+}
+
+.oo-ui-textInputWidget-icon {
+  width: 2em;
+}
+
+.oo-ui-textInputWidget.oo-ui-widget-enabled input:focus,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:focus {
+  border-color: #a7dcff;
+  outline: none;
+  box-shadow: 0 0 0.3em #a7dcff, 0 0 0 white;
+}
+
+.oo-ui-textInputWidget input[readonly],
+.oo-ui-textInputWidget textarea[readonly] {
+  color: #777;
+  text-shadow: 0 1px 1px #fff;
+}
+
+.oo-ui-textInputWidget-pending input,
+.oo-ui-textInputWidget-pending textarea {
+  background-color: transparent;
+}
+
+.oo-ui-textInputWidget.oo-ui-widget-disabled input,
+.oo-ui-textInputWidget.oo-ui-widget-disabled input:focus,
+.oo-ui-textInputWidget.oo-ui-widget-disabled textarea,
+.oo-ui-textInputWidget.oo-ui-widget-disabled textarea:focus {
+  color: #ccc;
+  text-shadow: 0 1px 1px #fff;
+  background-color: #f3f3f3;
+  border-color: #ddd;
+}
+
+.oo-ui-toggleSwitchWidget {
+  background: #eeeeee;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dddddd), color-stop(100%, #ffffff));
+  background-image: -webkit-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: -moz-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: -ms-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  background-image: linear-gradient(top, #dddddd 0%, #ffffff 100%);
+  border: solid 1px #ccc;
+  border-radius: 1em;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#dddddd', endColorstr='#ffffff');
+  box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
+}
+
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
+  opacity: 0.5;
+}
+
+.oo-ui-toggleSwitchWidget-grip {
+  background: #eeeeee;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #dddddd));
+  background-image: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: -moz-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: -ms-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  background-image: linear-gradient(top, #ffffff 0%, #dddddd 100%);
+  border: 1px #c9c9c9 solid;
+  border-radius: 1em;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#dddddd');
+  box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
+}
+
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover,
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover .oo-ui-toggleSwitchWidget-grip {
+  border-color: #aaa;
+}
+
+.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
+  background: #cde7f4;
+  background-image: -webkit-gradient(linear, left top, left 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: -ms-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+  background-image: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+  background-image: linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+  border-radius: 1em;
+  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#b0d9ee', endColorstr='#eaf4fa');
+  box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
+}
+
+.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-glow {
+  opacity: 1;
+}
+
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+  display: block;
+  opacity: 0;
+}
\ No newline at end of file
index 0262042..170d207 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.1.0-pre (a63f03882e)
+ * OOjs UI v0.1.0-pre (9cd400e3d5)
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-06-27T23:51:18Z
+ * Date: 2014-07-22T21:59:46Z
  */
 ( function ( OO ) {
 
@@ -94,7 +94,6 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
 };
 
 ( function () {
-
        /**
         * Message store for the default implementation of OO.ui.msg
         *
@@ -104,8 +103,6 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
         * @private
         */
        var messages = {
-               // Label text for button to exit from dialog
-               'ooui-dialog-action-close': 'Close',
                // 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
@@ -114,15 +111,16 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
                '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 generic dialog used to confirm things
-               'ooui-dialog-confirm-title': 'Confirm',
-               // The default prompt of a confirmation dialog
-               'ooui-dialog-confirm-default-prompt': 'Are you sure?',
-               // The default OK button text on a confirmation dialog
-               'ooui-dialog-confirm-default-ok': 'OK',
-               // The default cancel button text on a confirmation dialog
-               'ooui-dialog-confirm-default-cancel': 'Cancel'
+               // 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 recoverable errors
+               'ooui-dialog-process-retry': 'Try again'
        };
 
        /**
@@ -157,14 +155,30 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
                return message;
        };
 
-       /** */
-       OO.ui.deferMsg = function ( key ) {
+       /**
+        * Package a message and arguments for deferred resolution.
+        *
+        * Use this when you are statically specifying a message and the message may not yet be present.
+        *
+        * @param {string} key Message key
+        * @param {Mixed...} [params] Message parameters
+        * @return {Function} Function that returns the resolved message when executed
+        */
+       OO.ui.deferMsg = function () {
+               var args = arguments;
                return function () {
-                       return OO.ui.msg( key );
+                       return OO.ui.msg.apply( OO.ui, args );
                };
        };
 
-       /** */
+       /**
+        * Resolve a message.
+        *
+        * If the message is a function it will be executed, otherwise it will pass through directly.
+        *
+        * @param {Function|string} msg Deferred message, or message text
+        * @return {string} Resolved message
+        */
        OO.ui.resolveMsg = function ( msg ) {
                if ( $.isFunction( msg ) ) {
                        return msg();
@@ -174,6 +188,414 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
 
 } )();
 
+/**
+ * List of actions.
+ *
+ * @abstract
+ * @class
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.ActionSet = function OoUiActionSet( config ) {
+       // Configuration intialization
+       config = config || {};
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       // Properties
+       this.list = [];
+       this.categories = {
+               'actions': 'getAction',
+               'flags': 'getFlags',
+               'modes': 'getModes'
+       };
+       this.categorized = {};
+       this.special = {};
+       this.others = [];
+       this.organized = false;
+       this.changing = false;
+       this.changed = false;
+};
+
+/* Setup */
+
+OO.mixinClass( OO.ui.ActionSet, OO.EventEmitter );
+
+/* Static Properties */
+
+/**
+ * Symbolic name of dialog.
+ *
+ * @abstract
+ * @static
+ * @inheritable
+ * @property {string}
+ */
+OO.ui.ActionSet.static.specialFlags = [ 'safe', 'primary' ];
+
+/* Events */
+
+/**
+ * @event click
+ * @param {OO.ui.ActionWidget} action Action that was clicked
+ */
+
+/**
+ * @event resize
+ * @param {OO.ui.ActionWidget} action Action that was resized
+ */
+
+/**
+ * @event add
+ * @param {OO.ui.ActionWidget[]} added Actions added
+ */
+
+/**
+ * @event remove
+ * @param {OO.ui.ActionWidget[]} added Actions removed
+ */
+
+/**
+ * @event change
+ */
+
+/* Methods */
+
+/**
+ * Handle action change events.
+ *
+ * @fires change
+ */
+OO.ui.ActionSet.prototype.onActionChange = function () {
+       this.organized = false;
+       if ( this.changing ) {
+               this.changed = true;
+       } else {
+               this.emit( 'change' );
+       }
+};
+
+/**
+ * Check if a action is one of the special actions.
+ *
+ * @param {OO.ui.ActionWidget} action Action to check
+ * @return {boolean} Action is special
+ */
+OO.ui.ActionSet.prototype.isSpecial = function ( action ) {
+       var flag;
+
+       for ( flag in this.special ) {
+               if ( action === this.special[flag] ) {
+                       return true;
+               }
+       }
+
+       return false;
+};
+
+/**
+ * Get actions.
+ *
+ * @param {Object} [filters] Filters to use, omit to get all actions
+ * @param {string|string[]} [filters.actions] Actions that actions must have
+ * @param {string|string[]} [filters.flags] Flags that actions must have
+ * @param {string|string[]} [filters.modes] Modes that actions must have
+ * @param {boolean} [filters.visible] Actions must be visible
+ * @param {boolean} [filters.disabled] Actions must be disabled
+ * @return {OO.ui.ActionWidget[]} Actions matching all criteria
+ */
+OO.ui.ActionSet.prototype.get = function ( filters ) {
+       var i, len, list, category, actions, index, match, matches;
+
+       if ( filters ) {
+               this.organize();
+
+               // Collect category candidates
+               matches = [];
+               for ( category in this.categorized ) {
+                       list = filters[category];
+                       if ( list ) {
+                               if ( !Array.isArray( list ) ) {
+                                       list = [ list ];
+                               }
+                               for ( i = 0, len = list.length; i < len; i++ ) {
+                                       actions = this.categorized[category][list[i]];
+                                       if ( Array.isArray( actions ) ) {
+                                               matches.push.apply( matches, actions );
+                                       }
+                               }
+                       }
+               }
+               // Remove by boolean filters
+               for ( i = 0, len = matches.length; i < len; i++ ) {
+                       match = matches[i];
+                       if (
+                               ( filters.visible !== undefined && match.isVisible() !== filters.visible ) ||
+                               ( filters.disabled !== undefined && match.isDisabled() !== filters.disabled )
+                       ) {
+                               matches.splice( i, 1 );
+                               len--;
+                               i--;
+                       }
+               }
+               // Remove duplicates
+               for ( i = 0, len = matches.length; i < len; i++ ) {
+                       match = matches[i];
+                       index = matches.lastIndexOf( match );
+                       while ( index !== i ) {
+                               matches.splice( index, 1 );
+                               len--;
+                               index = matches.lastIndexOf( match );
+                       }
+               }
+               return matches;
+       }
+       return this.list.slice();
+};
+
+/**
+ * Get special actions.
+ *
+ * Special actions are the first visible actions with special flags, such as 'safe' and 'primary'.
+ * Special flags can be configured by changing #static-specialFlags in a subclass.
+ *
+ * @return {OO.ui.ActionWidget|null} Safe action
+ */
+OO.ui.ActionSet.prototype.getSpecial = function () {
+       this.organize();
+       return $.extend( {}, this.special );
+};
+
+/**
+ * Get other actions.
+ *
+ * Other actions include all non-special visible actions.
+ *
+ * @return {OO.ui.ActionWidget[]} Other actions
+ */
+OO.ui.ActionSet.prototype.getOthers = function () {
+       this.organize();
+       return this.others.slice();
+};
+
+/**
+ * Toggle actions based on their modes.
+ *
+ * Unlike calling toggle on actions with matching flags, this will enforce mutually exclusive
+ * visibility; matching actions will be shown, non-matching actions will be hidden.
+ *
+ * @param {string} mode Mode actions must have
+ * @chainable
+ * @fires toggle
+ * @fires change
+ */
+OO.ui.ActionSet.prototype.setMode = function ( mode ) {
+       var i, len, action;
+
+       this.changing = true;
+       for ( i = 0, len = this.list.length; i < len; i++ ) {
+               action = this.list[i];
+               action.toggle( action.hasMode( mode ) );
+       }
+
+       this.organized = false;
+       this.changing = false;
+       this.emit( 'change' );
+
+       return this;
+};
+
+/**
+ * Change which actions are able to be performed.
+ *
+ * Actions with matching actions will be disabled/enabled. Other actions will not be changed.
+ *
+ * @param {Object.<string,boolean>} actions List of abilities, keyed by action name, values
+ *   indicate actions are able to be performed
+ * @chainable
+ */
+OO.ui.ActionSet.prototype.setAbilities = function ( actions ) {
+       var i, len, action, item;
+
+       for ( i = 0, len = this.list.length; i < len; i++ ) {
+               item = this.list[i];
+               action = item.getAction();
+               if ( actions[action] !== undefined ) {
+                       item.setDisabled( !actions[action] );
+               }
+       }
+
+       return this;
+};
+
+/**
+ * Executes a function once per action.
+ *
+ * When making changes to multiple actions, use this method instead of iterating over the actions
+ * manually to defer emitting a change event until after all actions have been changed.
+ *
+ * @param {Object|null} actions Filters to use for which actions to iterate over; see #get
+ * @param {Function} callback Callback to run for each action; callback is invoked with three
+ *   arguments: the action, the action's index, the list of actions being iterated over
+ * @chainable
+ */
+OO.ui.ActionSet.prototype.forEach = function ( filter, callback ) {
+       this.changed = false;
+       this.changing = true;
+       this.get( filter ).forEach( callback );
+       this.changing = false;
+       if ( this.changed ) {
+               this.emit( 'change' );
+       }
+
+       return this;
+};
+
+/**
+ * Add actions.
+ *
+ * @param {OO.ui.ActionWidget[]} actions Actions to add
+ * @chainable
+ * @fires add
+ * @fires change
+ */
+OO.ui.ActionSet.prototype.add = function ( actions ) {
+       var i, len, action;
+
+       this.changing = true;
+       for ( i = 0, len = actions.length; i < len; i++ ) {
+               action = actions[i];
+               action.connect( this, {
+                       'click': [ 'emit', 'click', action ],
+                       'resize': [ 'emit', 'resize', action ],
+                       'toggle': [ 'onActionChange' ]
+               } );
+               this.list.push( action );
+       }
+       this.organized = false;
+       this.emit( 'add', actions );
+       this.changing = false;
+       this.emit( 'change' );
+
+       return this;
+};
+
+/**
+ * Remove actions.
+ *
+ * @param {OO.ui.ActionWidget[]} actions Actions to remove
+ * @chainable
+ * @fires remove
+ * @fires change
+ */
+OO.ui.ActionSet.prototype.remove = function ( actions ) {
+       var i, len, index, action;
+
+       this.changing = true;
+       for ( i = 0, len = actions.length; i < len; i++ ) {
+               action = actions[i];
+               index = this.list.indexOf( action );
+               if ( index !== -1 ) {
+                       action.disconnect( this );
+                       this.list.splice( index, 1 );
+               }
+       }
+       this.organized = false;
+       this.emit( 'remove', actions );
+       this.changing = false;
+       this.emit( 'change' );
+
+       return this;
+};
+
+/**
+ * Remove all actions.
+ *
+ * @chainable
+ * @fires remove
+ * @fires change
+ */
+OO.ui.ActionSet.prototype.clear = function () {
+       var i, len, action,
+               removed = this.list.slice();
+
+       this.changing = true;
+       for ( i = 0, len = this.list.length; i < len; i++ ) {
+               action = this.list[i];
+               action.disconnect( this );
+       }
+
+       this.list = [];
+
+       this.organized = false;
+       this.emit( 'remove', removed );
+       this.changing = false;
+       this.emit( 'change' );
+
+       return this;
+};
+
+/**
+ * Organize actions.
+ *
+ * This is called whenver organized information is requested. It will only reorganize the actions
+ * if something has changed since the last time it ran.
+ *
+ * @private
+ * @chainable
+ */
+OO.ui.ActionSet.prototype.organize = function () {
+       var i, iLen, j, jLen, flag, action, category, list, item, special,
+               specialFlags = this.constructor.static.specialFlags;
+
+       if ( !this.organized ) {
+               this.categorized = {};
+               this.special = {};
+               this.others = [];
+               for ( i = 0, iLen = this.list.length; i < iLen; i++ ) {
+                       action = this.list[i];
+                       if ( action.isVisible() ) {
+                               // Populate catgeories
+                               for ( category in this.categories ) {
+                                       if ( !this.categorized[category] ) {
+                                               this.categorized[category] = {};
+                                       }
+                                       list = action[this.categories[category]]();
+                                       if ( !Array.isArray( list ) ) {
+                                               list = [ list ];
+                                       }
+                                       for ( j = 0, jLen = list.length; j < jLen; j++ ) {
+                                               item = list[j];
+                                               if ( !this.categorized[category][item] ) {
+                                                       this.categorized[category][item] = [];
+                                               }
+                                               this.categorized[category][item].push( action );
+                                       }
+                               }
+                               // Populate special/others
+                               special = false;
+                               for ( j = 0, jLen = specialFlags.length; j < jLen; j++ ) {
+                                       flag = specialFlags[j];
+                                       if ( !this.special[flag] && action.hasFlag( flag ) ) {
+                                               this.special[flag] = action;
+                                               special = true;
+                                               break;
+                                       }
+                               }
+                               if ( !special ) {
+                                       this.others.push( action );
+                               }
+                       }
+               }
+               this.organized = true;
+       }
+
+       return this;
+};
+
 /**
  * DOM element abstraction.
  *
@@ -750,6 +1172,9 @@ OO.ui.Frame.static.transplantStyles = function ( parentDoc, frameDoc, timeout )
 
        for ( i = 0, numSheets = parentDoc.styleSheets.length; i < numSheets; i++ ) {
                styleNode = parentDoc.styleSheets[i].ownerNode;
+               if ( styleNode.disabled ) {
+                       continue;
+               }
                if ( styleNode.nodeName.toLowerCase() === 'link' ) {
                        // External stylesheet
                        // Create a node with a unique ID that we're going to monitor to see when the CSS
@@ -848,7 +1273,8 @@ OO.ui.Frame.static.transplantStyles = function ( parentDoc, frameDoc, timeout )
  * @fires load
  */
 OO.ui.Frame.prototype.load = function () {
-       var win, doc;
+       var win, doc,
+               frame = this;
 
        // Return existing promise if already loading or loaded
        if ( this.loading ) {
@@ -869,8 +1295,7 @@ OO.ui.Frame.prototype.load = function () {
        doc.write(
                '<!doctype html>' +
                '<html>' +
-                       '<body class="oo-ui-frame-body oo-ui-' + this.dir + '" style="direction:' + this.dir + ';" dir="' + this.dir + '">' +
-                               '<div class="oo-ui-frame-content"></div>' +
+                       '<body class="oo-ui-frame-content oo-ui-' + this.dir + '" style="direction:' + this.dir + ';" dir="' + this.dir + '">' +
                        '</body>' +
                '</html>'
        );
@@ -883,10 +1308,10 @@ OO.ui.Frame.prototype.load = function () {
 
        // Initialization
        this.constructor.static.transplantStyles( this.getElementDocument(), this.$document[0] )
-               .always( OO.ui.bind( function () {
-                       this.emit( 'load' );
-                       this.loading.resolve();
-               }, this ) );
+               .always( function () {
+                       frame.emit( 'load' );
+                       frame.loading.resolve();
+               } );
 
        return this.loading.promise();
 };
@@ -904,10 +1329,7 @@ OO.ui.Frame.prototype.setSize = function ( width, height ) {
 };
 
 /**
- * Container for elements in a child frame.
- *
- * There are two ways to specify a title: set the static `title` property or provide a `title`
- * property in the configuration options. The latter will override the former.
+ * Container for elements.
  *
  * @abstract
  * @class
@@ -916,305 +1338,369 @@ OO.ui.Frame.prototype.setSize = function ( width, height ) {
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title string or function that returns a string
- * @cfg {string} [icon] Symbolic name of icon
- * @fires initialize
  */
-OO.ui.Window = function OoUiWindow( config ) {
-       var element = this;
+OO.ui.Layout = function OoUiLayout( config ) {
+       // Initialize config
+       config = config || {};
+
        // Parent constructor
-       OO.ui.Window.super.call( this, config );
+       OO.ui.Layout.super.call( this, config );
 
        // Mixin constructors
        OO.EventEmitter.call( this );
 
-       // Properties
-       this.visible = false;
-       this.opening = null;
-       this.closing = null;
-       this.opened = null;
-       this.title = OO.ui.resolveMsg( config.title || this.constructor.static.title );
-       this.icon = config.icon || this.constructor.static.icon;
-       this.frame = new OO.ui.Frame( { '$': this.$ } );
-       this.$frame = this.$( '<div>' );
-       this.$ = function () {
-               throw new Error( 'this.$() cannot be used until the frame has been initialized.' );
-       };
-
        // Initialization
-       this.$element
-               .addClass( 'oo-ui-window' )
-               // Hide the window using visibility: hidden; while the iframe is still loading
-               // Can't use display: none; because that prevents the iframe from loading in Firefox
-               .css( 'visibility', 'hidden' )
-               .append( this.$frame );
-       this.$frame
-               .addClass( 'oo-ui-window-frame' )
-               .append( this.frame.$element );
-
-       // Events
-       this.frame.on( 'load', function () {
-               element.initialize();
-               // Undo the visibility: hidden; hack and apply display: none;
-               // We can do this safely now that the iframe has initialized
-               // (don't do this from within #initialize because it has to happen
-               // after the all subclasses have been handled as well).
-               element.$element.hide().css( 'visibility', '' );
-       } );
+       this.$element.addClass( 'oo-ui-layout' );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.Window, OO.ui.Element );
-OO.mixinClass( OO.ui.Window, OO.EventEmitter );
-
-/* Events */
+OO.inheritClass( OO.ui.Layout, OO.ui.Element );
+OO.mixinClass( OO.ui.Layout, OO.EventEmitter );
 
 /**
- * Window is setup.
+ * User interface control.
  *
- * Fired after the setup process has been executed.
+ * @abstract
+ * @class
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
  *
- * @event setup
- * @param {Object} data Window opening data
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [disabled=false] Disable
  */
+OO.ui.Widget = function OoUiWidget( config ) {
+       // Initialize config
+       config = $.extend( { 'disabled': false }, config );
+
+       // Parent constructor
+       OO.ui.Widget.super.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       // Properties
+       this.visible = true;
+       this.disabled = null;
+       this.wasDisabled = null;
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-widget' );
+       this.setDisabled( !!config.disabled );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.Widget, OO.ui.Element );
+OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
+
+/* Events */
 
 /**
- * Window is ready.
- *
- * Fired after the ready process has been executed.
- *
- * @event ready
- * @param {Object} data Window opening data
+ * @event disable
+ * @param {boolean} disabled Widget is disabled
  */
 
 /**
- * Window is torn down
- *
- * Fired after the teardown process has been executed.
- *
- * @event teardown
- * @param {Object} data Window closing data
+ * @event toggle
+ * @param {boolean} visible Widget is visible
  */
 
-/* Static Properties */
+/* Methods */
 
 /**
- * Symbolic name of icon.
+ * Check if the widget is disabled.
  *
- * @static
- * @inheritable
- * @property {string}
+ * @param {boolean} Button is disabled
  */
-OO.ui.Window.static.icon = 'window';
+OO.ui.Widget.prototype.isDisabled = function () {
+       return this.disabled;
+};
 
 /**
- * Window title.
+ * Check if widget is visible.
  *
- * Subclasses must implement this property before instantiating the window.
- * Alternatively, override #getTitle with an alternative implementation.
+ * @return {boolean} Widget is visible
+ */
+OO.ui.Widget.prototype.isVisible = function () {
+       return this.visible;
+};
+
+/**
+ * Set the disabled state of the widget.
  *
- * @static
- * @abstract
- * @inheritable
- * @property {string|Function} Title string or function that returns a string
+ * This should probably change the widgets' appearance and prevent it from being used.
+ *
+ * @param {boolean} disabled Disable widget
+ * @chainable
  */
-OO.ui.Window.static.title = null;
+OO.ui.Widget.prototype.setDisabled = function ( disabled ) {
+       var isDisabled;
 
-/* Methods */
+       this.disabled = !!disabled;
+       isDisabled = this.isDisabled();
+       if ( isDisabled !== this.wasDisabled ) {
+               this.$element.toggleClass( 'oo-ui-widget-disabled', isDisabled );
+               this.$element.toggleClass( 'oo-ui-widget-enabled', !isDisabled );
+               this.emit( 'disable', isDisabled );
+       }
+       this.wasDisabled = isDisabled;
+
+       return this;
+};
 
 /**
- * Check if window is visible.
+ * Toggle visibility of widget.
  *
- * @return {boolean} Window is visible
+ * @param {boolean} [show] Make widget visible, omit to toggle visibility
+ * @fires visible
+ * @chainable
  */
-OO.ui.Window.prototype.isVisible = function () {
-       return this.visible;
+OO.ui.Widget.prototype.toggle = function ( show ) {
+       show = show === undefined ? !this.visible : !!show;
+
+       if ( show !== this.isVisible() ) {
+               this.visible = show;
+               this.$element.toggle( show );
+               this.emit( 'toggle', show );
+       }
+
+       return this;
 };
 
 /**
- * Check if window is opening.
+ * Update the disabled state, in case of changes in parent widget.
  *
- * @return {boolean} Window is opening
+ * @chainable
  */
-OO.ui.Window.prototype.isOpening = function () {
-       return !!this.opening && this.opening.state() === 'pending';
+OO.ui.Widget.prototype.updateDisabled = function () {
+       this.setDisabled( this.disabled );
+       return this;
 };
 
 /**
- * Check if window is closing.
+ * Container for elements in a child frame.
  *
- * @return {boolean} Window is closing
+ * Use together with OO.ui.WindowManager.
+ *
+ * @abstract
+ * @class
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
+ *
+ * When a window is opened, the setup and ready processes are executed. Similarly, the hold and
+ * teardown processes are executed when the window is closed.
+ *
+ * - {@link OO.ui.WindowManager#openWindow} or {@link #open} methods are used to start opening
+ * - Window manager begins opening window
+ * - {@link #getSetupProcess} method is called and its result executed
+ * - {@link #getReadyProcess} method is called and its result executed
+ * - Window is now open
+ *
+ * - {@link OO.ui.WindowManager#closeWindow} or {@link #close} methods are used to start closing
+ * - Window manager begins closing window
+ * - {@link #getHoldProcess} method is called and its result executed
+ * - {@link #getTeardownProcess} method is called and its result executed
+ * - Window is now closed
+ *
+ * Each process (setup, ready, hold and teardown) can be extended in subclasses by overriding
+ * {@link #getSetupProcess}, {@link #getReadyProcess}, {@link #getHoldProcess} and
+ * {@link #getTeardownProcess} respectively. Each process is executed in series, so asynchonous
+ * processing can complete. Always assume window processes are executed asychronously. See
+ * OO.ui.Process for more details about how to work with processes. Some events, as well as the
+ * #open and #close methods, provide promises which are resolved when the window enters a new state.
+ *
+ * Sizing of windows is specified using symbolic names which are interpreted by the window manager.
+ * If the requested size is not recognized, the window manager will choose a sensible fallback.
+ *
+ * @constructor
+ * @param {OO.ui.WindowManager} manager Manager of window
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [size] Symbolic name of dialog size, `small`, `medium`, `large` or `full`; omit to
+ *   use #static-size
+ * @fires initialize
  */
-OO.ui.Window.prototype.isClosing = function () {
-       return !!this.closing && this.closing.state() === 'pending';
+OO.ui.Window = function OoUiWindow( manager, config ) {
+       var win = this;
+
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Window.super.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       if ( !( manager instanceof OO.ui.WindowManager ) ) {
+               throw new Error( 'Cannot construct window: window must have a manager' );
+       }
+
+       // Properties
+       this.manager = manager;
+       this.initialized = false;
+       this.visible = false;
+       this.opening = null;
+       this.closing = null;
+       this.opened = null;
+       this.timing = null;
+       this.size = config.size || this.constructor.static.size;
+       this.frame = new OO.ui.Frame( { '$': this.$ } );
+       this.$frame = this.$( '<div>' );
+       this.$ = function () {
+               throw new Error( 'this.$() cannot be used until the frame has been initialized.' );
+       };
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-window' )
+               // Hide the window using visibility: hidden; while the iframe is still loading
+               // Can't use display: none; because that prevents the iframe from loading in Firefox
+               .css( 'visibility', 'hidden' )
+               .append( this.$frame );
+       this.$frame
+               .addClass( 'oo-ui-window-frame' )
+               .append( this.frame.$element );
+
+       // Events
+       this.frame.on( 'load', function () {
+               win.initialize();
+               win.initialized = true;
+               // Undo the visibility: hidden; hack and apply display: none;
+               // We can do this safely now that the iframe has initialized
+               // (don't do this from within #initialize because it has to happen
+               // after the all subclasses have been handled as well).
+               win.$element.hide().css( 'visibility', '' );
+       } );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.Window, OO.ui.Element );
+OO.mixinClass( OO.ui.Window, OO.EventEmitter );
+
+/* Events */
+
 /**
- * Check if window is opened.
+ * @event resize
+ * @param {string} size Symbolic size name, e.g. 'small', 'medium', 'large', 'full'
+ */
+
+/* Static Properties */
+
+/**
+ * Symbolic name of size.
  *
- * @return {boolean} Window is opened
+ * Size is used if no size is configured during construction.
+ *
+ * @static
+ * @inheritable
+ * @property {string}
  */
-OO.ui.Window.prototype.isOpened = function () {
-       return !!this.opened && this.opened.state() === 'pending';
-};
+OO.ui.Window.static.size = 'medium';
+
+/* Methods */
 
 /**
- * Get the window frame.
+ * Check if window has been initialized.
  *
- * @return {OO.ui.Frame} Frame of window
+ * @return {boolean} Window has been initialized
  */
-OO.ui.Window.prototype.getFrame = function () {
-       return this.frame;
+OO.ui.Window.prototype.isInitialized = function () {
+       return this.initialized;
 };
 
 /**
- * Get the title of the window.
+ * Check if window is visible.
  *
- * @return {string} Title text
+ * @return {boolean} Window is visible
  */
-OO.ui.Window.prototype.getTitle = function () {
-       return this.title;
+OO.ui.Window.prototype.isVisible = function () {
+       return this.visible;
 };
 
 /**
- * Get the window icon.
+ * Check if window is opening.
  *
- * @return {string} Symbolic name of icon
+ * This is a wrapper around OO.ui.WindowManager#isOpening.
+ *
+ * @return {boolean} Window is opening
  */
-OO.ui.Window.prototype.getIcon = function () {
-       return this.icon;
+OO.ui.Window.prototype.isOpening = function () {
+       return this.manager.isOpening( this );
 };
 
 /**
- * Set the size of window frame.
+ * Check if window is closing.
  *
- * @param {number} [width=auto] Custom width
- * @param {number} [height=auto] Custom height
- * @chainable
+ * This is a wrapper around OO.ui.WindowManager#isClosing.
+ *
+ * @return {boolean} Window is closing
  */
-OO.ui.Window.prototype.setSize = function ( width, height ) {
-       if ( !this.frame.$content ) {
-               return;
-       }
-
-       this.frame.$element.css( {
-               'width': width === undefined ? 'auto' : width,
-               'height': height === undefined ? 'auto' : height
-       } );
-
-       return this;
+OO.ui.Window.prototype.isClosing = function () {
+       return this.manager.isClosing( this );
 };
 
 /**
- * Set the title of the window.
+ * Check if window is opened.
  *
- * @param {string|Function} title Title text or a function that returns text
- * @chainable
+ * This is a wrapper around OO.ui.WindowManager#isOpened.
+ *
+ * @return {boolean} Window is opened
  */
-OO.ui.Window.prototype.setTitle = function ( title ) {
-       this.title = OO.ui.resolveMsg( title );
-       if ( this.$title ) {
-               this.$title.text( title );
-       }
-       return this;
+OO.ui.Window.prototype.isOpened = function () {
+       return this.manager.isOpened( this );
 };
 
 /**
- * Set the icon of the window.
+ * Get the window manager.
  *
- * @param {string} icon Symbolic name of icon
- * @chainable
+ * @return {OO.ui.WindowManager} Manager of window
  */
-OO.ui.Window.prototype.setIcon = function ( icon ) {
-       if ( this.$icon ) {
-               this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
-       }
-       this.icon = icon;
-       if ( this.$icon ) {
-               this.$icon.addClass( 'oo-ui-icon-' + this.icon );
-       }
-
-       return this;
+OO.ui.Window.prototype.getManager = function () {
+       return this.manager;
 };
 
 /**
- * Set the position of window to fit with contents.
+ * Get the window frame.
  *
- * @param {string} left Left offset
- * @param {string} top Top offset
- * @chainable
+ * @return {OO.ui.Frame} Frame of window
  */
-OO.ui.Window.prototype.setPosition = function ( left, top ) {
-       this.$element.css( { 'left': left, 'top': top } );
-       return this;
+OO.ui.Window.prototype.getFrame = function () {
+       return this.frame;
 };
 
 /**
- * Set the height of window to fit with contents.
+ * Get the window size.
  *
- * @param {number} [min=0] Min height
- * @param {number} [max] Max height (defaults to content's outer height)
- * @chainable
+ * @return {string} Symbolic size name, e.g. 'small', 'medium', 'large', 'full'
  */
-OO.ui.Window.prototype.fitHeightToContents = function ( min, max ) {
-       var height = this.frame.$content.outerHeight();
-
-       this.frame.$element.css(
-               'height', Math.max( min || 0, max === undefined ? height : Math.min( max, height ) )
-       );
-
-       return this;
+OO.ui.Window.prototype.getSize = function () {
+       return this.size;
 };
 
 /**
- * Set the width of window to fit with contents.
+ * Get the height of the dialog contents.
  *
- * @param {number} [min=0] Min height
- * @param {number} [max] Max height (defaults to content's outer width)
- * @chainable
+ * @return {number} Content height
  */
-OO.ui.Window.prototype.fitWidthToContents = function ( min, max ) {
-       var width = this.frame.$content.outerWidth();
-
-       this.frame.$element.css(
-               'width', Math.max( min || 0, max === undefined ? width : Math.min( max, width ) )
+OO.ui.Window.prototype.getContentHeight = function () {
+       return Math.round(
+               // Add buffer for border
+               ( ( this.$frame.outerHeight() - this.$frame.innerHeight() ) * 2 ) +
+               // Height of contents
+               ( this.$head.outerHeight( true ) + this.getBodyHeight() + this.$foot.outerHeight( true ) )
        );
-
-       return this;
 };
 
 /**
- * Initialize window contents.
+ * Get the height of the dialog contents.
  *
- * The first time the window is opened, #initialize is called when it's safe to begin populating
- * its contents. See #setup for a way to make changes each time the window opens.
- *
- * Once this method is called, this.$$ can be used to create elements within the frame.
- *
- * @chainable
+ * @return {number} Height of content
  */
-OO.ui.Window.prototype.initialize = function () {
-       // Properties
-       this.$ = this.frame.$;
-       this.$title = this.$( '<div class="oo-ui-window-title"></div>' )
-               .text( this.title );
-       this.$icon = this.$( '<div class="oo-ui-window-icon"></div>' )
-               .addClass( 'oo-ui-icon-' + this.icon );
-       this.$head = this.$( '<div class="oo-ui-window-head"></div>' );
-       this.$body = this.$( '<div class="oo-ui-window-body"></div>' );
-       this.$foot = this.$( '<div class="oo-ui-window-foot"></div>' );
-       this.$overlay = this.$( '<div class="oo-ui-window-overlay"></div>' );
-
-       // Initialization
-       this.frame.$content.append(
-               this.$head.append( this.$icon, this.$title ),
-               this.$body,
-               this.$foot,
-               this.$overlay
-       );
-
-       return this;
+OO.ui.Window.prototype.getBodyHeight = function () {
+       return this.$body[0].scrollHeight;
 };
 
 /**
@@ -1252,10 +1738,27 @@ OO.ui.Window.prototype.getReadyProcess = function () {
 };
 
 /**
- * Get a process for tearing down a window after use.
+ * Get a process for holding a window from use.
  *
- * Each time the window is closed this process will tear it down and do something with the user's
- * interactions within the window, based on the `data` argument.
+ * Each time the window is closed, this process will hold it from use in a particular context, based
+ * on the `data` argument.
+ *
+ * When you override this method, you can add additional setup steps to the process the parent
+ * method provides using the 'first' and 'next' methods.
+ *
+ * @abstract
+ * @param {Object} [data] Window closing data
+ * @return {OO.ui.Process} Hold process
+ */
+OO.ui.Window.prototype.getHoldProcess = function () {
+       return new OO.ui.Process();
+};
+
+/**
+ * Get a process for tearing down a window after use.
+ *
+ * Each time the window is closed this process will tear it down and do something with the user's
+ * interactions within the window, based on the `data` argument.
  *
  * When you override this method, you can add additional teardown steps to the process the parent
  * method provides using the 'first' and 'next' methods.
@@ -1269,305 +1772,267 @@ OO.ui.Window.prototype.getTeardownProcess = function () {
 };
 
 /**
- * Open window.
+ * Set the window size.
  *
- * Do not override this method. Use #getSetupProcess to do something each time the window closes.
- *
- * @param {Object} [data] Window opening data
- * @fires initialize
- * @fires opening
- * @fires open
- * @fires ready
- * @return {jQuery.Promise} Promise resolved when window is opened; when the promise is resolved the
- *   first argument will be a promise which will be resolved when the window begins closing
+ * @param {string} size Symbolic size name, e.g. 'small', 'medium', 'large', 'full'
+ * @chainable
  */
-OO.ui.Window.prototype.open = function ( data ) {
-       // Return existing promise if already opening or open
-       if ( this.opening ) {
-               return this.opening.promise();
-       }
-
-       // Open the window
-       this.opening = $.Deferred();
-
-       this.$ariaHidden = $( 'body' ).children().not( this.$element.parentsUntil( 'body' ).last() )
-               .attr( 'aria-hidden', '' );
-
-       this.frame.load().done( OO.ui.bind( function () {
-               this.$element.show();
-               this.visible = true;
-               this.getSetupProcess( data ).execute().done( OO.ui.bind( function () {
-                       this.$element.addClass( 'oo-ui-window-setup' );
-                       this.emit( 'setup', data );
-                       setTimeout( OO.ui.bind( function () {
-                               this.frame.$content.focus();
-                               this.getReadyProcess( data ).execute().done( OO.ui.bind( function () {
-                                       this.$element.addClass( 'oo-ui-window-ready' );
-                                       this.emit( 'ready', data );
-                                       this.opened = $.Deferred();
-                                       // Now that we are totally done opening, it's safe to allow closing
-                                       this.closing = null;
-                                       this.opening.resolve( this.opened.promise() );
-                               }, this ) );
-                       }, this ) );
-               }, this ) );
-       }, this ) );
-
-       return this.opening.promise();
+OO.ui.Window.prototype.setSize = function ( size ) {
+       this.size = size;
+       this.manager.updateWindowSize( this );
+       return this;
 };
 
 /**
- * Close window.
+ * Set window dimensions.
  *
- * Do not override this method. Use #getTeardownProcess to do something each time the window closes.
+ * Properties are applied to the frame container.
  *
- * @param {Object} [data] Window closing data
- * @fires closing
- * @fires close
- * @return {jQuery.Promise} Promise resolved when window is closed
+ * @param {Object} dim CSS dimension properties
+ * @param {string|number} [dim.width] Width
+ * @param {string|number} [dim.minWidth] Minimum width
+ * @param {string|number} [dim.maxWidth] Maximum width
+ * @param {string|number} [dim.width] Height, omit to set based on height of contents
+ * @param {string|number} [dim.minWidth] Minimum height
+ * @param {string|number} [dim.maxWidth] Maximum height
+ * @chainable
  */
-OO.ui.Window.prototype.close = function ( data ) {
-       var close;
-
-       // Return existing promise if already closing or closed
-       if ( this.closing ) {
-               return this.closing.promise();
-       }
-
-       // Close after opening is done if opening is in progress
-       if ( this.opening && this.opening.state() === 'pending' ) {
-               close = OO.ui.bind( function () {
-                       return this.close( data );
-               }, this );
-               return this.opening.then( close, close );
-       }
-
-       // Close the window
-       // This.closing needs to exist before we emit the closing event so that handlers can call
-       // window.close() and trigger the safety check above
-       this.closing = $.Deferred();
-       this.frame.$content.find( ':focus' ).blur();
-       this.$element.removeClass( 'oo-ui-window-ready' );
-       this.getTeardownProcess( data ).execute().done( OO.ui.bind( function () {
-               this.$element.removeClass( 'oo-ui-window-setup' );
-               this.emit( 'teardown', data );
-               // To do something different with #opened, resolve/reject #opened in the teardown process
-               if ( this.opened && this.opened.state() === 'pending' ) {
-                       this.opened.resolve();
-               }
-               this.$element.hide();
-               if ( this.$ariaHidden ) {
-                       this.$ariaHidden.removeAttr( 'aria-hidden' );
-                       this.$ariaHidden = undefined;
-               }
-               this.visible = false;
-               this.closing.resolve();
-               // Now that we are totally done closing, it's safe to allow opening
-               this.opening = null;
-       }, this ) );
-
-       return this.closing.promise();
+OO.ui.Window.prototype.setDimensions = function ( dim ) {
+       // Apply width before height so height is not based on wrapping content using the wrong width
+       this.$frame.css( {
+               'width': dim.width || '',
+               'min-width': dim.minWidth || '',
+               'max-width': dim.maxWidth || ''
+       } );
+       this.$frame.css( {
+               'height': ( dim.height !== undefined ? dim.height : this.getContentHeight() ) || '',
+               'min-height': dim.minHeight || '',
+               'max-height': dim.maxHeight || ''
+       } );
+       return this;
 };
 
 /**
- * Set of mutually exclusive windows.
+ * Initialize window contents.
  *
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
+ * The first time the window is opened, #initialize is called when it's safe to begin populating
+ * its contents. See #getSetupProcess for a way to make changes each time the window opens.
  *
- * @constructor
- * @param {OO.Factory} factory Window factory
- * @param {Object} [config] Configuration options
+ * Once this method is called, this.$ can be used to create elements within the frame.
+ *
+ * @chainable
  */
-OO.ui.WindowSet = function OoUiWindowSet( factory, config ) {
-       // Parent constructor
-       OO.ui.WindowSet.super.call( this, config );
-
-       // Mixin constructors
-       OO.EventEmitter.call( this );
-
+OO.ui.Window.prototype.initialize = function () {
        // Properties
-       this.factory = factory;
-
-       /**
-        * List of all windows associated with this window set.
-        *
-        * @property {OO.ui.Window[]}
-        */
-       this.windowList = [];
-
-       /**
-        * Mapping of OO.ui.Window objects created by name from the #factory.
-        *
-        * @property {Object}
-        */
-       this.windows = {};
-       this.currentWindow = null;
+       this.$ = this.frame.$;
+       this.$head = this.$( '<div>' );
+       this.$body = this.$( '<div>' );
+       this.$foot = this.$( '<div>' );
+       this.$overlay = this.$( '<div>' );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-windowSet' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.WindowSet, OO.ui.Element );
-OO.mixinClass( OO.ui.WindowSet, OO.EventEmitter );
-
-/* Events */
+       this.$head.addClass( 'oo-ui-window-head' );
+       this.$body.addClass( 'oo-ui-window-body' );
+       this.$foot.addClass( 'oo-ui-window-foot' );
+       this.$overlay.addClass( 'oo-ui-window-overlay' );
+       this.frame.$content
+               .addClass( 'oo-ui-window-content' )
+               .append( this.$head, this.$body, this.$foot, this.$overlay );
 
-/**
- * @event setup
- * @param {OO.ui.Window} win Window that's been setup
- * @param {Object} config Window opening information
- */
-
-/**
- * @event ready
- * @param {OO.ui.Window} win Window that's ready
- * @param {Object} config Window opening information
- */
-
-/**
- * @event teardown
- * @param {OO.ui.Window} win Window that's been torn down
- * @param {Object} config Window closing information
- */
-
-/* Methods */
+       return this;
+};
 
 /**
- * Handle a window setup event.
+ * Open window.
+ *
+ * This is a wrapper around calling {@link OO.ui.WindowManager#openWindow} on the window manager.
+ * To do something each time the window opens, use #getSetupProcess or #getReadyProcess.
  *
- * @param {OO.ui.Window} win Window that's been setup
- * @param {Object} [config] Window opening information
- * @fires setup
+ * @param {Object} [data] Window opening data
+ * @return {jQuery.Promise} Promise resolved when window is opened; when the promise is resolved the
+ *   first argument will be a promise which will be resolved when the window begins closing
  */
-OO.ui.WindowSet.prototype.onWindowSetup = function ( win, config ) {
-       if ( this.currentWindow && this.currentWindow !== win ) {
-               this.currentWindow.close();
-       }
-       this.currentWindow = win;
-       this.emit( 'setup', win, config );
+OO.ui.Window.prototype.open = function ( data ) {
+       return this.manager.openWindow( this, data );
 };
 
 /**
- * Handle a window ready event.
+ * Close window.
  *
- * @param {OO.ui.Window} win Window that's ready
- * @param {Object} [config] Window opening information
- * @fires ready
+ * This is a wrapper around calling OO.ui.WindowManager#closeWindow on the window manager.
+ * To do something each time the window closes, use #getHoldProcess or #getTeardownProcess.
+ *
+ * @param {Object} [data] Window closing data
+ * @return {jQuery.Promise} Promise resolved when window is closed
  */
-OO.ui.WindowSet.prototype.onWindowReady = function ( win, config ) {
-       this.emit( 'ready', win, config );
+OO.ui.Window.prototype.close = function ( data ) {
+       return this.manager.closeWindow( this, data );
 };
 
 /**
- * Handle a window teardown event.
+ * Load window.
  *
- * @param {OO.ui.Window} win Window that's been torn down
- * @param {Object} [config] Window closing information
- * @fires teardown
+ * This is called by OO.ui.WindowManager durring window adding, and should not be called directly
+ * by other systems.
+ *
+ * @return {jQuery.Promise} Promise resolved when window is loaded
  */
-OO.ui.WindowSet.prototype.onWindowTeardown = function ( win, config ) {
-       this.currentWindow = null;
-       this.emit( 'teardown', win, config );
+OO.ui.Window.prototype.load = function () {
+       return this.frame.load();
 };
 
 /**
- * Get the current window.
+ * Setup window.
  *
- * @return {OO.ui.Window|null} Current window or null if none open
+ * This is called by OO.ui.WindowManager durring window opening, and should not be called directly
+ * by other systems.
+ *
+ * @param {Object} [data] Window opening data
+ * @return {jQuery.Promise} Promise resolved when window is setup
  */
-OO.ui.WindowSet.prototype.getCurrentWindow = function () {
-       return this.currentWindow;
+OO.ui.Window.prototype.setup = function ( data ) {
+       var win = this,
+               deferred = $.Deferred();
+
+       this.$element.show();
+       this.visible = true;
+       this.getSetupProcess( data ).execute().done( function () {
+               win.manager.updateWindowSize( win );
+               // Force redraw by asking the browser to measure the elements' widths
+               win.$element.addClass( 'oo-ui-window-setup' ).width();
+               win.frame.$content.addClass( 'oo-ui-window-content-setup' ).width();
+               deferred.resolve();
+       } );
+
+       return deferred.promise();
 };
 
 /**
- * Return a given window.
+ * Ready window.
+ *
+ * This is called by OO.ui.WindowManager durring window opening, and should not be called directly
+ * by other systems.
  *
- * @param {string} name Symbolic name of window
- * @return {OO.ui.Window} Window with specified name
+ * @param {Object} [data] Window opening data
+ * @return {jQuery.Promise} Promise resolved when window is ready
  */
-OO.ui.WindowSet.prototype.getWindow = function ( name ) {
-       var win;
+OO.ui.Window.prototype.ready = function ( data ) {
+       var win = this,
+               deferred = $.Deferred();
 
-       if ( !this.factory.lookup( name ) ) {
-               throw new Error( 'Unknown window: ' + name );
-       }
-       if ( !( name in this.windows ) ) {
-               win = this.windows[name] = this.createWindow( name );
-               this.addWindow( win );
-       }
-       return this.windows[name];
+       this.frame.$content[0].focus();
+       this.getReadyProcess( data ).execute().done( function () {
+               // Force redraw by asking the browser to measure the elements' widths
+               win.$element.addClass( 'oo-ui-window-ready' ).width();
+               win.frame.$content.addClass( 'oo-ui-window-content-ready' ).width();
+               deferred.resolve();
+       } );
+
+       return deferred.promise();
 };
 
 /**
- * Create a window for use in this window set.
+ * Hold window.
  *
- * @param {string} name Symbolic name of window
- * @return {OO.ui.Window} Window with specified name
+ * This is called by OO.ui.WindowManager durring window closing, and should not be called directly
+ * by other systems.
+ *
+ * @param {Object} [data] Window closing data
+ * @return {jQuery.Promise} Promise resolved when window is held
  */
-OO.ui.WindowSet.prototype.createWindow = function ( name ) {
-       return this.factory.create( name, { '$': this.$ } );
+OO.ui.Window.prototype.hold = function ( data ) {
+       var win = this,
+               deferred = $.Deferred();
+
+       this.getHoldProcess( data ).execute().done( function () {
+               var $focused = win.frame.$content.find( ':focus' );
+               if ( $focused.length ) {
+                       $focused[0].blur();
+               }
+               // Force redraw by asking the browser to measure the elements' widths
+               win.$element.removeClass( 'oo-ui-window-ready' ).width();
+               win.frame.$content.removeClass( 'oo-ui-window-content-ready' ).width();
+               deferred.resolve();
+       } );
+
+       return deferred.promise();
 };
 
 /**
- * Add a given window to this window set.
+ * Teardown window.
  *
- * Connects event handlers and attaches it to the DOM. Calling
- * OO.ui.Window#open will not work until the window is added to the set.
+ * This is called by OO.ui.WindowManager durring window closing, and should not be called directly
+ * by other systems.
  *
- * @param {OO.ui.Window} win Window to add
+ * @param {Object} [data] Window closing data
+ * @return {jQuery.Promise} Promise resolved when window is torn down
  */
-OO.ui.WindowSet.prototype.addWindow = function ( win ) {
-       if ( this.windowList.indexOf( win ) !== -1 ) {
-               // Already set up
-               return;
-       }
-       this.windowList.push( win );
+OO.ui.Window.prototype.teardown = function ( data ) {
+       var win = this,
+               deferred = $.Deferred();
 
-       win.connect( this, {
-               'setup': [ 'onWindowSetup', win ],
-               'ready': [ 'onWindowReady', win ],
-               'teardown': [ 'onWindowTeardown', win ]
+       this.getTeardownProcess( data ).execute().done( function () {
+               // Force redraw by asking the browser to measure the elements' widths
+               win.$element.removeClass( 'oo-ui-window-setup' ).width();
+               win.frame.$content.removeClass( 'oo-ui-window-content-setup' ).width();
+               win.$element.hide();
+               win.visible = false;
+               deferred.resolve();
        } );
-       this.$element.append( win.$element );
+
+       return deferred.promise();
 };
 
 /**
- * Modal dialog window.
+ * Base class for all dialogs.
+ *
+ * Logic:
+ * - Manage the window (open and close, etc.).
+ * - Store the internal name and display title.
+ * - A stack to track one or more pending actions.
+ * - Manage a set of actions that can be performed.
+ * - Configure and create action widgets.
+ *
+ * User interface:
+ * - Close the dialog with Escape key.
+ * - Visually lock the dialog while an action is in
+ *   progress (aka "pending").
+ *
+ * Subclass responsibilities:
+ * - Display the title somewhere.
+ * - Add content to the dialog.
+ * - Provide a UI to close the dialog.
+ * - Display the action widgets somewhere.
  *
  * @abstract
  * @class
  * @extends OO.ui.Window
+ * @mixins OO.ui.LabeledElement
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {boolean} [footless] Hide foot
- * @cfg {string} [size='large'] Symbolic name of dialog size, `small`, `medium` or `large`
  */
-OO.ui.Dialog = function OoUiDialog( config ) {
-       // Configuration initialization
-       config = $.extend( { 'size': 'large' }, config );
-
+OO.ui.Dialog = function OoUiDialog( manager, config ) {
        // Parent constructor
-       OO.ui.Dialog.super.call( this, config );
+       OO.ui.Dialog.super.call( this, manager, config );
 
        // Properties
-       this.visible = false;
-       this.footless = !!config.footless;
-       this.size = null;
+       this.actions = new OO.ui.ActionSet();
+       this.attachedActions = [];
+       this.currentAction = null;
        this.pending = 0;
-       this.onWindowMouseWheelHandler = OO.ui.bind( this.onWindowMouseWheel, this );
-       this.onDocumentKeyDownHandler = OO.ui.bind( this.onDocumentKeyDown, this );
 
        // Events
-       this.$element.on( 'mousedown', false );
+       this.actions.connect( this, {
+               'click': 'onActionClick',
+               'resize': 'onActionResize',
+               'change': 'onActionsChange'
+       } );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-dialog' ).attr( 'role', 'dialog' );
-       this.setSize( config.size );
+       this.$element
+               .addClass( 'oo-ui-dialog' )
+               .attr( 'role', 'dialog' );
 };
 
 /* Setup */
@@ -1587,55 +2052,35 @@ OO.inheritClass( OO.ui.Dialog, OO.ui.Window );
 OO.ui.Dialog.static.name = '';
 
 /**
- * Map of symbolic size names and CSS classes.
+ * Dialog title.
  *
+ * @abstract
  * @static
  * @inheritable
- * @property {Object}
- */
-OO.ui.Dialog.static.sizeCssClasses = {
-       'small': 'oo-ui-dialog-small',
-       'medium': 'oo-ui-dialog-medium',
-       'large': 'oo-ui-dialog-large'
-};
-
-/* Methods */
-
-/**
- * Handle close button click events.
+ * @property {jQuery|string|Function} Label nodes, text or a function that returns nodes or text
  */
-OO.ui.Dialog.prototype.onCloseButtonClick = function () {
-       this.close( { 'action': 'cancel' } );
-};
+OO.ui.Dialog.static.title = '';
 
 /**
- * Handle window mouse wheel events.
+ * List of OO.ui.ActionWidget configuration options.
  *
- * @param {jQuery.Event} e Mouse wheel event
+ * @static
+ * inheritable
+ * @property {Object[]}
  */
-OO.ui.Dialog.prototype.onWindowMouseWheel = function () {
-       return false;
-};
+OO.ui.Dialog.static.actions = [];
 
 /**
- * Handle document key down events.
+ * Close dialog when the escape key is pressed.
  *
- * @param {jQuery.Event} e Key down event
+ * @static
+ * @abstract
+ * @inheritable
+ * @property {boolean}
  */
-OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
-       switch ( e.which ) {
-               case OO.ui.Keys.PAGEUP:
-               case OO.ui.Keys.PAGEDOWN:
-               case OO.ui.Keys.END:
-               case OO.ui.Keys.HOME:
-               case OO.ui.Keys.LEFT:
-               case OO.ui.Keys.UP:
-               case OO.ui.Keys.RIGHT:
-               case OO.ui.Keys.DOWN:
-                       // Prevent any key events that might cause scrolling
-                       return false;
-       }
-};
+OO.ui.Dialog.static.escapable = true;
+
+/* Methods */
 
 /**
  * Handle frame document key down events.
@@ -1644,68 +2089,109 @@ OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
  */
 OO.ui.Dialog.prototype.onFrameDocumentKeyDown = function ( e ) {
        if ( e.which === OO.ui.Keys.ESCAPE ) {
-               this.close( { 'action': 'cancel' } );
+               this.close();
                return false;
        }
 };
 
 /**
- * Set dialog size.
+ * Handle action resized events.
  *
- * @param {string} [size='large'] Symbolic name of dialog size, `small`, `medium` or `large`
+ * @param {OO.ui.ActionWidget} action Action that was resized
  */
-OO.ui.Dialog.prototype.setSize = function ( size ) {
-       var name, state, cssClass,
-               sizeCssClasses = OO.ui.Dialog.static.sizeCssClasses;
+OO.ui.Dialog.prototype.onActionResize = function () {
+       // Override in subclass
+};
 
-       if ( !sizeCssClasses[size] ) {
-               size = 'large';
-       }
-       this.size = size;
-       for ( name in sizeCssClasses ) {
-               state = name === size;
-               cssClass = sizeCssClasses[name];
-               this.$element.toggleClass( cssClass, state );
+/**
+ * Handle action click events.
+ *
+ * @param {OO.ui.ActionWidget} action Action that was clicked
+ */
+OO.ui.Dialog.prototype.onActionClick = function ( action ) {
+       if ( !this.isPending() ) {
+               this.currentAction = action;
+               this.executeAction( action.getAction() );
        }
 };
 
 /**
- * @inheritdoc
+ * Handle actions change event.
  */
-OO.ui.Dialog.prototype.initialize = function () {
-       // Parent method
-       OO.ui.Dialog.super.prototype.initialize.call( this );
+OO.ui.Dialog.prototype.onActionsChange = function () {
+       this.detachActions();
+       if ( !this.isClosing() ) {
+               this.attachActions();
+       }
+};
 
-       // Properties
-       this.closeButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'close',
-               'title': OO.ui.msg( 'ooui-dialog-action-close' )
-       } );
+/**
+ * Check if input is pending.
+ *
+ * @return {boolean}
+ */
+OO.ui.Dialog.prototype.isPending = function () {
+       return !!this.pending;
+};
 
-       // Events
-       this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
-       this.frame.$document.on( 'keydown', OO.ui.bind( this.onFrameDocumentKeyDown, this ) );
+/**
+ * Get set of actions.
+ *
+ * @return {OO.ui.ActionSet}
+ */
+OO.ui.Dialog.prototype.getActions = function () {
+       return this.actions;
+};
 
-       // Initialization
-       this.frame.$content.addClass( 'oo-ui-dialog-content' );
-       if ( this.footless ) {
-               this.frame.$content.addClass( 'oo-ui-dialog-content-footless' );
-       }
-       this.closeButton.$element.addClass( 'oo-ui-window-closeButton' );
-       this.$head.append( this.closeButton.$element );
+/**
+ * Get a process for taking action.
+ *
+ * When you override this method, you can add additional accept steps to the process the parent
+ * method provides using the 'first' and 'next' methods.
+ *
+ * @abstract
+ * @param {string} [action] Symbolic name of action
+ * @return {OO.ui.Process} Action process
+ */
+OO.ui.Dialog.prototype.getActionProcess = function ( action ) {
+       return new OO.ui.Process()
+               .next( function () {
+                       if ( !action ) {
+                               // An empty action always closes the dialog without data, which should always be
+                               // safe and make no changes
+                               this.close();
+                       }
+               }, this );
 };
 
 /**
  * @inheritdoc
+ *
+ * @param {Object} [data] Dialog opening data
+ * @param {jQuery|string|Function|null} [data.label] Dialog label, omit to use #static-label
+ * @param {Object[]} [data.actions] List of OO.ui.ActionWidget configuration options for each
+ *   action item, omit to use #static-actions
  */
 OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
+       data = data || {};
+
+       // Parent method
        return OO.ui.Dialog.super.prototype.getSetupProcess.call( this, data )
                .next( function () {
-                       // Prevent scrolling in top-level window
-                       this.$( window ).on( 'mousewheel', this.onWindowMouseWheelHandler );
-                       this.$( document ).on( 'keydown', this.onDocumentKeyDownHandler );
+                       var i, len,
+                               items = [],
+                               config = this.constructor.static,
+                               actions = data.actions !== undefined ? data.actions : config.actions;
+
+                       this.title.setLabel(
+                               data.title !== undefined ? data.title : this.constructor.static.title
+                       );
+                       for ( i = 0, len = actions.length; i < len; i++ ) {
+                               items.push(
+                                       new OO.ui.ActionWidget( $.extend( { '$': this.$ }, actions[i] ) )
+                               );
+                       }
+                       this.actions.add( items );
                }, this );
 };
 
@@ -1713,37 +2199,77 @@ OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
  * @inheritdoc
  */
 OO.ui.Dialog.prototype.getTeardownProcess = function ( data ) {
+       // Parent method
        return OO.ui.Dialog.super.prototype.getTeardownProcess.call( this, data )
                .first( function () {
-                       // Wait for closing transition
-                       return OO.ui.Process.static.delay( 250 );
-               }, this )
-               .next( function () {
-                       // Allow scrolling in top-level window
-                       this.$( window ).off( 'mousewheel', this.onWindowMouseWheelHandler );
-                       this.$( document ).off( 'keydown', this.onDocumentKeyDownHandler );
+                       this.actions.clear();
+                       this.currentAction = null;
                }, this );
 };
 
 /**
- * Check if input is pending.
- *
- * @return {boolean}
+ * @inheritdoc
  */
-OO.ui.Dialog.prototype.isPending = function () {
-       return !!this.pending;
+OO.ui.Dialog.prototype.initialize = function () {
+       // Parent method
+       OO.ui.Dialog.super.prototype.initialize.call( this );
+
+       // Properties
+       this.title = new OO.ui.LabelWidget( { '$': this.$ } );
+
+       // Events
+       if ( this.constructor.static.escapable ) {
+               this.frame.$document.on( 'keydown', OO.ui.bind( this.onFrameDocumentKeyDown, this ) );
+       }
+
+       // Initialization
+       this.frame.$content.addClass( 'oo-ui-dialog-content' );
 };
 
 /**
- * Increase the pending stack.
+ * Attach action actions.
+ */
+OO.ui.Dialog.prototype.attachActions = function () {
+       // Remember the list of potentially attached actions
+       this.attachedActions = this.actions.get();
+};
+
+/**
+ * Detach action actions.
+ *
+ * @chainable
+ */
+OO.ui.Dialog.prototype.detachActions = function () {
+       var i, len;
+
+       // Detach all actions that may have been previously attached
+       for ( i = 0, len = this.attachedActions.length; i < len; i++ ) {
+               this.attachedActions[i].$element.detach();
+       }
+       this.attachedActions = [];
+};
+
+/**
+ * Execute an action.
+ *
+ * @param {string} action Symbolic name of action to execute
+ * @return {jQuery.Promise} Promise resolved when action completes, rejected if it fails
+ */
+OO.ui.Dialog.prototype.executeAction = function ( action ) {
+       this.pushPending();
+       return this.getActionProcess( action ).execute()
+               .always( OO.ui.bind( this.popPending, this ) );
+};
+
+/**
+ * Increase the pending stack.
  *
  * @chainable
  */
 OO.ui.Dialog.prototype.pushPending = function () {
        if ( this.pending === 0 ) {
-               this.frame.$content.addClass( 'oo-ui-dialog-pending' );
+               this.frame.$content.addClass( 'oo-ui-actionDialog-content-pending' );
                this.$head.addClass( 'oo-ui-texture-pending' );
-               this.$foot.addClass( 'oo-ui-texture-pending' );
        }
        this.pending++;
 
@@ -1759,9 +2285,8 @@ OO.ui.Dialog.prototype.pushPending = function () {
  */
 OO.ui.Dialog.prototype.popPending = function () {
        if ( this.pending === 1 ) {
-               this.frame.$content.removeClass( 'oo-ui-dialog-pending' );
+               this.frame.$content.removeClass( 'oo-ui-actionDialog-content-pending' );
                this.$head.removeClass( 'oo-ui-texture-pending' );
-               this.$foot.removeClass( 'oo-ui-texture-pending' );
        }
        this.pending = Math.max( 0, this.pending - 1 );
 
@@ -1769,1889 +2294,2493 @@ OO.ui.Dialog.prototype.popPending = function () {
 };
 
 /**
- * Container for elements.
+ * Collection of windows.
  *
- * @abstract
  * @class
  * @extends OO.ui.Element
  * @mixins OO.EventEmitter
  *
+ * Managed windows are mutually exclusive. If a window is opened while there is a current window
+ * already opening or opened, the current window will be closed without data. Empty closing data
+ * should always result in the window being closed without causing constructive or destructive
+ * action.
+ *
+ * As a window is opened and closed, it passes through several stages and the manager emits several
+ * corresponding events.
+ *
+ * - {@link #openWindow} or {@link OO.ui.Window#open} methods are used to start opening
+ * - {@link #event-opening} is emitted with `opening` promise
+ * - {@link #getSetupDelay} is called the returned value is used to time a pause in execution
+ * - {@link OO.ui.Window#getSetupProcess} method is called on the window and its result executed
+ * - `setup` progress notification is emitted from opening promise
+ * - {@link #getReadyDelay} is called the returned value is used to time a pause in execution
+ * - {@link OO.ui.Window#getReadyProcess} method is called on the window and its result executed
+ * - `ready` progress notification is emitted from opening promise
+ * - `opening` promise is resolved with `opened` promise
+ * - Window is now open
+ *
+ * - {@link #closeWindow} or {@link OO.ui.Window#close} methods are used to start closing
+ * - `opened` promise is resolved with `closing` promise
+ * - {@link #event-opening} is emitted with `closing` promise
+ * - {@link #getHoldDelay} is called the returned value is used to time a pause in execution
+ * - {@link OO.ui.Window#getHoldProcess} method is called on the window and its result executed
+ * - `hold` progress notification is emitted from opening promise
+ * - {@link #getTeardownDelay} is called the returned value is used to time a pause in execution
+ * - {@link OO.ui.Window#getTeardownProcess} method is called on the window and its result executed
+ * - `teardown` progress notification is emitted from opening promise
+ * - Closing promise is resolved
+ * - Window is now closed
+ *
  * @constructor
  * @param {Object} [config] Configuration options
+ * @cfg {OO.Factory} [factory] Window factory to use for automatic instantiation
+ * @cfg {boolean} [modal=true] Prevent interaction outside the dialog
  */
-OO.ui.Layout = function OoUiLayout( config ) {
-       // Initialize config
+OO.ui.WindowManager = function OoUiWindowManager( config ) {
+       // Configuration initialization
        config = config || {};
 
        // Parent constructor
-       OO.ui.Layout.super.call( this, config );
+       OO.ui.WindowManager.super.call( this, config );
 
        // Mixin constructors
        OO.EventEmitter.call( this );
 
+       // Properties
+       this.factory = config.factory;
+       this.modal = config.modal === undefined || !!config.modal;
+       this.windows = {};
+       this.opening = null;
+       this.opened = null;
+       this.closing = null;
+       this.size = null;
+       this.currentWindow = null;
+       this.$ariaHidden = null;
+       this.requestedSize = null;
+       this.onWindowResizeTimeout = null;
+       this.onWindowResizeHandler = OO.ui.bind( this.onWindowResize, this );
+       this.afterWindowResizeHandler = OO.ui.bind( this.afterWindowResize, this );
+       this.onWindowMouseWheelHandler = OO.ui.bind( this.onWindowMouseWheel, this );
+       this.onDocumentKeyDownHandler = OO.ui.bind( this.onDocumentKeyDown, this );
+
+       // Events
+       this.$element.on( 'mousedown', false );
+
        // Initialization
-       this.$element.addClass( 'oo-ui-layout' );
+       this.$element
+               .addClass( 'oo-ui-windowManager' )
+               .toggleClass( 'oo-ui-windowManager-modal', this.modal );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.Layout, OO.ui.Element );
-OO.mixinClass( OO.ui.Layout, OO.EventEmitter );
+OO.inheritClass( OO.ui.WindowManager, OO.ui.Element );
+OO.mixinClass( OO.ui.WindowManager, OO.EventEmitter );
+
+/* Events */
 
 /**
- * User interface control.
+ * Window is opening.
  *
- * @abstract
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
+ * Fired when the window begins to be opened.
  *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [disabled=false] Disable
+ * @event opening
+ * @param {OO.ui.Window} win Window that's being opened
+ * @param {jQuery.Promise} opening Promise resolved when window is opened; when the promise is
+ *   resolved the first argument will be a promise which will be resolved when the window begins
+ *   closing, the second argument will be the opening data; progress notifications will be fired on
+ *   the promise for `setup` and `ready` when those processes are completed respectively.
+ * @param {Object} data Window opening data
  */
-OO.ui.Widget = function OoUiWidget( config ) {
-       // Initialize config
-       config = $.extend( { 'disabled': false }, config );
-
-       // Parent constructor
-       OO.ui.Widget.super.call( this, config );
 
-       // Mixin constructors
-       OO.EventEmitter.call( this );
+/**
+ * Window is closing.
+ *
+ * Fired when the window begins to be closed.
+ *
+ * @event closing
+ * @param {OO.ui.Window} win Window that's being closed
+ * @param {jQuery.Promise} opening Promise resolved when window is closed; when the promise
+ *   is resolved the first argument will be a the closing data; progress notifications will be fired
+ *   on the promise for `hold` and `teardown` when those processes are completed respectively.
+ * @param {Object} data Window closing data
+ */
 
-       // Properties
-       this.disabled = null;
-       this.wasDisabled = null;
+/* Static Properties */
 
-       // Initialization
-       this.$element.addClass( 'oo-ui-widget' );
-       this.setDisabled( !!config.disabled );
+/**
+ * Map of symbolic size names and CSS properties.
+ *
+ * @static
+ * @inheritable
+ * @property {Object}
+ */
+OO.ui.WindowManager.static.sizes = {
+       'small': {
+               'width': 300
+       },
+       'medium': {
+               'width': 500
+       },
+       'large': {
+               'width': 700
+       },
+       'full': {
+               // These can be non-numeric because they are never used in calculations
+               'width': '100%',
+               'height': '100%'
+       }
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.Widget, OO.ui.Element );
-OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
-
-/* Events */
-
 /**
- * @event disable
- * @param {boolean} disabled Widget is disabled
+ * Symbolic name of default size.
+ *
+ * Default size is used if the window's requested size is not recognized.
+ *
+ * @static
+ * @inheritable
+ * @property {string}
  */
+OO.ui.WindowManager.static.defaultSize = 'medium';
 
 /* Methods */
 
 /**
- * Check if the widget is disabled.
+ * Handle window resize events.
  *
- * @param {boolean} Button is disabled
+ * @param {jQuery.Event} e Window resize event
  */
-OO.ui.Widget.prototype.isDisabled = function () {
-       return this.disabled;
+OO.ui.WindowManager.prototype.onWindowResize = function () {
+       clearTimeout( this.onWindowResizeTimeout );
+       this.onWindowResizeTimeout = setTimeout( this.afterWindowResizeHandler, 200 );
 };
 
 /**
- * Update the disabled state, in case of changes in parent widget.
+ * Handle window resize events.
  *
- * @chainable
+ * @param {jQuery.Event} e Window resize event
  */
-OO.ui.Widget.prototype.updateDisabled = function () {
-       this.setDisabled( this.disabled );
-       return this;
+OO.ui.WindowManager.prototype.afterWindowResize = function () {
+       if ( this.currentWindow ) {
+               this.updateWindowSize( this.currentWindow );
+       }
 };
 
 /**
- * Set the disabled state of the widget.
- *
- * This should probably change the widgets' appearance and prevent it from being used.
+ * Handle window mouse wheel events.
  *
- * @param {boolean} disabled Disable widget
- * @chainable
+ * @param {jQuery.Event} e Mouse wheel event
  */
-OO.ui.Widget.prototype.setDisabled = function ( disabled ) {
-       var isDisabled;
+OO.ui.WindowManager.prototype.onWindowMouseWheel = function () {
+       return false;
+};
 
-       this.disabled = !!disabled;
-       isDisabled = this.isDisabled();
-       if ( isDisabled !== this.wasDisabled ) {
-               this.$element.toggleClass( 'oo-ui-widget-disabled', isDisabled );
-               this.$element.toggleClass( 'oo-ui-widget-enabled', !isDisabled );
-               this.emit( 'disable', isDisabled );
+/**
+ * Handle document key down events.
+ *
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.WindowManager.prototype.onDocumentKeyDown = function ( e ) {
+       switch ( e.which ) {
+               case OO.ui.Keys.PAGEUP:
+               case OO.ui.Keys.PAGEDOWN:
+               case OO.ui.Keys.END:
+               case OO.ui.Keys.HOME:
+               case OO.ui.Keys.LEFT:
+               case OO.ui.Keys.UP:
+               case OO.ui.Keys.RIGHT:
+               case OO.ui.Keys.DOWN:
+                       // Prevent any key events that might cause scrolling
+                       return false;
        }
-       this.wasDisabled = isDisabled;
-       return this;
 };
 
 /**
- * A list of functions, called in sequence.
+ * Check if window is opening.
  *
- * If a function added to a process returns boolean false the process will stop; if it returns an
- * object with a `promise` method the process will use the promise to either continue to the next
- * step when the promise is resolved or stop when the promise is rejected.
+ * @return {boolean} Window is opening
+ */
+OO.ui.WindowManager.prototype.isOpening = function ( win ) {
+       return win === this.currentWindow && !!this.opening && this.opening.state() === 'pending';
+};
+
+/**
+ * Check if window is closing.
  *
- * @class
+ * @return {boolean} Window is closing
+ */
+OO.ui.WindowManager.prototype.isClosing = function ( win ) {
+       return win === this.currentWindow && !!this.closing && this.closing.state() === 'pending';
+};
+
+/**
+ * Check if window is opened.
  *
- * @constructor
+ * @return {boolean} Window is opened
  */
-OO.ui.Process = function () {
-       // Properties
-       this.steps = [];
+OO.ui.WindowManager.prototype.isOpened = function ( win ) {
+       return win === this.currentWindow && !!this.opened && this.opened.state() === 'pending';
 };
 
-/* Setup */
+/**
+ * Check if a window is being managed.
+ *
+ * @param {OO.ui.Window} win Window to check
+ * @return {boolean} Window is being managed
+ */
+OO.ui.WindowManager.prototype.hasWindow = function ( win ) {
+       var name;
 
-OO.initClass( OO.ui.Process );
+       for ( name in this.windows ) {
+               if ( this.windows[name] === win ) {
+                       return true;
+               }
+       }
 
-/* Static Methods */
+       return false;
+};
 
 /**
- * Generate a promise which is resolved after a set amount of time.
+ * Get the number of milliseconds to wait between beginning opening and executing setup process.
  *
- * @param {number} length Number of milliseconds before resolving the promise
- * @return {jQuery.Promise} Promise that will be resolved after a set amount of time
+ * @param {OO.ui.Window} win Window being opened
+ * @param {Object} [data] Window opening data
+ * @return {number} Milliseconds to wait
  */
-OO.ui.Process.static.delay = function ( length ) {
-       var deferred = $.Deferred();
-
-       setTimeout( function () {
-               deferred.resolve();
-       }, length );
+OO.ui.WindowManager.prototype.getSetupDelay = function () {
+       return 0;
+};
 
-       return deferred.promise();
+/**
+ * Get the number of milliseconds to wait between finishing setup and executing ready process.
+ *
+ * @param {OO.ui.Window} win Window being opened
+ * @param {Object} [data] Window opening data
+ * @return {number} Milliseconds to wait
+ */
+OO.ui.WindowManager.prototype.getReadyDelay = function () {
+       return 0;
 };
 
-/* Methods */
+/**
+ * Get the number of milliseconds to wait between beginning closing and executing hold process.
+ *
+ * @param {OO.ui.Window} win Window being closed
+ * @param {Object} [data] Window closing data
+ * @return {number} Milliseconds to wait
+ */
+OO.ui.WindowManager.prototype.getHoldDelay = function () {
+       return 0;
+};
 
 /**
- * Start the process.
+ * Get the number of milliseconds to wait between finishing hold and executing teardown process.
  *
- * @return {jQuery.Promise} Promise that is resolved when all steps have completed or rejected when
- *   any of the steps return boolean false or a promise which gets rejected; upon stopping the
- *   process, the remaining steps will not be taken
+ * @param {OO.ui.Window} win Window being closed
+ * @param {Object} [data] Window closing data
+ * @return {number} Milliseconds to wait
  */
-OO.ui.Process.prototype.execute = function () {
-       var i, len, promise;
+OO.ui.WindowManager.prototype.getTeardownDelay = function () {
+       return this.modal ? 250 : 0;
+};
 
-       /**
-        * Continue execution.
-        *
-        * @ignore
-        * @param {Array} step A function and the context it should be called in
-        * @return {Function} Function that continues the process
-        */
-       function proceed( step ) {
-               return function () {
-                       // Execute step in the correct context
-                       var result = step[0].call( step[1] );
+/**
+ * Get managed window by symbolic name.
+ *
+ * If window is not yet instantiated, it will be instantiated and added automatically.
+ *
+ * @param {string} name Symbolic window name
+ * @return {jQuery.Promise} Promise resolved when window is ready to be accessed; when resolved the
+ *   first argument is an OO.ui.Window; when rejected the first argument is an OO.ui.Error
+ * @throws {Error} If the symbolic name is unrecognized by the factory
+ * @throws {Error} If the symbolic name unrecognized as a managed window
+ */
+OO.ui.WindowManager.prototype.getWindow = function ( name ) {
+       var deferred = $.Deferred(),
+               win = this.windows[name];
 
-                       if ( result === false ) {
-                               // Use rejected promise for boolean false results
-                               return $.Deferred().reject().promise();
-                       }
-                       // Duck-type the object to see if it can produce a promise
-                       if ( result && $.isFunction( result.promise ) ) {
-                               // Use a promise generated from the result
-                               return result.promise();
+       if ( !( win instanceof OO.ui.Window ) ) {
+               if ( this.factory ) {
+                       if ( !this.factory.lookup( name ) ) {
+                               deferred.reject( new OO.ui.Error(
+                                       'Cannot auto-instantiate window: symbolic name is unrecognized by the factory'
+                               ) );
+                       } else {
+                               win = this.factory.create( name, this, { '$': this.$ } );
+                               this.addWindows( [ win ] ).then(
+                                       OO.ui.bind( deferred.resolve, deferred, win ),
+                                       deferred.reject
+                               );
                        }
-                       // Use resolved promise for other results
-                       return $.Deferred().resolve().promise();
-               };
-       }
-
-       if ( this.steps.length ) {
-               // Generate a chain reaction of promises
-               promise = proceed( this.steps[0] )();
-               for ( i = 1, len = this.steps.length; i < len; i++ ) {
-                       promise = promise.then( proceed( this.steps[i] ) );
+               } else {
+                       deferred.reject( new OO.ui.Error(
+                               'Cannot get unmanaged window: symbolic name unrecognized as a managed window'
+                       ) );
                }
        } else {
-               promise = $.Deferred().resolve().promise();
+               deferred.resolve( win );
        }
 
-       return promise;
+       return deferred.promise();
 };
 
 /**
- * Add step to the beginning of the process.
+ * Get current window.
  *
- * @param {Function} step Function to execute; if it returns boolean false the process will stop; if
- *   it returns an object with a `promise` method the process will use the promise to either
- *   continue to the next step when the promise is resolved or stop when the promise is rejected
- * @param {Object} [context=null] Context to call the step function in
- * @chainable
+ * @return {OO.ui.Window|null} Currently opening/opened/closing window
  */
-OO.ui.Process.prototype.first = function ( step, context ) {
-       this.steps.unshift( [ step, context || null ] );
-       return this;
+OO.ui.WindowManager.prototype.getCurrentWindow = function () {
+       return this.currentWindow;
 };
 
 /**
- * Add step to the end of the process.
+ * Open a window.
  *
- * @param {Function} step Function to execute; if it returns boolean false the process will stop; if
- *   it returns an object with a `promise` method the process will use the promise to either
- *   continue to the next step when the promise is resolved or stop when the promise is rejected
- * @param {Object} [context=null] Context to call the step function in
- * @chainable
+ * @param {OO.ui.Window|string} win Window object or symbolic name of window to open
+ * @param {Object} [data] Window opening data
+ * @return {jQuery.Promise} Promise resolved when window is done opening; see {@link #event-opening}
+ *   for more details about the `opening` promise
+ * @fires opening
  */
-OO.ui.Process.prototype.next = function ( step, context ) {
-       this.steps.push( [ step, context || null ] );
-       return this;
+OO.ui.WindowManager.prototype.openWindow = function ( win, data ) {
+       var manager = this,
+               preparing = [],
+               opening = $.Deferred();
+
+       // Argument handling
+       if ( typeof win === 'string' ) {
+               return this.getWindow( win ).then( function ( win ) {
+                       return manager.openWindow( win, data );
+               } );
+       }
+
+       // Error handling
+       if ( !this.hasWindow( win ) ) {
+               opening.reject( new OO.ui.Error(
+                       'Cannot open window: window is not attached to manager'
+               ) );
+       }
+
+       // Window opening
+       if ( opening.state() !== 'rejected' ) {
+               // Begin loading the window if it's not loaded already - may take noticable time and we want
+               // too do this in paralell with any preparatory actions
+               preparing.push( win.load() );
+
+               if ( this.opening || this.opened ) {
+                       // If a window is currently opening or opened, close it first
+                       preparing.push( this.closeWindow( this.currentWindow ) );
+               } else if ( this.closing ) {
+                       // If a window is currently closing, wait for it to complete
+                       preparing.push( this.closing );
+               }
+
+               $.when.apply( $, preparing ).done( function () {
+                       if ( manager.modal ) {
+                               manager.$( manager.getElementDocument() ).on( {
+                                       // Prevent scrolling by keys in top-level window
+                                       'keydown': manager.onDocumentKeyDownHandler
+                               } );
+                               manager.$( manager.getElementWindow() ).on( {
+                                       // Prevent scrolling by wheel in top-level window
+                                       'mousewheel': manager.onWindowMouseWheelHandler,
+                                       // Start listening for top-level window dimension changes
+                                       'orientationchange resize': manager.onWindowResizeHandler
+                               } );
+                               // Hide other content from screen readers
+                               manager.$ariaHidden = $( 'body' )
+                                       .children()
+                                       .not( manager.$element.parentsUntil( 'body' ).last() )
+                                       .attr( 'aria-hidden', '' );
+                       }
+                       manager.currentWindow = win;
+                       manager.opening = opening;
+                       manager.emit( 'opening', win, opening, data );
+                       manager.updateWindowSize( win );
+                       setTimeout( function () {
+                               win.setup( data ).then( function () {
+                                       manager.opening.notify( { 'state': 'setup' } );
+                                       setTimeout( function () {
+                                               win.ready( data ).then( function () {
+                                                       manager.opening.notify( { 'state': 'ready' } );
+                                                       manager.opening = null;
+                                                       manager.opened = $.Deferred();
+                                                       opening.resolve( manager.opened.promise(), data );
+                                               } );
+                                       }, manager.getReadyDelay() );
+                               } );
+                       }, manager.getSetupDelay() );
+               } );
+       }
+
+       return opening;
 };
 
 /**
- * Dialog for showing a confirmation/warning message.
+ * Close a window.
  *
- * @class
- * @extends OO.ui.Dialog
- *
- * @constructor
- * @param {Object} [config] Configuration options
+ * @param {OO.ui.Window|string} win Window object or symbolic name of window to close
+ * @param {Object} [data] Window closing data
+ * @return {jQuery.Promise} Promise resolved when window is done opening; see {@link #event-closing}
+ *   for more details about the `closing` promise
+ * @throws {Error} If no window by that name is being managed
+ * @fires closing
  */
-OO.ui.ConfirmationDialog = function OoUiConfirmationDialog( config ) {
-       // Configuration initialization
-       config = $.extend( { 'size': 'small' }, config );
-
-       // Parent constructor
-       OO.ui.Dialog.call( this, config );
-};
+OO.ui.WindowManager.prototype.closeWindow = function ( win, data ) {
+       var manager = this,
+               preparing = [],
+               closing = $.Deferred(),
+               opened = this.opened;
+
+       // Argument handling
+       if ( typeof win === 'string' ) {
+               win = this.windows[win];
+       } else if ( !this.hasWindow( win ) ) {
+               win = null;
+       }
+
+       // Error handling
+       if ( !win ) {
+               closing.reject( new OO.ui.Error(
+                       'Cannot close window: window is not attached to manager'
+               ) );
+       } else if ( win !== this.currentWindow ) {
+               closing.reject( new OO.ui.Error(
+                       'Cannot close window: window already closed with different data'
+               ) );
+       } else if ( this.closing ) {
+               closing.reject( new OO.ui.Error(
+                       'Cannot close window: window already closing with different data'
+               ) );
+       }
+
+       // Window closing
+       if ( closing.state() !== 'rejected' ) {
+               if ( this.opening ) {
+                       // If the window is currently opening, close it when it's done
+                       preparing.push( this.opening );
+               }
 
-/* Inheritance */
+               // Close the window
+               $.when.apply( $, preparing ).done( function () {
+                       manager.closing = closing;
+                       manager.emit( 'closing', win, closing, data );
+                       manager.opened = null;
+                       opened.resolve( closing.promise(), data );
+                       setTimeout( function () {
+                               win.hold( data ).then( function () {
+                                       closing.notify( { 'state': 'hold' } );
+                                       setTimeout( function () {
+                                               win.teardown( data ).then( function () {
+                                                       closing.notify( { 'state': 'teardown' } );
+                                                       if ( manager.modal ) {
+                                                               manager.$( manager.getElementDocument() ).off( {
+                                                                       // Allow scrolling by keys in top-level window
+                                                                       'keydown': manager.onDocumentKeyDownHandler
+                                                               } );
+                                                               manager.$( manager.getElementWindow() ).off( {
+                                                                       // Allow scrolling by wheel in top-level window
+                                                                       'mousewheel': manager.onWindowMouseWheelHandler,
+                                                                       // Stop listening for top-level window dimension changes
+                                                                       'orientationchange resize': manager.onWindowResizeHandler
+                                                               } );
+                                                       }
+                                                       // Restore screen reader visiblity
+                                                       if ( manager.$ariaHidden ) {
+                                                               manager.$ariaHidden.removeAttr( 'aria-hidden' );
+                                                               manager.$ariaHidden = null;
+                                                       }
+                                                       manager.closing = null;
+                                                       manager.currentWindow = null;
+                                                       closing.resolve( data );
+                                               } );
+                                       }, manager.getTeardownDelay() );
+                               } );
+                       }, manager.getHoldDelay() );
+               } );
+       }
 
-OO.inheritClass( OO.ui.ConfirmationDialog, OO.ui.Dialog );
+       return closing;
+};
 
-/* Static Properties */
+/**
+ * Add windows.
+ *
+ * If the window manager is attached to the DOM then windows will be automatically loaded as they
+ * are added.
+ *
+ * @param {Object.<string,OO.ui.Window>|OO.ui.Window[]} windows Windows to add
+ * @return {jQuery.Promise} Promise resolved when all windows are added
+ * @throws {Error} If one of the windows being added without an explicit symbolic name does not have
+ *   a statically configured symbolic name
+ */
+OO.ui.WindowManager.prototype.addWindows = function ( windows ) {
+       var i, len, win, name, list,
+               promises = [];
 
-OO.ui.ConfirmationDialog.static.name = 'confirm';
+       if ( $.isArray( windows ) ) {
+               // Convert to map of windows by looking up symbolic names from static configuration
+               list = {};
+               for ( i = 0, len = windows.length; i < len; i++ ) {
+                       name = windows[i].constructor.static.name;
+                       if ( typeof name !== 'string' ) {
+                               throw new Error( 'Cannot add window' );
+                       }
+                       list[name] = windows[i];
+               }
+       } else if ( $.isPlainObject( windows ) ) {
+               list = windows;
+       }
 
-OO.ui.ConfirmationDialog.static.icon = 'help';
+       // Add windows
+       for ( name in list ) {
+               win = list[name];
+               this.windows[name] = win;
+               this.$element.append( win.$element );
 
-OO.ui.ConfirmationDialog.static.title = OO.ui.deferMsg( 'ooui-dialog-confirm-title' );
+               if ( this.isElementAttached() ) {
+                       promises.push( win.load() );
+               }
+       }
 
-/* Methods */
+       return $.when.apply( $, promises );
+};
 
 /**
- * @inheritdoc
+ * Remove windows.
+ *
+ * Windows will be closed before they are removed.
+ *
+ * @param {string} name Symbolic name of window to remove
+ * @return {jQuery.Promise} Promise resolved when window is closed and removed
+ * @throws {Error} If windows being removed are not being managed
  */
-OO.ui.ConfirmationDialog.prototype.initialize = function () {
-       // Parent method
-       OO.ui.Dialog.prototype.initialize.call( this );
-
-       // Set up the layout
-       var contentLayout = new OO.ui.PanelLayout( {
-               '$': this.$,
-               'padded': true
-       } );
-
-       this.$promptContainer = this.$( '<div>' ).addClass( 'oo-ui-dialog-confirm-promptContainer' );
-
-       this.cancelButton = new OO.ui.ButtonWidget();
-       this.cancelButton.connect( this, { 'click': [ 'close', 'cancel' ] } );
-
-       this.okButton = new OO.ui.ButtonWidget();
-       this.okButton.connect( this, { 'click': [ 'close', 'ok' ] } );
+OO.ui.WindowManager.prototype.removeWindows = function ( names ) {
+       var i, len, win, name,
+               manager = this,
+               promises = [],
+               cleanup = function ( name, win ) {
+                       delete manager.windows[name];
+                       win.$element.detach();
+               };
 
-       // Make the buttons
-       contentLayout.$element.append( this.$promptContainer );
-       this.$body.append( contentLayout.$element );
+       for ( i = 0, len = names.length; i < len; i++ ) {
+               name = names[i];
+               win = this.windows[name];
+               if ( !win ) {
+                       throw new Error( 'Cannot remove window' );
+               }
+               promises.push( this.closeWindow( name ).then( OO.ui.bind( cleanup, null, name, win ) ) );
+       }
 
-       this.$foot.append(
-               this.okButton.$element,
-               this.cancelButton.$element
-       );
+       return $.when.apply( $, promises );
 };
 
-/*
- * Setup a confirmation dialog.
+/**
+ * Remove all windows.
  *
- * @param {Object} [data] Window opening data including text of the dialog and text for the buttons
- * @param {jQuery|string} [data.prompt] Text to display or list of nodes to use as content of the dialog.
- * @param {jQuery|string|Function|null} [data.okLabel] Label of the OK button
- * @param {jQuery|string|Function|null} [data.cancelLabel] Label of the cancel button
- * @param {string|string[]} [data.okFlags="constructive"] Flags for the OK button
- * @param {string|string[]} [data.cancelFlags="destructive"] Flags for the cancel button
- * @return {OO.ui.Process} Setup process
+ * Windows will be closed before they are removed.
+ *
+ * @return {jQuery.Promise} Promise resolved when all windows are closed and removed
  */
-OO.ui.ConfirmationDialog.prototype.getSetupProcess = function ( data ) {
-       // Parent method
-       return OO.ui.ConfirmationDialog.super.prototype.getSetupProcess.call( this, data )
-               .next( function () {
-                       var prompt = data.prompt || OO.ui.deferMsg( 'ooui-dialog-confirm-default-prompt' ),
-                               okLabel = data.okLabel || OO.ui.deferMsg( 'ooui-dialog-confirm-default-ok' ),
-                               cancelLabel = data.cancelLabel || OO.ui.deferMsg( 'ooui-dialog-confirm-default-cancel' ),
-                               okFlags = data.okFlags || 'constructive',
-                               cancelFlags = data.cancelFlags || 'destructive';
-
-                       if ( typeof prompt === 'string' ) {
-                               this.$promptContainer.text( prompt );
-                       } else {
-                               this.$promptContainer.empty().append( prompt );
-                       }
-
-                       this.okButton.setLabel( okLabel ).clearFlags().setFlags( okFlags );
-                       this.cancelButton.setLabel( cancelLabel ).clearFlags().setFlags( cancelFlags );
-               }, this );
+OO.ui.WindowManager.prototype.clearWindows = function () {
+       return this.removeWindows( Object.keys( this.windows ) );
 };
 
 /**
- * @inheritdoc
+ * Set dialog size.
+ *
+ * Fullscreen mode will be used if the dialog is too wide to fit in the screen.
+ *
+ * @chainable
  */
-OO.ui.ConfirmationDialog.prototype.getTeardownProcess = function ( data ) {
-       // Parent method
-       return OO.ui.ConfirmationDialog.super.prototype.getTeardownProcess.call( this, data )
-               .first( function () {
-                       if ( data === 'ok' ) {
-                               this.opened.resolve();
-                       } else { // data === 'cancel', or no data
-                               this.opened.reject();
-                       }
-               }, this );
+OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
+       // Bypass for non-current, and thus invisible, windows
+       if ( win !== this.currentWindow ) {
+               return;
+       }
+
+       var viewport = OO.ui.Element.getDimensions( win.getElementWindow() ),
+               sizes = this.constructor.static.sizes,
+               size = win.getSize();
+
+       if ( !sizes[size] ) {
+               size = this.constructor.static.defaultSize;
+       }
+       if ( size !== 'full' && viewport.rect.right - viewport.rect.left < sizes[size].width ) {
+               size = 'full';
+       }
+
+       this.$element.toggleClass( 'oo-ui-windowManager-fullscreen', size === 'full' );
+       this.$element.toggleClass( 'oo-ui-windowManager-floating', size !== 'full' );
+       win.setDimensions( sizes[size] );
+
+       return this;
 };
 
 /**
- * Element with a button.
- *
  * @abstract
  * @class
  *
  * @constructor
- * @param {jQuery} $button Button node, assigned to #$button
+ * @param {string|jQuery} message Description of error
  * @param {Object} [config] Configuration options
- * @cfg {boolean} [frameless] Render button without a frame
- * @cfg {number} [tabIndex=0] Button's tab index, use -1 to prevent tab focusing
+ * @cfg {boolean} [recoverable=true] Error is recoverable
  */
-OO.ui.ButtonedElement = function OoUiButtonedElement( $button, config ) {
+OO.ui.Error = function OoUiElement( message, config ) {
        // Configuration initialization
        config = config || {};
 
        // Properties
-       this.$button = $button;
-       this.tabIndex = null;
-       this.active = false;
-       this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
-
-       // Events
-       this.$button.on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-buttonedElement' );
-       this.$button
-               .addClass( 'oo-ui-buttonedElement-button' )
-               .attr( 'role', 'button' )
-               .prop( 'tabIndex', config.tabIndex || 0 );
-       if ( config.frameless ) {
-               this.$element.addClass( 'oo-ui-buttonedElement-frameless' );
-       } else {
-               this.$element.addClass( 'oo-ui-buttonedElement-framed' );
-       }
+       this.message = message instanceof jQuery ? message : String( message );
+       this.recoverable = config.recoverable === undefined || !!config.recoverable;
 };
 
 /* Setup */
 
-OO.initClass( OO.ui.ButtonedElement );
-
-/* Static Properties */
-
-/**
- * Cancel mouse down events.
- *
- * @static
- * @inheritable
- * @property {boolean}
- */
-OO.ui.ButtonedElement.static.cancelButtonMouseDownEvents = true;
+OO.initClass( OO.ui.Error );
 
 /* Methods */
 
 /**
- * Handles mouse down events.
+ * Check if error can be recovered from.
  *
- * @param {jQuery.Event} e Mouse down event
+ * @return {boolean} Error is recoverable
  */
-OO.ui.ButtonedElement.prototype.onMouseDown = function ( e ) {
-       if ( this.isDisabled() || e.which !== 1 ) {
-               return false;
-       }
-       // tabIndex should generally be interacted with via the property, but it's not possible to
-       // reliably unset a tabIndex via a property so we use the (lowercase) "tabindex" attribute
-       this.tabIndex = this.$button.attr( 'tabindex' );
-       this.$button
-               // Remove the tab-index while the button is down to prevent the button from stealing focus
-               .removeAttr( 'tabindex' )
-               .addClass( 'oo-ui-buttonedElement-pressed' );
-       // Run the mouseup handler no matter where the mouse is when the button is let go, so we can
-       // reliably reapply the tabindex and remove the pressed class
-       this.getElementDocument().addEventListener( 'mouseup', this.onMouseUpHandler, true );
-       // Prevent change of focus unless specifically configured otherwise
-       if ( this.constructor.static.cancelButtonMouseDownEvents ) {
-               return false;
-       }
+OO.ui.Error.prototype.isRecoverable = function () {
+       return this.recoverable;
 };
 
 /**
- * Handles mouse up events.
+ * Get error message as DOM nodes.
  *
- * @param {jQuery.Event} e Mouse up event
+ * @return {jQuery} Error message in DOM nodes
  */
-OO.ui.ButtonedElement.prototype.onMouseUp = function ( e ) {
-       if ( this.isDisabled() || e.which !== 1 ) {
-               return false;
-       }
-       this.$button
-               // Restore the tab-index after the button is up to restore the button's accesssibility
-               .attr( 'tabindex', this.tabIndex )
-               .removeClass( 'oo-ui-buttonedElement-pressed' );
-       // Stop listening for mouseup, since we only needed this once
-       this.getElementDocument().removeEventListener( 'mouseup', this.onMouseUpHandler, true );
+OO.ui.Error.prototype.getMessage = function () {
+       return this.message instanceof jQuery ?
+               this.message.clone() :
+               $( '<div>' ).text( this.message ).contents();
 };
 
 /**
- * Set active state.
+ * Get error message as text.
  *
- * @param {boolean} [value] Make button active
- * @chainable
+ * @return {string} Error message
  */
-OO.ui.ButtonedElement.prototype.setActive = function ( value ) {
-       this.$button.toggleClass( 'oo-ui-buttonedElement-active', !!value );
-       return this;
+OO.ui.Error.prototype.getMessageText = function () {
+       return this.message instanceof jQuery ? this.message.text() : this.message;
 };
 
 /**
- * Element that can be automatically clipped to visible boundaies.
+ * A list of functions, called in sequence.
+ *
+ * If a function added to a process returns boolean false the process will stop; if it returns an
+ * object with a `promise` method the process will use the promise to either continue to the next
+ * step when the promise is resolved or stop when the promise is rejected.
  *
- * @abstract
  * @class
  *
  * @constructor
- * @param {jQuery} $clippable Nodes to clip, assigned to #$clippable
- * @param {Object} [config] Configuration options
+ * @param {number|jQuery.Promise|Function} step Time to wait, promise to wait for or function to
+ *   call, see #createStep for more information
+ * @param {Object} [context=null] Context to call the step function in, ignored if step is a number
+ *   or a promise
+ * @return {Object} Step object, with `callback` and `context` properties
  */
-OO.ui.ClippableElement = function OoUiClippableElement( $clippable, config ) {
-       // Configuration initialization
-       config = config || {};
-
+OO.ui.Process = function ( step, context ) {
        // Properties
-       this.$clippable = $clippable;
-       this.clipping = false;
-       this.clipped = false;
-       this.$clippableContainer = null;
-       this.$clippableScroller = null;
-       this.$clippableWindow = null;
-       this.idealWidth = null;
-       this.idealHeight = null;
-       this.onClippableContainerScrollHandler = OO.ui.bind( this.clip, this );
-       this.onClippableWindowResizeHandler = OO.ui.bind( this.clip, this );
+       this.steps = [];
 
        // Initialization
-       this.$clippable.addClass( 'oo-ui-clippableElement-clippable' );
+       if ( step !== undefined ) {
+               this.next( step, context );
+       }
 };
 
+/* Setup */
+
+OO.initClass( OO.ui.Process );
+
 /* Methods */
 
 /**
- * Set clipping.
+ * Start the process.
  *
- * @param {boolean} value Enable clipping
- * @chainable
+ * @return {jQuery.Promise} Promise that is resolved when all steps have completed or rejected when
+ *   any of the steps return boolean false or a promise which gets rejected; upon stopping the
+ *   process, the remaining steps will not be taken
  */
-OO.ui.ClippableElement.prototype.setClipping = function ( value ) {
-       value = !!value;
+OO.ui.Process.prototype.execute = function () {
+       var i, len, promise;
 
-       if ( this.clipping !== value ) {
-               this.clipping = value;
-               if ( this.clipping ) {
-                       this.$clippableContainer = this.$( this.getClosestScrollableElementContainer() );
-                       // If the clippable container is the body, we have to listen to scroll events and check
-                       // jQuery.scrollTop on the window because of browser inconsistencies
-                       this.$clippableScroller = this.$clippableContainer.is( 'body' ) ?
-                               this.$( OO.ui.Element.getWindow( this.$clippableContainer ) ) :
-                               this.$clippableContainer;
-                       this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
-                       this.$clippableWindow = this.$( this.getElementWindow() )
-                               .on( 'resize', this.onClippableWindowResizeHandler );
-                       // Initial clip after visible
-                       setTimeout( OO.ui.bind( this.clip, this ) );
-               } else {
-                       this.$clippableContainer = null;
-                       this.$clippableScroller.off( 'scroll', this.onClippableContainerScrollHandler );
-                       this.$clippableScroller = null;
-                       this.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );
-                       this.$clippableWindow = null;
+       /**
+        * Continue execution.
+        *
+        * @ignore
+        * @param {Array} step A function and the context it should be called in
+        * @return {Function} Function that continues the process
+        */
+       function proceed( step ) {
+               return function () {
+                       // Execute step in the correct context
+                       var deferred,
+                               result = step.callback.call( step.context );
+
+                       if ( result === false ) {
+                               // Use rejected promise for boolean false results
+                               return $.Deferred().reject( [] ).promise();
+                       }
+                       if ( typeof result === 'number' ) {
+                               if ( result < 0 ) {
+                                       throw new Error( 'Cannot go back in time: flux capacitor is out of service' );
+                               }
+                               // Use a delayed promise for numbers, expecting them to be in milliseconds
+                               deferred = $.Deferred();
+                               setTimeout( deferred.resolve, result );
+                               return deferred.promise();
+                       }
+                       if ( result instanceof OO.ui.Error ) {
+                               // Use rejected promise for error
+                               return $.Deferred().reject( [ result ] ).promise();
+                       }
+                       if ( $.isArray( result ) && result.length && result[0] instanceof OO.ui.Error ) {
+                               // Use rejected promise for list of errors
+                               return $.Deferred().reject( result ).promise();
+                       }
+                       // Duck-type the object to see if it can produce a promise
+                       if ( result && $.isFunction( result.promise ) ) {
+                               // Use a promise generated from the result
+                               return result.promise();
+                       }
+                       // Use resolved promise for other results
+                       return $.Deferred().resolve().promise();
+               };
+       }
+
+       if ( this.steps.length ) {
+               // Generate a chain reaction of promises
+               promise = proceed( this.steps[0] )();
+               for ( i = 1, len = this.steps.length; i < len; i++ ) {
+                       promise = promise.then( proceed( this.steps[i] ) );
                }
+       } else {
+               promise = $.Deferred().resolve().promise();
        }
 
-       return this;
+       return promise;
 };
 
 /**
- * Check if the element will be clipped to fit the visible area of the nearest scrollable container.
+ * Create a process step.
  *
- * @return {boolean} Element will be clipped to the visible area
- */
-OO.ui.ClippableElement.prototype.isClipping = function () {
-       return this.clipping;
+ * @private
+ * @param {number|jQuery.Promise|Function} step
+ *
+ * - Number of milliseconds to wait; or
+ * - Promise to wait to be resolved; or
+ * - Function to execute
+ *   - If it returns boolean false the process will stop
+ *   - If it returns an object with a `promise` method the process will use the promise to either
+ *     continue to the next step when the promise is resolved or stop when the promise is rejected
+ *   - If it returns a number, the process will wait for that number of milliseconds before
+ *     proceeding
+ * @param {Object} [context=null] Context to call the step function in, ignored if step is a number
+ *   or a promise
+ * @return {Object} Step object, with `callback` and `context` properties
+ */
+OO.ui.Process.prototype.createStep = function ( step, context ) {
+       if ( typeof step === 'number' || $.isFunction( step.promise ) ) {
+               return {
+                       'callback': function () {
+                               return step;
+                       },
+                       'context': null
+               };
+       }
+       if ( $.isFunction( step ) ) {
+               return {
+                       'callback': step,
+                       'context': context
+               };
+       }
+       throw new Error( 'Cannot create process step: number, promise or function expected' );
 };
 
 /**
- * Check if the bottom or right of the element is being clipped by the nearest scrollable container.
+ * Add step to the beginning of the process.
  *
- * @return {boolean} Part of the element is being clipped
+ * @inheritdoc #createStep
+ * @return {OO.ui.Process} this
+ * @chainable
  */
-OO.ui.ClippableElement.prototype.isClipped = function () {
-       return this.clipped;
-};
-
-/**
- * Set the ideal size.
- *
- * @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix
- * @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix
- */
-OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
-       this.idealWidth = width;
-       this.idealHeight = height;
+OO.ui.Process.prototype.first = function ( step, context ) {
+       this.steps.unshift( this.createStep( step, context ) );
+       return this;
 };
 
 /**
- * Clip element to visible boundaries and allow scrolling when needed.
- *
- * Element will be clipped the bottom or right of the element is within 10px of the edge of, or
- * overlapped by, the visible area of the nearest scrollable container.
+ * Add step to the end of the process.
  *
+ * @inheritdoc #createStep
+ * @return {OO.ui.Process} this
  * @chainable
  */
-OO.ui.ClippableElement.prototype.clip = function () {
-       if ( !this.clipping ) {
-               // this.$clippableContainer and this.$clippableWindow are null, so the below will fail
-               return this;
-       }
-
-       var buffer = 10,
-               cOffset = this.$clippable.offset(),
-               ccOffset = this.$clippableContainer.offset() || { 'top': 0, 'left': 0 },
-               ccHeight = this.$clippableContainer.innerHeight() - buffer,
-               ccWidth = this.$clippableContainer.innerWidth() - buffer,
-               scrollTop = this.$clippableScroller.scrollTop(),
-               scrollLeft = this.$clippableScroller.scrollLeft(),
-               desiredWidth = ( ccOffset.left + scrollLeft + ccWidth ) - cOffset.left,
-               desiredHeight = ( ccOffset.top + scrollTop + ccHeight ) - cOffset.top,
-               naturalWidth = this.$clippable.prop( 'scrollWidth' ),
-               naturalHeight = this.$clippable.prop( 'scrollHeight' ),
-               clipWidth = desiredWidth < naturalWidth,
-               clipHeight = desiredHeight < naturalHeight;
-
-       if ( clipWidth ) {
-               this.$clippable.css( { 'overflow-x': 'auto', 'width': desiredWidth } );
-       } else {
-               this.$clippable.css( 'width', this.idealWidth || '' );
-               this.$clippable.width(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
-               this.$clippable.css( 'overflow-x', '' );
-       }
-       if ( clipHeight ) {
-               this.$clippable.css( { 'overflow-y': 'auto', 'height': desiredHeight } );
-       } else {
-               this.$clippable.css( 'height', this.idealHeight || '' );
-               this.$clippable.height(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
-               this.$clippable.css( 'overflow-y', '' );
-       }
-
-       this.clipped = clipWidth || clipHeight;
-
+OO.ui.Process.prototype.next = function ( step, context ) {
+       this.steps.push( this.createStep( step, context ) );
        return this;
 };
 
 /**
- * Element with named flags that can be added, removed, listed and checked.
- *
- * A flag, when set, adds a CSS class on the `$element` by combing `oo-ui-flaggableElement-` with
- * the flag name. Flags are primarily useful for styling.
+ * Factory for tools.
  *
- * @abstract
  * @class
- *
+ * @extends OO.Factory
  * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string[]} [flags=[]] Styling flags, e.g. 'primary', 'destructive' or 'constructive'
  */
-OO.ui.FlaggableElement = function OoUiFlaggableElement( config ) {
-       // Config initialization
-       config = config || {};
+OO.ui.ToolFactory = function OoUiToolFactory() {
+       // Parent constructor
+       OO.ui.ToolFactory.super.call( this );
+};
 
-       // Properties
-       this.flags = {};
+/* Setup */
 
-       // Initialization
-       this.setFlags( config.flags );
-};
+OO.inheritClass( OO.ui.ToolFactory, OO.Factory );
 
 /* Methods */
 
-/**
- * Check if a flag is set.
- *
- * @param {string} flag Name of flag
- * @return {boolean} Has flag
- */
-OO.ui.FlaggableElement.prototype.hasFlag = function ( flag ) {
-       return flag in this.flags;
-};
+/** */
+OO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {
+       var i, len, included, promoted, demoted,
+               auto = [],
+               used = {};
 
-/**
- * Get the names of all flags set.
- *
- * @return {string[]} flags Flag names
- */
-OO.ui.FlaggableElement.prototype.getFlags = function () {
-       return Object.keys( this.flags );
-};
+       // Collect included and not excluded tools
+       included = OO.simpleArrayDifference( this.extract( include ), this.extract( exclude ) );
 
-/**
- * Clear all flags.
- *
- * @chainable
- */
-OO.ui.FlaggableElement.prototype.clearFlags = function () {
-       var flag,
-               classPrefix = 'oo-ui-flaggableElement-';
+       // Promotion
+       promoted = this.extract( promote, used );
+       demoted = this.extract( demote, used );
 
-       for ( flag in this.flags ) {
-               delete this.flags[flag];
-               this.$element.removeClass( classPrefix + flag );
+       // Auto
+       for ( i = 0, len = included.length; i < len; i++ ) {
+               if ( !used[included[i]] ) {
+                       auto.push( included[i] );
+               }
        }
 
-       return this;
+       return promoted.concat( auto ).concat( demoted );
 };
 
 /**
- * Add one or more flags.
+ * Get a flat list of names from a list of names or groups.
  *
- * @param {string|string[]|Object.<string, boolean>} flags One or more flags to add, or an object
- *  keyed by flag name containing boolean set/remove instructions.
- * @chainable
+ * Tools can be specified in the following ways:
+ *
+ * - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
+ * - All tools in a group: `{ 'group': 'group-name' }`
+ * - All tools: `'*'`
+ *
+ * @private
+ * @param {Array|string} collection List of tools
+ * @param {Object} [used] Object with names that should be skipped as properties; extracted
+ *  names will be added as properties
+ * @return {string[]} List of extracted names
  */
-OO.ui.FlaggableElement.prototype.setFlags = function ( flags ) {
-       var i, len, flag,
-               classPrefix = 'oo-ui-flaggableElement-';
+OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
+       var i, len, item, name, tool,
+               names = [];
 
-       if ( typeof flags === 'string' ) {
-               // Set
-               this.flags[flags] = true;
-               this.$element.addClass( classPrefix + flags );
-       } else if ( $.isArray( flags ) ) {
-               for ( i = 0, len = flags.length; i < len; i++ ) {
-                       flag = flags[i];
-                       // Set
-                       this.flags[flag] = true;
-                       this.$element.addClass( classPrefix + flag );
+       if ( collection === '*' ) {
+               for ( name in this.registry ) {
+                       tool = this.registry[name];
+                       if (
+                               // Only add tools by group name when auto-add is enabled
+                               tool.static.autoAddToCatchall &&
+                               // Exclude already used tools
+                               ( !used || !used[name] )
+                       ) {
+                               names.push( name );
+                               if ( used ) {
+                                       used[name] = true;
+                               }
+                       }
                }
-       } else if ( OO.isPlainObject( flags ) ) {
-               for ( flag in flags ) {
-                       if ( flags[flag] ) {
-                               // Set
-                               this.flags[flag] = true;
-                               this.$element.addClass( classPrefix + flag );
-                       } else {
-                               // Remove
-                               delete this.flags[flag];
-                               this.$element.removeClass( classPrefix + flag );
+       } else if ( $.isArray( collection ) ) {
+               for ( i = 0, len = collection.length; i < len; i++ ) {
+                       item = collection[i];
+                       // Allow plain strings as shorthand for named tools
+                       if ( typeof item === 'string' ) {
+                               item = { 'name': item };
+                       }
+                       if ( OO.isPlainObject( item ) ) {
+                               if ( item.group ) {
+                                       for ( name in this.registry ) {
+                                               tool = this.registry[name];
+                                               if (
+                                                       // Include tools with matching group
+                                                       tool.static.group === item.group &&
+                                                       // Only add tools by group name when auto-add is enabled
+                                                       tool.static.autoAddToGroup &&
+                                                       // Exclude already used tools
+                                                       ( !used || !used[name] )
+                                               ) {
+                                                       names.push( name );
+                                                       if ( used ) {
+                                                               used[name] = true;
+                                                       }
+                                               }
+                                       }
+                               // Include tools with matching name and exclude already used tools
+                               } else if ( item.name && ( !used || !used[item.name] ) ) {
+                                       names.push( item.name );
+                                       if ( used ) {
+                                               used[item.name] = true;
+                                       }
+                               }
                        }
                }
        }
-       return this;
+       return names;
 };
 
 /**
- * Element containing a sequence of child elements.
+ * Factory for tool groups.
  *
- * @abstract
  * @class
- *
+ * @extends OO.Factory
  * @constructor
- * @param {jQuery} $group Container node, assigned to #$group
- * @param {Object} [config] Configuration options
  */
-OO.ui.GroupElement = function OoUiGroupElement( $group, config ) {
-       // Configuration
-       config = config || {};
+OO.ui.ToolGroupFactory = function OoUiToolGroupFactory() {
+       // Parent constructor
+       OO.Factory.call( this );
 
-       // Properties
-       this.$group = $group;
-       this.items = [];
-       this.aggregateItemEvents = {};
+       var i, l,
+               defaultClasses = this.constructor.static.getDefaultClasses();
+
+       // Register default toolgroups
+       for ( i = 0, l = defaultClasses.length; i < l; i++ ) {
+               this.register( defaultClasses[i] );
+       }
 };
 
-/* Methods */
+/* Setup */
+
+OO.inheritClass( OO.ui.ToolGroupFactory, OO.Factory );
+
+/* Static Methods */
 
 /**
- * Get items.
+ * Get a default set of classes to be registered on construction
  *
- * @return {OO.ui.Element[]} Items
+ * @return {Function[]} Default classes
  */
-OO.ui.GroupElement.prototype.getItems = function () {
-       return this.items.slice( 0 );
+OO.ui.ToolGroupFactory.static.getDefaultClasses = function () {
+       return [
+               OO.ui.BarToolGroup,
+               OO.ui.ListToolGroup,
+               OO.ui.MenuToolGroup
+       ];
 };
 
 /**
- * Add an aggregate item event.
+ * Element with a button.
  *
- * Aggregated events are listened to on each item and then emitted by the group under a new name,
- * and with an additional leading parameter containing the item that emitted the original event.
- * Other arguments that were emitted from the original event are passed through.
+ * Buttons are used for controls which can be clicked. They can be configured to use tab indexing
+ * and access keys for accessibility purposes.
  *
- * @param {Object.<string,string|null>} events Aggregate events emitted by group, keyed by item
- *   event, use null value to remove aggregation
- * @throws {Error} If aggregation already exists
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {jQuery} $button Button node, assigned to #$button
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [framed=true] Render button with a frame
+ * @cfg {number} [tabIndex=0] Button's tab index, use null to have no tabIndex
+ * @cfg {string} [accessKey] Button's access key
  */
-OO.ui.GroupElement.prototype.aggregate = function ( events ) {
-       var i, len, item, add, remove, itemEvent, groupEvent;
+OO.ui.ButtonedElement = function OoUiButtonedElement( $button, config ) {
+       // Configuration initialization
+       config = config || {};
 
-       for ( itemEvent in events ) {
-               groupEvent = events[itemEvent];
+       // Properties
+       this.$button = $button;
+       this.tabIndex = null;
+       this.framed = null;
+       this.active = false;
+       this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
 
-               // Remove existing aggregated event
-               if ( itemEvent in this.aggregateItemEvents ) {
-                       // Don't allow duplicate aggregations
-                       if ( groupEvent ) {
-                               throw new Error( 'Duplicate item event aggregation for ' + itemEvent );
-                       }
-                       // Remove event aggregation from existing items
-                       for ( i = 0, len = this.items.length; i < len; i++ ) {
-                               item = this.items[i];
-                               if ( item.connect && item.disconnect ) {
-                                       remove = {};
-                                       remove[itemEvent] = [ 'emit', groupEvent, item ];
-                                       item.disconnect( this, remove );
-                               }
-                       }
-                       // Prevent future items from aggregating event
-                       delete this.aggregateItemEvents[itemEvent];
-               }
+       // Events
+       this.$button.on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
 
-               // Add new aggregate event
-               if ( groupEvent ) {
-                       // Make future items aggregate event
-                       this.aggregateItemEvents[itemEvent] = groupEvent;
-                       // Add event aggregation to existing items
-                       for ( i = 0, len = this.items.length; i < len; i++ ) {
-                               item = this.items[i];
-                               if ( item.connect && item.disconnect ) {
-                                       add = {};
-                                       add[itemEvent] = [ 'emit', groupEvent, item ];
-                                       item.connect( this, add );
-                               }
-                       }
-               }
-       }
+       // Initialization
+       this.$element.addClass( 'oo-ui-buttonedElement' );
+       this.$button
+               .addClass( 'oo-ui-buttonedElement-button' )
+               .attr( 'role', 'button' );
+       this.setTabIndex( config.tabIndex || 0 );
+       this.setAccessKey( config.accessKey );
+       this.toggleFramed( config.framed === undefined || config.framed );
 };
 
+/* Setup */
+
+OO.initClass( OO.ui.ButtonedElement );
+
+/* Static Properties */
+
 /**
- * Add items.
+ * Cancel mouse down events.
  *
- * @param {OO.ui.Element[]} items Item
- * @param {number} [index] Index to insert items at
- * @chainable
+ * @static
+ * @inheritable
+ * @property {boolean}
  */
-OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
-       var i, len, item, event, events, currentIndex,
-               itemElements = [];
+OO.ui.ButtonedElement.static.cancelButtonMouseDownEvents = true;
 
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
+/* Methods */
 
-               // Check if item exists then remove it first, effectively "moving" it
-               currentIndex = $.inArray( item, this.items );
-               if ( currentIndex >= 0 ) {
-                       this.removeItems( [ item ] );
-                       // Adjust index to compensate for removal
-                       if ( currentIndex < index ) {
-                               index--;
-                       }
-               }
-               // Add the item
-               if ( item.connect && item.disconnect && !$.isEmptyObject( this.aggregateItemEvents ) ) {
-                       events = {};
-                       for ( event in this.aggregateItemEvents ) {
-                               events[event] = [ 'emit', this.aggregateItemEvents[event], item ];
-                       }
-                       item.connect( this, events );
-               }
-               item.setElementGroup( this );
-               itemElements.push( item.$element.get( 0 ) );
+/**
+ * Handles mouse down events.
+ *
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.ButtonedElement.prototype.onMouseDown = function ( e ) {
+       if ( this.isDisabled() || e.which !== 1 ) {
+               return false;
        }
-
-       if ( index === undefined || index < 0 || index >= this.items.length ) {
-               this.$group.append( itemElements );
-               this.items.push.apply( this.items, items );
-       } else if ( index === 0 ) {
-               this.$group.prepend( itemElements );
-               this.items.unshift.apply( this.items, items );
-       } else {
-               this.items[index].$element.before( itemElements );
-               this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
+       // tabIndex should generally be interacted with via the property, but it's not possible to
+       // reliably unset a tabIndex via a property so we use the (lowercase) "tabindex" attribute
+       this.tabIndex = this.$button.attr( 'tabindex' );
+       this.$button
+               // Remove the tab-index while the button is down to prevent the button from stealing focus
+               .removeAttr( 'tabindex' )
+               .addClass( 'oo-ui-buttonedElement-pressed' );
+       // Run the mouseup handler no matter where the mouse is when the button is let go, so we can
+       // reliably reapply the tabindex and remove the pressed class
+       this.getElementDocument().addEventListener( 'mouseup', this.onMouseUpHandler, true );
+       // Prevent change of focus unless specifically configured otherwise
+       if ( this.constructor.static.cancelButtonMouseDownEvents ) {
+               return false;
        }
-
-       return this;
 };
 
 /**
- * Remove items.
+ * Handles mouse up events.
  *
- * Items will be detached, not removed, so they can be used later.
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.ButtonedElement.prototype.onMouseUp = function ( e ) {
+       if ( this.isDisabled() || e.which !== 1 ) {
+               return false;
+       }
+       this.$button
+               // Restore the tab-index after the button is up to restore the button's accesssibility
+               .attr( 'tabindex', this.tabIndex )
+               .removeClass( 'oo-ui-buttonedElement-pressed' );
+       // Stop listening for mouseup, since we only needed this once
+       this.getElementDocument().removeEventListener( 'mouseup', this.onMouseUpHandler, true );
+};
+
+/**
+ * Toggle frame.
  *
- * @param {OO.ui.Element[]} items Items to remove
+ * @param {boolean} [framed] Make button framed, omit to toggle
  * @chainable
  */
-OO.ui.GroupElement.prototype.removeItems = function ( items ) {
-       var i, len, item, index, remove, itemEvent;
-
-       // Remove specific items
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               index = $.inArray( item, this.items );
-               if ( index !== -1 ) {
-                       if (
-                               item.connect && item.disconnect &&
-                               !$.isEmptyObject( this.aggregateItemEvents )
-                       ) {
-                               remove = {};
-                               if ( itemEvent in this.aggregateItemEvents ) {
-                                       remove[itemEvent] = [ 'emit', this.aggregateItemEvents[itemEvent], item ];
-                               }
-                               item.disconnect( this, remove );
-                       }
-                       item.setElementGroup( null );
-                       this.items.splice( index, 1 );
-                       item.$element.detach();
-               }
+OO.ui.ButtonedElement.prototype.toggleFramed = function ( framed ) {
+       framed = framed === undefined ? !this.framed : !!framed;
+       if ( framed !== this.framed ) {
+               this.framed = framed;
+               this.$element
+                       .toggleClass( 'oo-ui-buttonedElement-frameless', !framed )
+                       .toggleClass( 'oo-ui-buttonedElement-framed', framed );
        }
 
        return this;
 };
 
 /**
- * Clear all items.
- *
- * Items will be detached, not removed, so they can be used later.
+ * Set tab index.
  *
+ * @param {number|null} tabIndex Button's tab index, use null to remove
  * @chainable
  */
-OO.ui.GroupElement.prototype.clearItems = function () {
-       var i, len, item, remove, itemEvent;
+OO.ui.ButtonedElement.prototype.setTabIndex = function ( tabIndex ) {
+       if ( typeof tabIndex === 'number' && tabIndex >= 0 ) {
+               this.$button.attr( 'tabindex', tabIndex );
+       } else {
+               this.$button.removeAttr( 'tabindex' );
+       }
+       return this;
+};
 
-       // Remove all items
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               item = this.items[i];
-               if (
-                       item.connect && item.disconnect &&
-                       !$.isEmptyObject( this.aggregateItemEvents )
-               ) {
-                       remove = {};
-                       if ( itemEvent in this.aggregateItemEvents ) {
-                               remove[itemEvent] = [ 'emit', this.aggregateItemEvents[itemEvent], item ];
-                       }
-                       item.disconnect( this, remove );
-               }
-               item.setElementGroup( null );
-               item.$element.detach();
+/**
+ * Set access key
+ *
+ * @param {string} accessKey Button's access key, use empty string to remove
+ * @chainable
+ */
+OO.ui.ButtonedElement.prototype.setAccessKey = function ( accessKey ) {
+       if ( typeof accessKey === 'string' && accessKey.length ) {
+               this.$button.attr( 'accesskey', accessKey );
+       } else {
+               this.$button.removeAttr( 'accesskey' );
        }
+       return this;
+};
 
-       this.items = [];
+/**
+ * Set active state.
+ *
+ * @param {boolean} [value] Make button active
+ * @chainable
+ */
+OO.ui.ButtonedElement.prototype.setActive = function ( value ) {
+       this.$button.toggleClass( 'oo-ui-buttonedElement-active', !!value );
        return this;
 };
 
 /**
- * Element containing an icon.
+ * Element that can be automatically clipped to visible boundaies.
  *
  * @abstract
  * @class
  *
  * @constructor
- * @param {jQuery} $icon Icon node, assigned to #$icon
+ * @param {jQuery} $clippable Nodes to clip, assigned to #$clippable
  * @param {Object} [config] Configuration options
- * @cfg {Object|string} [icon=''] Symbolic icon name, or map of icon names keyed by language ID;
- *  use the 'default' key to specify the icon to be used when there is no icon in the user's
- *  language
  */
-OO.ui.IconedElement = function OoUiIconedElement( $icon, config ) {
-       // Config intialization
+OO.ui.ClippableElement = function OoUiClippableElement( $clippable, config ) {
+       // Configuration initialization
        config = config || {};
 
        // Properties
-       this.$icon = $icon;
-       this.icon = null;
+       this.$clippable = $clippable;
+       this.clipping = false;
+       this.clipped = false;
+       this.$clippableContainer = null;
+       this.$clippableScroller = null;
+       this.$clippableWindow = null;
+       this.idealWidth = null;
+       this.idealHeight = null;
+       this.onClippableContainerScrollHandler = OO.ui.bind( this.clip, this );
+       this.onClippableWindowResizeHandler = OO.ui.bind( this.clip, this );
 
        // Initialization
-       this.$icon.addClass( 'oo-ui-iconedElement-icon' );
-       this.setIcon( config.icon || this.constructor.static.icon );
+       this.$clippable.addClass( 'oo-ui-clippableElement-clippable' );
 };
 
-/* Setup */
-
-OO.initClass( OO.ui.IconedElement );
-
-/* Static Properties */
+/* Methods */
 
 /**
- * Icon.
- *
- * Value should be the unique portion of an icon CSS class name, such as 'up' for 'oo-ui-icon-up'.
+ * Set clipping.
  *
- * For i18n purposes, this property can be an object containing a `default` icon name property and
- * additional icon names keyed by language code.
+ * @param {boolean} value Enable clipping
+ * @chainable
+ */
+OO.ui.ClippableElement.prototype.setClipping = function ( value ) {
+       value = !!value;
+
+       if ( this.clipping !== value ) {
+               this.clipping = value;
+               if ( this.clipping ) {
+                       this.$clippableContainer = this.$( this.getClosestScrollableElementContainer() );
+                       // If the clippable container is the body, we have to listen to scroll events and check
+                       // jQuery.scrollTop on the window because of browser inconsistencies
+                       this.$clippableScroller = this.$clippableContainer.is( 'body' ) ?
+                               this.$( OO.ui.Element.getWindow( this.$clippableContainer ) ) :
+                               this.$clippableContainer;
+                       this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
+                       this.$clippableWindow = this.$( this.getElementWindow() )
+                               .on( 'resize', this.onClippableWindowResizeHandler );
+                       // Initial clip after visible
+                       setTimeout( OO.ui.bind( this.clip, this ) );
+               } else {
+                       this.$clippableContainer = null;
+                       this.$clippableScroller.off( 'scroll', this.onClippableContainerScrollHandler );
+                       this.$clippableScroller = null;
+                       this.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );
+                       this.$clippableWindow = null;
+               }
+       }
+
+       return this;
+};
+
+/**
+ * Check if the element will be clipped to fit the visible area of the nearest scrollable container.
  *
- * Example of i18n icon definition:
- *     { 'default': 'bold-a', 'en': 'bold-b', 'de': 'bold-f' }
+ * @return {boolean} Element will be clipped to the visible area
+ */
+OO.ui.ClippableElement.prototype.isClipping = function () {
+       return this.clipping;
+};
+
+/**
+ * Check if the bottom or right of the element is being clipped by the nearest scrollable container.
  *
- * @static
- * @inheritable
- * @property {Object|string} Symbolic icon name, or map of icon names keyed by language ID;
- *  use the 'default' key to specify the icon to be used when there is no icon in the user's
- *  language
+ * @return {boolean} Part of the element is being clipped
  */
-OO.ui.IconedElement.static.icon = null;
+OO.ui.ClippableElement.prototype.isClipped = function () {
+       return this.clipped;
+};
 
-/* Methods */
+/**
+ * Set the ideal size.
+ *
+ * @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix
+ * @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix
+ */
+OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
+       this.idealWidth = width;
+       this.idealHeight = height;
+};
 
 /**
- * Set icon.
+ * Clip element to visible boundaries and allow scrolling when needed.
+ *
+ * Element will be clipped the bottom or right of the element is within 10px of the edge of, or
+ * overlapped by, the visible area of the nearest scrollable container.
  *
- * @param {Object|string} icon Symbolic icon name, or map of icon names keyed by language ID;
- *  use the 'default' key to specify the icon to be used when there is no icon in the user's
- *  language
  * @chainable
  */
-OO.ui.IconedElement.prototype.setIcon = function ( icon ) {
-       icon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;
+OO.ui.ClippableElement.prototype.clip = function () {
+       if ( !this.clipping ) {
+               // this.$clippableContainer and this.$clippableWindow are null, so the below will fail
+               return this;
+       }
 
-       if ( this.icon ) {
-               this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
+       var buffer = 10,
+               cOffset = this.$clippable.offset(),
+               $container = this.$clippableContainer.is( 'body' ) ? this.$clippableWindow : this.$clippableContainer,
+               ccOffset = $container.offset() || { 'top': 0, 'left': 0 },
+               ccHeight = $container.innerHeight() - buffer,
+               ccWidth = $container.innerWidth() - buffer,
+               scrollTop = this.$clippableScroller.scrollTop(),
+               scrollLeft = this.$clippableScroller.scrollLeft(),
+               desiredWidth = ( ccOffset.left + scrollLeft + ccWidth ) - cOffset.left,
+               desiredHeight = ( ccOffset.top + scrollTop + ccHeight ) - cOffset.top,
+               naturalWidth = this.$clippable.prop( 'scrollWidth' ),
+               naturalHeight = this.$clippable.prop( 'scrollHeight' ),
+               clipWidth = desiredWidth < naturalWidth,
+               clipHeight = desiredHeight < naturalHeight;
+
+       if ( clipWidth ) {
+               this.$clippable.css( { 'overflow-x': 'auto', 'width': desiredWidth } );
+       } else {
+               this.$clippable.css( 'width', this.idealWidth || '' );
+               this.$clippable.width(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
+               this.$clippable.css( 'overflow-x', '' );
        }
-       if ( typeof icon === 'string' ) {
-               icon = icon.trim();
-               if ( icon.length ) {
-                       this.$icon.addClass( 'oo-ui-icon-' + icon );
-                       this.icon = icon;
-               }
+       if ( clipHeight ) {
+               this.$clippable.css( { 'overflow-y': 'auto', 'height': desiredHeight } );
+       } else {
+               this.$clippable.css( 'height', this.idealHeight || '' );
+               this.$clippable.height(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
+               this.$clippable.css( 'overflow-y', '' );
        }
-       this.$element.toggleClass( 'oo-ui-iconedElement', !!this.icon );
+
+       this.clipped = clipWidth || clipHeight;
 
        return this;
 };
 
 /**
- * Get icon.
+ * Element with named flags that can be added, removed, listed and checked.
  *
- * @return {string} Icon
- */
-OO.ui.IconedElement.prototype.getIcon = function () {
-       return this.icon;
-};
-
-/**
- * Element containing an indicator.
+ * A flag, when set, adds a CSS class on the `$element` by combing `oo-ui-flaggableElement-` with
+ * the flag name. Flags are primarily useful for styling.
  *
  * @abstract
  * @class
  *
  * @constructor
- * @param {jQuery} $indicator Indicator node, assigned to #$indicator
  * @param {Object} [config] Configuration options
- * @cfg {string} [indicator] Symbolic indicator name
- * @cfg {string} [indicatorTitle] Indicator title text or a function that return text
+ * @cfg {string[]} [flags=[]] Styling flags, e.g. 'primary', 'destructive' or 'constructive'
  */
-OO.ui.IndicatedElement = function OoUiIndicatedElement( $indicator, config ) {
-       // Config intialization
+OO.ui.FlaggableElement = function OoUiFlaggableElement( config ) {
+       // Config initialization
        config = config || {};
 
        // Properties
-       this.$indicator = $indicator;
-       this.indicator = null;
-       this.indicatorLabel = null;
+       this.flags = {};
 
        // Initialization
-       this.$indicator.addClass( 'oo-ui-indicatedElement-indicator' );
-       this.setIndicator( config.indicator || this.constructor.static.indicator );
-       this.setIndicatorTitle( config.indicatorTitle  || this.constructor.static.indicatorTitle );
+       this.setFlags( config.flags );
 };
 
-/* Setup */
+/* Events */
 
-OO.initClass( OO.ui.IndicatedElement );
+/**
+ * @event flag
+ * @param {Object.<string,boolean>} changes Object keyed by flag name containing boolean
+ *   added/removed properties
+ */
 
-/* Static Properties */
+/* Methods */
 
 /**
- * indicator.
+ * Check if a flag is set.
  *
- * @static
- * @inheritable
- * @property {string|null} Symbolic indicator name or null for no indicator
+ * @param {string} flag Name of flag
+ * @return {boolean} Has flag
  */
-OO.ui.IndicatedElement.static.indicator = null;
+OO.ui.FlaggableElement.prototype.hasFlag = function ( flag ) {
+       return flag in this.flags;
+};
 
 /**
- * Indicator title.
+ * Get the names of all flags set.
  *
- * @static
- * @inheritable
- * @property {string|Function|null} Indicator title text, a function that return text or null for no
- *  indicator title
+ * @return {string[]} flags Flag names
  */
-OO.ui.IndicatedElement.static.indicatorTitle = null;
-
-/* Methods */
+OO.ui.FlaggableElement.prototype.getFlags = function () {
+       return Object.keys( this.flags );
+};
 
 /**
- * Set indicator.
+ * Clear all flags.
  *
- * @param {string|null} indicator Symbolic name of indicator to use or null for no indicator
  * @chainable
+ * @fires flag
  */
-OO.ui.IndicatedElement.prototype.setIndicator = function ( indicator ) {
-       if ( this.indicator ) {
-               this.$indicator.removeClass( 'oo-ui-indicator-' + this.indicator );
-               this.indicator = null;
-       }
-       if ( typeof indicator === 'string' ) {
-               indicator = indicator.trim();
-               if ( indicator.length ) {
-                       this.$indicator.addClass( 'oo-ui-indicator-' + indicator );
-                       this.indicator = indicator;
-               }
+OO.ui.FlaggableElement.prototype.clearFlags = function () {
+       var flag,
+               changes = {},
+               classPrefix = 'oo-ui-flaggableElement-';
+
+       for ( flag in this.flags ) {
+               changes[flag] = false;
+               delete this.flags[flag];
+               this.$element.removeClass( classPrefix + flag );
        }
-       this.$element.toggleClass( 'oo-ui-indicatedElement', !!this.indicator );
+
+       this.emit( 'flag', changes );
 
        return this;
 };
 
 /**
- * Set indicator label.
+ * Add one or more flags.
  *
- * @param {string|Function|null} indicator Indicator title text, a function that return text or null
- *  for no indicator title
+ * @param {string|string[]|Object.<string, boolean>} flags One or more flags to add, or an object
+ *  keyed by flag name containing boolean set/remove instructions.
  * @chainable
+ * @fires flag
  */
-OO.ui.IndicatedElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
-       this.indicatorTitle = indicatorTitle = OO.ui.resolveMsg( indicatorTitle );
+OO.ui.FlaggableElement.prototype.setFlags = function ( flags ) {
+       var i, len, flag,
+               changes = {},
+               classPrefix = 'oo-ui-flaggableElement-';
 
-       if ( typeof indicatorTitle === 'string' && indicatorTitle.length ) {
-               this.$indicator.attr( 'title', indicatorTitle );
-       } else {
-               this.$indicator.removeAttr( 'title' );
+       if ( typeof flags === 'string' ) {
+               // Set
+               this.flags[flags] = true;
+               this.$element.addClass( classPrefix + flags );
+       } else if ( $.isArray( flags ) ) {
+               for ( i = 0, len = flags.length; i < len; i++ ) {
+                       flag = flags[i];
+                       // Set
+                       changes[flag] = true;
+                       this.flags[flag] = true;
+                       this.$element.addClass( classPrefix + flag );
+               }
+       } else if ( OO.isPlainObject( flags ) ) {
+               for ( flag in flags ) {
+                       if ( flags[flag] ) {
+                               // Set
+                               changes[flag] = true;
+                               this.flags[flag] = true;
+                               this.$element.addClass( classPrefix + flag );
+                       } else {
+                               // Remove
+                               changes[flag] = false;
+                               delete this.flags[flag];
+                               this.$element.removeClass( classPrefix + flag );
+                       }
+               }
        }
 
-       return this;
-};
-
-/**
- * Get indicator.
- *
- * @return {string} title Symbolic name of indicator
- */
-OO.ui.IndicatedElement.prototype.getIndicator = function () {
-       return this.indicator;
-};
+       this.emit( 'flag', changes );
 
-/**
- * Get indicator title.
- *
- * @return {string} Indicator title text
- */
-OO.ui.IndicatedElement.prototype.getIndicatorTitle = function () {
-       return this.indicatorTitle;
+       return this;
 };
 
 /**
- * Element containing a label.
+ * Element containing a sequence of child elements.
  *
  * @abstract
  * @class
  *
  * @constructor
- * @param {jQuery} $label Label node, assigned to #$label
+ * @param {jQuery} $group Container node, assigned to #$group
  * @param {Object} [config] Configuration options
- * @cfg {jQuery|string|Function} [label] Label nodes, text or a function that returns nodes or text
- * @cfg {boolean} [autoFitLabel=true] Whether to fit the label or not.
  */
-OO.ui.LabeledElement = function OoUiLabeledElement( $label, config ) {
-       // Config intialization
+OO.ui.GroupElement = function OoUiGroupElement( $group, config ) {
+       // Configuration
        config = config || {};
 
        // Properties
-       this.$label = $label;
-       this.label = null;
-
-       // Initialization
-       this.$label.addClass( 'oo-ui-labeledElement-label' );
-       this.setLabel( config.label || this.constructor.static.label );
-       this.autoFitLabel = config.autoFitLabel === undefined || !!config.autoFitLabel;
+       this.$group = $group;
+       this.items = [];
+       this.aggregateItemEvents = {};
 };
 
-/* Setup */
-
-OO.initClass( OO.ui.LabeledElement );
-
-/* Static Properties */
+/* Methods */
 
 /**
- * Label.
+ * Get items.
  *
- * @static
- * @inheritable
- * @property {string|Function|null} Label text; a function that returns a nodes or text; or null for
- *  no label
+ * @return {OO.ui.Element[]} Items
  */
-OO.ui.LabeledElement.static.label = null;
-
-/* Methods */
+OO.ui.GroupElement.prototype.getItems = function () {
+       return this.items.slice( 0 );
+};
 
 /**
- * Set the label.
+ * Add an aggregate item event.
  *
- * An empty string will result in the label being hidden. A string containing only whitespace will
- * be converted to a single &nbsp;
+ * Aggregated events are listened to on each item and then emitted by the group under a new name,
+ * and with an additional leading parameter containing the item that emitted the original event.
+ * Other arguments that were emitted from the original event are passed through.
  *
- * @param {jQuery|string|Function|null} label Label nodes; text; a function that retuns nodes or
- *  text; or null for no label
- * @chainable
+ * @param {Object.<string,string|null>} events Aggregate events emitted by group, keyed by item
+ *   event, use null value to remove aggregation
+ * @throws {Error} If aggregation already exists
  */
-OO.ui.LabeledElement.prototype.setLabel = function ( label ) {
-       var empty = false;
+OO.ui.GroupElement.prototype.aggregate = function ( events ) {
+       var i, len, item, add, remove, itemEvent, groupEvent;
 
-       this.label = label = OO.ui.resolveMsg( label ) || null;
-       if ( typeof label === 'string' && label.length ) {
-               if ( label.match( /^\s*$/ ) ) {
-                       // Convert whitespace only string to a single non-breaking space
-                       this.$label.html( '&nbsp;' );
-               } else {
-                       this.$label.text( label );
-               }
-       } else if ( label instanceof jQuery ) {
-               this.$label.empty().append( label );
-       } else {
-               this.$label.empty();
-               empty = true;
-       }
-       this.$element.toggleClass( 'oo-ui-labeledElement', !empty );
-       this.$label.css( 'display', empty ? 'none' : '' );
+       for ( itemEvent in events ) {
+               groupEvent = events[itemEvent];
 
-       return this;
-};
+               // Remove existing aggregated event
+               if ( itemEvent in this.aggregateItemEvents ) {
+                       // Don't allow duplicate aggregations
+                       if ( groupEvent ) {
+                               throw new Error( 'Duplicate item event aggregation for ' + itemEvent );
+                       }
+                       // Remove event aggregation from existing items
+                       for ( i = 0, len = this.items.length; i < len; i++ ) {
+                               item = this.items[i];
+                               if ( item.connect && item.disconnect ) {
+                                       remove = {};
+                                       remove[itemEvent] = [ 'emit', groupEvent, item ];
+                                       item.disconnect( this, remove );
+                               }
+                       }
+                       // Prevent future items from aggregating event
+                       delete this.aggregateItemEvents[itemEvent];
+               }
 
-/**
- * Get the label.
- *
- * @return {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
- *  text; or null for no label
- */
-OO.ui.LabeledElement.prototype.getLabel = function () {
-       return this.label;
+               // Add new aggregate event
+               if ( groupEvent ) {
+                       // Make future items aggregate event
+                       this.aggregateItemEvents[itemEvent] = groupEvent;
+                       // Add event aggregation to existing items
+                       for ( i = 0, len = this.items.length; i < len; i++ ) {
+                               item = this.items[i];
+                               if ( item.connect && item.disconnect ) {
+                                       add = {};
+                                       add[itemEvent] = [ 'emit', groupEvent, item ];
+                                       item.connect( this, add );
+                               }
+                       }
+               }
+       }
 };
 
 /**
- * Fit the label.
+ * Add items.
  *
+ * @param {OO.ui.Element[]} items Item
+ * @param {number} [index] Index to insert items at
  * @chainable
  */
-OO.ui.LabeledElement.prototype.fitLabel = function () {
-       if ( this.$label.autoEllipsis && this.autoFitLabel ) {
-               this.$label.autoEllipsis( { 'hasSpan': false, 'tooltip': true } );
+OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
+       var i, len, item, event, events, currentIndex,
+               itemElements = [];
+
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+
+               // Check if item exists then remove it first, effectively "moving" it
+               currentIndex = $.inArray( item, this.items );
+               if ( currentIndex >= 0 ) {
+                       this.removeItems( [ item ] );
+                       // Adjust index to compensate for removal
+                       if ( currentIndex < index ) {
+                               index--;
+                       }
+               }
+               // Add the item
+               if ( item.connect && item.disconnect && !$.isEmptyObject( this.aggregateItemEvents ) ) {
+                       events = {};
+                       for ( event in this.aggregateItemEvents ) {
+                               events[event] = [ 'emit', this.aggregateItemEvents[event], item ];
+                       }
+                       item.connect( this, events );
+               }
+               item.setElementGroup( this );
+               itemElements.push( item.$element.get( 0 ) );
+       }
+
+       if ( index === undefined || index < 0 || index >= this.items.length ) {
+               this.$group.append( itemElements );
+               this.items.push.apply( this.items, items );
+       } else if ( index === 0 ) {
+               this.$group.prepend( itemElements );
+               this.items.unshift.apply( this.items, items );
+       } else {
+               this.items[index].$element.before( itemElements );
+               this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
        }
+
        return this;
 };
 
 /**
- * Popuppable element.
+ * Remove items.
  *
- * @abstract
- * @class
+ * Items will be detached, not removed, so they can be used later.
  *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {number} [popupWidth=320] Width of popup
- * @cfg {number} [popupHeight] Height of popup
- * @cfg {Object} [popup] Configuration to pass to popup
+ * @param {OO.ui.Element[]} items Items to remove
+ * @chainable
  */
-OO.ui.PopuppableElement = function OoUiPopuppableElement( config ) {
-       // Configuration initialization
-       config = $.extend( { 'popupWidth': 320 }, config );
+OO.ui.GroupElement.prototype.removeItems = function ( items ) {
+       var i, len, item, index, remove, itemEvent;
 
-       // Properties
-       this.popup = new OO.ui.PopupWidget( $.extend(
-               { 'align': 'center', 'autoClose': true },
-               config.popup,
-               { '$': this.$, '$autoCloseIgnore': this.$element }
-       ) );
-       this.popupWidth = config.popupWidth;
-       this.popupHeight = config.popupHeight;
-};
+       // Remove specific items
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               index = $.inArray( item, this.items );
+               if ( index !== -1 ) {
+                       if (
+                               item.connect && item.disconnect &&
+                               !$.isEmptyObject( this.aggregateItemEvents )
+                       ) {
+                               remove = {};
+                               if ( itemEvent in this.aggregateItemEvents ) {
+                                       remove[itemEvent] = [ 'emit', this.aggregateItemEvents[itemEvent], item ];
+                               }
+                               item.disconnect( this, remove );
+                       }
+                       item.setElementGroup( null );
+                       this.items.splice( index, 1 );
+                       item.$element.detach();
+               }
+       }
 
-/* Methods */
+       return this;
+};
 
 /**
- * Get popup.
+ * Clear all items.
  *
- * @return {OO.ui.PopupWidget} Popup widget
+ * Items will be detached, not removed, so they can be used later.
+ *
+ * @chainable
  */
-OO.ui.PopuppableElement.prototype.getPopup = function () {
-       return this.popup;
-};
+OO.ui.GroupElement.prototype.clearItems = function () {
+       var i, len, item, remove, itemEvent;
 
-/**
- * Show popup.
- */
-OO.ui.PopuppableElement.prototype.showPopup = function () {
-       this.popup.show().display( this.popupWidth, this.popupHeight );
-};
+       // Remove all items
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               item = this.items[i];
+               if (
+                       item.connect && item.disconnect &&
+                       !$.isEmptyObject( this.aggregateItemEvents )
+               ) {
+                       remove = {};
+                       if ( itemEvent in this.aggregateItemEvents ) {
+                               remove[itemEvent] = [ 'emit', this.aggregateItemEvents[itemEvent], item ];
+                       }
+                       item.disconnect( this, remove );
+               }
+               item.setElementGroup( null );
+               item.$element.detach();
+       }
 
-/**
- * Hide popup.
- */
-OO.ui.PopuppableElement.prototype.hidePopup = function () {
-       this.popup.hide();
+       this.items = [];
+       return this;
 };
 
 /**
- * Element with a title.
+ * Element containing an icon.
+ *
+ * Icons are graphics, about the size of normal text. They can be used to aid the user in locating
+ * a control or convey information in a more space efficient way. Icons should rarely be used
+ * without labels; such as in a toolbar where space is at a premium or within a context where the
+ * meaning is very clear to the user.
  *
  * @abstract
  * @class
  *
  * @constructor
- * @param {jQuery} $label Titled node, assigned to #$titled
+ * @param {jQuery} $icon Icon node, assigned to #$icon
  * @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title text or a function that returns text
+ * @cfg {Object|string} [icon=''] Symbolic icon name, or map of icon names keyed by language ID;
+ *  use the 'default' key to specify the icon to be used when there is no icon in the user's
+ *  language
  */
-OO.ui.TitledElement = function OoUiTitledElement( $titled, config ) {
+OO.ui.IconedElement = function OoUiIconedElement( $icon, config ) {
        // Config intialization
        config = config || {};
 
        // Properties
-       this.$titled = $titled;
-       this.title = null;
+       this.$icon = $icon;
+       this.icon = null;
 
        // Initialization
-       this.setTitle( config.title || this.constructor.static.title );
+       this.$icon.addClass( 'oo-ui-iconedElement-icon' );
+       this.setIcon( config.icon || this.constructor.static.icon );
 };
 
 /* Setup */
 
-OO.initClass( OO.ui.TitledElement );
+OO.initClass( OO.ui.IconedElement );
 
 /* Static Properties */
 
 /**
- * Title.
+ * Icon.
+ *
+ * Value should be the unique portion of an icon CSS class name, such as 'up' for 'oo-ui-icon-up'.
+ *
+ * For i18n purposes, this property can be an object containing a `default` icon name property and
+ * additional icon names keyed by language code.
+ *
+ * Example of i18n icon definition:
+ *     { 'default': 'bold-a', 'en': 'bold-b', 'de': 'bold-f' }
  *
  * @static
  * @inheritable
- * @property {string|Function} Title text or a function that returns text
+ * @property {Object|string} Symbolic icon name, or map of icon names keyed by language ID;
+ *  use the 'default' key to specify the icon to be used when there is no icon in the user's
+ *  language
  */
-OO.ui.TitledElement.static.title = null;
+OO.ui.IconedElement.static.icon = null;
 
 /* Methods */
 
 /**
- * Set title.
+ * Set icon.
  *
- * @param {string|Function|null} title Title text, a function that returns text or null for no title
+ * @param {Object|string} icon Symbolic icon name, or map of icon names keyed by language ID;
+ *  use the 'default' key to specify the icon to be used when there is no icon in the user's
+ *  language
  * @chainable
  */
-OO.ui.TitledElement.prototype.setTitle = function ( title ) {
-       this.title = title = OO.ui.resolveMsg( title ) || null;
+OO.ui.IconedElement.prototype.setIcon = function ( icon ) {
+       icon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;
 
-       if ( typeof title === 'string' && title.length ) {
-               this.$titled.attr( 'title', title );
-       } else {
-               this.$titled.removeAttr( 'title' );
+       if ( this.icon ) {
+               this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
+       }
+       if ( typeof icon === 'string' ) {
+               icon = icon.trim();
+               if ( icon.length ) {
+                       this.$icon.addClass( 'oo-ui-icon-' + icon );
+                       this.icon = icon;
+               }
        }
+       this.$element.toggleClass( 'oo-ui-iconedElement', !!this.icon );
 
        return this;
 };
 
 /**
- * Get title.
+ * Get icon.
  *
- * @return {string} Title string
+ * @return {string} Icon
  */
-OO.ui.TitledElement.prototype.getTitle = function () {
-       return this.title;
+OO.ui.IconedElement.prototype.getIcon = function () {
+       return this.icon;
 };
 
 /**
- * Generic toolbar tool.
+ * Element containing an indicator.
+ *
+ * Indicators are graphics, smaller than normal text. They can be used to describe unique status or
+ * behavior. Indicators should only be used in exceptional cases; such as a button that opens a menu
+ * instead of performing an action directly, or an item in a list which has errors that need to be
+ * resolved.
  *
  * @abstract
  * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconedElement
  *
  * @constructor
- * @param {OO.ui.ToolGroup} toolGroup
+ * @param {jQuery} $indicator Indicator node, assigned to #$indicator
  * @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title text or a function that returns text
+ * @cfg {string} [indicator] Symbolic indicator name
+ * @cfg {string} [indicatorTitle] Indicator title text or a function that return text
  */
-OO.ui.Tool = function OoUiTool( toolGroup, config ) {
+OO.ui.IndicatedElement = function OoUiIndicatedElement( $indicator, config ) {
        // Config intialization
        config = config || {};
 
-       // Parent constructor
-       OO.ui.Tool.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
-
        // Properties
-       this.toolGroup = toolGroup;
-       this.toolbar = this.toolGroup.getToolbar();
-       this.active = false;
-       this.$title = this.$( '<span>' );
-       this.$link = this.$( '<a>' );
-       this.title = null;
-
-       // Events
-       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
+       this.$indicator = $indicator;
+       this.indicator = null;
+       this.indicatorLabel = null;
 
        // Initialization
-       this.$title.addClass( 'oo-ui-tool-title' );
-       this.$link
-               .addClass( 'oo-ui-tool-link' )
-               .append( this.$icon, this.$title );
-       this.$element
-               .data( 'oo-ui-tool', this )
-               .addClass(
-                       'oo-ui-tool ' + 'oo-ui-tool-name-' +
-                       this.constructor.static.name.replace( /^([^\/]+)\/([^\/]+).*$/, '$1-$2' )
-               )
-               .append( this.$link );
-       this.setTitle( config.title || this.constructor.static.title );
+       this.$indicator.addClass( 'oo-ui-indicatedElement-indicator' );
+       this.setIndicator( config.indicator || this.constructor.static.indicator );
+       this.setIndicatorTitle( config.indicatorTitle  || this.constructor.static.indicatorTitle );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.Tool, OO.ui.Widget );
-OO.mixinClass( OO.ui.Tool, OO.ui.IconedElement );
-
-/* Events */
-
-/**
- * @event select
- */
+OO.initClass( OO.ui.IndicatedElement );
 
 /* Static Properties */
 
 /**
- * @static
- * @inheritdoc
- */
-OO.ui.Tool.static.tagName = 'span';
-
-/**
- * Symbolic name of tool.
+ * indicator.
  *
- * @abstract
  * @static
  * @inheritable
- * @property {string}
+ * @property {string|null} Symbolic indicator name or null for no indicator
  */
-OO.ui.Tool.static.name = '';
+OO.ui.IndicatedElement.static.indicator = null;
 
 /**
- * Tool group.
+ * Indicator title.
  *
- * @abstract
  * @static
  * @inheritable
- * @property {string}
+ * @property {string|Function|null} Indicator title text, a function that return text or null for no
+ *  indicator title
  */
-OO.ui.Tool.static.group = '';
+OO.ui.IndicatedElement.static.indicatorTitle = null;
 
-/**
- * Tool title.
- *
- * Title is used as a tooltip when the tool is part of a bar tool group, or a label when the tool
- * is part of a list or menu tool group. If a trigger is associated with an action by the same name
- * as the tool, a description of its keyboard shortcut for the appropriate platform will be
- * appended to the title if the tool is part of a bar tool group.
- *
- * @abstract
- * @static
- * @inheritable
- * @property {string|Function} Title text or a function that returns text
- */
-OO.ui.Tool.static.title = '';
+/* Methods */
 
 /**
- * Tool can be automatically added to catch-all groups.
+ * Set indicator.
  *
- * @static
- * @inheritable
- * @property {boolean}
+ * @param {string|null} indicator Symbolic name of indicator to use or null for no indicator
+ * @chainable
  */
-OO.ui.Tool.static.autoAddToCatchall = true;
+OO.ui.IndicatedElement.prototype.setIndicator = function ( indicator ) {
+       if ( this.indicator ) {
+               this.$indicator.removeClass( 'oo-ui-indicator-' + this.indicator );
+               this.indicator = null;
+       }
+       if ( typeof indicator === 'string' ) {
+               indicator = indicator.trim();
+               if ( indicator.length ) {
+                       this.$indicator.addClass( 'oo-ui-indicator-' + indicator );
+                       this.indicator = indicator;
+               }
+       }
+       this.$element.toggleClass( 'oo-ui-indicatedElement', !!this.indicator );
+
+       return this;
+};
 
 /**
- * Tool can be automatically added to named groups.
+ * Set indicator label.
  *
- * @static
- * @property {boolean}
- * @inheritable
+ * @param {string|Function|null} indicator Indicator title text, a function that return text or null
+ *  for no indicator title
+ * @chainable
  */
-OO.ui.Tool.static.autoAddToGroup = true;
+OO.ui.IndicatedElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
+       this.indicatorTitle = indicatorTitle = OO.ui.resolveMsg( indicatorTitle );
+
+       if ( typeof indicatorTitle === 'string' && indicatorTitle.length ) {
+               this.$indicator.attr( 'title', indicatorTitle );
+       } else {
+               this.$indicator.removeAttr( 'title' );
+       }
+
+       return this;
+};
 
 /**
- * Check if this tool is compatible with given data.
+ * Get indicator.
  *
- * @static
- * @inheritable
- * @param {Mixed} data Data to check
- * @return {boolean} Tool can be used with data
+ * @return {string} title Symbolic name of indicator
  */
-OO.ui.Tool.static.isCompatibleWith = function () {
-       return false;
+OO.ui.IndicatedElement.prototype.getIndicator = function () {
+       return this.indicator;
 };
 
-/* Methods */
-
 /**
- * Handle the toolbar state being updated.
- *
- * This is an abstract method that must be overridden in a concrete subclass.
+ * Get indicator title.
  *
- * @abstract
+ * @return {string} Indicator title text
  */
-OO.ui.Tool.prototype.onUpdateState = function () {
-       throw new Error(
-               'OO.ui.Tool.onUpdateState not implemented in this subclass:' + this.constructor
-       );
+OO.ui.IndicatedElement.prototype.getIndicatorTitle = function () {
+       return this.indicatorTitle;
 };
 
 /**
- * Handle the tool being selected.
- *
- * This is an abstract method that must be overridden in a concrete subclass.
+ * Element containing a label.
  *
  * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {jQuery} $label Label node, assigned to #$label
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery|string|Function} [label] Label nodes, text or a function that returns nodes or text
+ * @cfg {boolean} [autoFitLabel=true] Whether to fit the label or not.
  */
-OO.ui.Tool.prototype.onSelect = function () {
-       throw new Error(
-               'OO.ui.Tool.onSelect not implemented in this subclass:' + this.constructor
-       );
+OO.ui.LabeledElement = function OoUiLabeledElement( $label, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Properties
+       this.$label = $label;
+       this.label = null;
+
+       // Initialization
+       this.$label.addClass( 'oo-ui-labeledElement-label' );
+       this.setLabel( config.label || this.constructor.static.label );
+       this.autoFitLabel = config.autoFitLabel === undefined || !!config.autoFitLabel;
 };
 
+/* Setup */
+
+OO.initClass( OO.ui.LabeledElement );
+
+/* Static Properties */
+
 /**
- * Check if the button is active.
+ * Label.
  *
- * @param {boolean} Button is active
+ * @static
+ * @inheritable
+ * @property {string|Function|null} Label text; a function that returns a nodes or text; or null for
+ *  no label
  */
-OO.ui.Tool.prototype.isActive = function () {
-       return this.active;
-};
+OO.ui.LabeledElement.static.label = null;
+
+/* Methods */
 
 /**
- * Make the button appear active or inactive.
+ * Set the label.
  *
- * @param {boolean} state Make button appear active
- */
-OO.ui.Tool.prototype.setActive = function ( state ) {
-       this.active = !!state;
-       if ( this.active ) {
-               this.$element.addClass( 'oo-ui-tool-active' );
+ * An empty string will result in the label being hidden. A string containing only whitespace will
+ * be converted to a single &nbsp;
+ *
+ * @param {jQuery|string|Function|null} label Label nodes; text; a function that retuns nodes or
+ *  text; or null for no label
+ * @chainable
+ */
+OO.ui.LabeledElement.prototype.setLabel = function ( label ) {
+       var empty = false;
+
+       this.label = label = OO.ui.resolveMsg( label ) || null;
+       if ( typeof label === 'string' && label.length ) {
+               if ( label.match( /^\s*$/ ) ) {
+                       // Convert whitespace only string to a single non-breaking space
+                       this.$label.html( '&nbsp;' );
+               } else {
+                       this.$label.text( label );
+               }
+       } else if ( label instanceof jQuery ) {
+               this.$label.empty().append( label );
        } else {
-               this.$element.removeClass( 'oo-ui-tool-active' );
+               this.$label.empty();
+               empty = true;
        }
+       this.$element.toggleClass( 'oo-ui-labeledElement', !empty );
+       this.$label.css( 'display', empty ? 'none' : '' );
+
+       return this;
 };
 
 /**
- * Get the tool title.
+ * Get the label.
+ *
+ * @return {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
+ *  text; or null for no label
+ */
+OO.ui.LabeledElement.prototype.getLabel = function () {
+       return this.label;
+};
+
+/**
+ * Fit the label.
  *
- * @param {string|Function} title Title text or a function that returns text
  * @chainable
  */
-OO.ui.Tool.prototype.setTitle = function ( title ) {
-       this.title = OO.ui.resolveMsg( title );
-       this.updateTitle();
+OO.ui.LabeledElement.prototype.fitLabel = function () {
+       if ( this.$label.autoEllipsis && this.autoFitLabel ) {
+               this.$label.autoEllipsis( { 'hasSpan': false, 'tooltip': true } );
+       }
        return this;
 };
 
 /**
- * Get the tool title.
+ * Element containing an OO.ui.PopupWidget object.
  *
- * @return {string} Title text
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Object} [popup] Configuration to pass to popup
+ * @cfg {boolean} [autoClose=true] Popup auto-closes when it loses focus
  */
-OO.ui.Tool.prototype.getTitle = function () {
-       return this.title;
+OO.ui.PopuppableElement = function OoUiPopuppableElement( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Properties
+       this.popup = new OO.ui.PopupWidget( $.extend(
+               { 'autoClose': true },
+               config.popup,
+               { '$': this.$, '$autoCloseIgnore': this.$element }
+       ) );
 };
 
+/* Methods */
+
 /**
- * Get the tool's symbolic name.
+ * Get popup.
  *
- * @return {string} Symbolic name of tool
+ * @return {OO.ui.PopupWidget} Popup widget
  */
-OO.ui.Tool.prototype.getName = function () {
-       return this.constructor.static.name;
+OO.ui.PopuppableElement.prototype.getPopup = function () {
+       return this.popup;
 };
 
 /**
- * Update the title.
+ * Element with a title.
+ *
+ * Titles are rendered by the browser and are made visible when hovering the element. Titles are
+ * not visible on touch devices.
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {jQuery} $label Titled node, assigned to #$titled
+ * @param {Object} [config] Configuration options
+ * @cfg {string|Function} [title] Title text or a function that returns text
  */
-OO.ui.Tool.prototype.updateTitle = function () {
-       var titleTooltips = this.toolGroup.constructor.static.titleTooltips,
-               accelTooltips = this.toolGroup.constructor.static.accelTooltips,
-               accel = this.toolbar.getToolAccelerator( this.constructor.static.name ),
-               tooltipParts = [];
+OO.ui.TitledElement = function OoUiTitledElement( $titled, config ) {
+       // Config intialization
+       config = config || {};
 
-       this.$title.empty()
-               .text( this.title )
-               .append(
-                       this.$( '<span>' )
-                               .addClass( 'oo-ui-tool-accel' )
-                               .text( accel )
-               );
+       // Properties
+       this.$titled = $titled;
+       this.title = null;
 
-       if ( titleTooltips && typeof this.title === 'string' && this.title.length ) {
-               tooltipParts.push( this.title );
-       }
-       if ( accelTooltips && typeof accel === 'string' && accel.length ) {
-               tooltipParts.push( accel );
-       }
-       if ( tooltipParts.length ) {
-               this.$link.attr( 'title', tooltipParts.join( ' ' ) );
+       // Initialization
+       this.setTitle( config.title || this.constructor.static.title );
+};
+
+/* Setup */
+
+OO.initClass( OO.ui.TitledElement );
+
+/* Static Properties */
+
+/**
+ * Title.
+ *
+ * @static
+ * @inheritable
+ * @property {string|Function} Title text or a function that returns text
+ */
+OO.ui.TitledElement.static.title = null;
+
+/* Methods */
+
+/**
+ * Set title.
+ *
+ * @param {string|Function|null} title Title text, a function that returns text or null for no title
+ * @chainable
+ */
+OO.ui.TitledElement.prototype.setTitle = function ( title ) {
+       this.title = title = OO.ui.resolveMsg( title ) || null;
+
+       if ( typeof title === 'string' && title.length ) {
+               this.$titled.attr( 'title', title );
        } else {
-               this.$link.removeAttr( 'title' );
+               this.$titled.removeAttr( 'title' );
        }
+
+       return this;
 };
 
 /**
- * Destroy tool.
+ * Get title.
+ *
+ * @return {string} Title string
  */
-OO.ui.Tool.prototype.destroy = function () {
-       this.toolbar.disconnect( this );
-       this.$element.remove();
+OO.ui.TitledElement.prototype.getTitle = function () {
+       return this.title;
 };
 
 /**
- * Collection of tool groups.
+ * Generic toolbar tool.
  *
+ * @abstract
  * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- * @mixins OO.ui.GroupElement
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.IconedElement
  *
  * @constructor
- * @param {OO.ui.ToolFactory} toolFactory Factory for creating tools
- * @param {OO.ui.ToolGroupFactory} toolGroupFactory Factory for creating tool groups
+ * @param {OO.ui.ToolGroup} toolGroup
  * @param {Object} [config] Configuration options
- * @cfg {boolean} [actions] Add an actions section opposite to the tools
- * @cfg {boolean} [shadow] Add a shadow below the toolbar
+ * @cfg {string|Function} [title] Title text or a function that returns text
  */
-OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
-       // Configuration initialization
+OO.ui.Tool = function OoUiTool( toolGroup, config ) {
+       // Config intialization
        config = config || {};
 
        // Parent constructor
-       OO.ui.Toolbar.super.call( this, config );
+       OO.ui.Tool.super.call( this, config );
 
        // Mixin constructors
-       OO.EventEmitter.call( this );
-       OO.ui.GroupElement.call( this, this.$( '<div>' ), config );
+       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
 
        // Properties
-       this.toolFactory = toolFactory;
-       this.toolGroupFactory = toolGroupFactory;
-       this.groups = [];
-       this.tools = {};
-       this.$bar = this.$( '<div>' );
-       this.$actions = this.$( '<div>' );
-       this.initialized = false;
+       this.toolGroup = toolGroup;
+       this.toolbar = this.toolGroup.getToolbar();
+       this.active = false;
+       this.$title = this.$( '<span>' );
+       this.$link = this.$( '<a>' );
+       this.title = null;
 
        // Events
-       this.$element
-               .add( this.$bar ).add( this.$group ).add( this.$actions )
-               .on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
+       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
 
        // Initialization
-       this.$group.addClass( 'oo-ui-toolbar-tools' );
-       this.$bar.addClass( 'oo-ui-toolbar-bar' ).append( this.$group );
-       if ( config.actions ) {
-               this.$actions.addClass( 'oo-ui-toolbar-actions' );
-               this.$bar.append( this.$actions );
-       }
-       this.$bar.append( '<div style="clear:both"></div>' );
-       if ( config.shadow ) {
-               this.$bar.append( '<div class="oo-ui-toolbar-shadow"></div>' );
-       }
-       this.$element.addClass( 'oo-ui-toolbar' ).append( this.$bar );
+       this.$title.addClass( 'oo-ui-tool-title' );
+       this.$link
+               .addClass( 'oo-ui-tool-link' )
+               .append( this.$icon, this.$title )
+               .prop( 'tabIndex', 0 )
+               .attr( 'role', 'button' );
+       this.$element
+               .data( 'oo-ui-tool', this )
+               .addClass(
+                       'oo-ui-tool ' + 'oo-ui-tool-name-' +
+                       this.constructor.static.name.replace( /^([^\/]+)\/([^\/]+).*$/, '$1-$2' )
+               )
+               .append( this.$link );
+       this.setTitle( config.title || this.constructor.static.title );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.Toolbar, OO.ui.Element );
-OO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );
-OO.mixinClass( OO.ui.Toolbar, OO.ui.GroupElement );
+OO.inheritClass( OO.ui.Tool, OO.ui.Widget );
+OO.mixinClass( OO.ui.Tool, OO.ui.IconedElement );
 
-/* Methods */
+/* Events */
 
 /**
- * Get the tool factory.
- *
- * @return {OO.ui.ToolFactory} Tool factory
+ * @event select
  */
-OO.ui.Toolbar.prototype.getToolFactory = function () {
-       return this.toolFactory;
-};
+
+/* Static Properties */
 
 /**
- * Get the tool group factory.
- *
- * @return {OO.Factory} Tool group factory
+ * @static
+ * @inheritdoc
  */
-OO.ui.Toolbar.prototype.getToolGroupFactory = function () {
-       return this.toolGroupFactory;
-};
+OO.ui.Tool.static.tagName = 'span';
 
 /**
- * Handles mouse down events.
+ * Symbolic name of tool.
  *
- * @param {jQuery.Event} e Mouse down event
+ * @abstract
+ * @static
+ * @inheritable
+ * @property {string}
  */
-OO.ui.Toolbar.prototype.onMouseDown = function ( e ) {
-       var $closestWidgetToEvent = this.$( e.target ).closest( '.oo-ui-widget' ),
-               $closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );
-       if ( !$closestWidgetToEvent.length || $closestWidgetToEvent[0] === $closestWidgetToToolbar[0] ) {
-               return false;
-       }
-};
+OO.ui.Tool.static.name = '';
 
 /**
- * Sets up handles and preloads required information for the toolbar to work.
- * This must be called immediately after it is attached to a visible document.
+ * Tool group.
+ *
+ * @abstract
+ * @static
+ * @inheritable
+ * @property {string}
  */
-OO.ui.Toolbar.prototype.initialize = function () {
-       this.initialized = true;
-};
+OO.ui.Tool.static.group = '';
 
 /**
- * Setup toolbar.
+ * Tool title.
  *
- * Tools can be specified in the following ways:
+ * Title is used as a tooltip when the tool is part of a bar tool group, or a label when the tool
+ * is part of a list or menu tool group. If a trigger is associated with an action by the same name
+ * as the tool, a description of its keyboard shortcut for the appropriate platform will be
+ * appended to the title if the tool is part of a bar tool group.
  *
- * - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ 'group': 'group-name' }`
- * - All tools: `'*'` - Using this will make the group a list with a "More" label by default
+ * @abstract
+ * @static
+ * @inheritable
+ * @property {string|Function} Title text or a function that returns text
+ */
+OO.ui.Tool.static.title = '';
+
+/**
+ * Tool can be automatically added to catch-all groups.
  *
- * @param {Object.<string,Array>} groups List of tool group configurations
- * @param {Array|string} [groups.include] Tools to include
- * @param {Array|string} [groups.exclude] Tools to exclude
- * @param {Array|string} [groups.promote] Tools to promote to the beginning
- * @param {Array|string} [groups.demote] Tools to demote to the end
+ * @static
+ * @inheritable
+ * @property {boolean}
  */
-OO.ui.Toolbar.prototype.setup = function ( groups ) {
-       var i, len, type, group,
-               items = [],
-               defaultType = 'bar';
+OO.ui.Tool.static.autoAddToCatchall = true;
 
-       // Cleanup previous groups
-       this.reset();
+/**
+ * Tool can be automatically added to named groups.
+ *
+ * @static
+ * @property {boolean}
+ * @inheritable
+ */
+OO.ui.Tool.static.autoAddToGroup = true;
 
-       // Build out new groups
-       for ( i = 0, len = groups.length; i < len; i++ ) {
-               group = groups[i];
-               if ( group.include === '*' ) {
-                       // Apply defaults to catch-all groups
-                       if ( group.type === undefined ) {
-                               group.type = 'list';
-                       }
-                       if ( group.label === undefined ) {
-                               group.label = 'ooui-toolbar-more';
-                       }
-               }
-               // Check type has been registered
-               type = this.getToolGroupFactory().lookup( group.type ) ? group.type : defaultType;
-               items.push(
-                       this.getToolGroupFactory().create( type, this, $.extend( { '$': this.$ }, group ) )
-               );
-       }
-       this.addItems( items );
+/**
+ * Check if this tool is compatible with given data.
+ *
+ * @static
+ * @inheritable
+ * @param {Mixed} data Data to check
+ * @return {boolean} Tool can be used with data
+ */
+OO.ui.Tool.static.isCompatibleWith = function () {
+       return false;
 };
 
+/* Methods */
+
 /**
- * Remove all tools and groups from the toolbar.
+ * Handle the toolbar state being updated.
+ *
+ * This is an abstract method that must be overridden in a concrete subclass.
+ *
+ * @abstract
  */
-OO.ui.Toolbar.prototype.reset = function () {
-       var i, len;
-
-       this.groups = [];
-       this.tools = {};
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               this.items[i].destroy();
-       }
-       this.clearItems();
+OO.ui.Tool.prototype.onUpdateState = function () {
+       throw new Error(
+               'OO.ui.Tool.onUpdateState not implemented in this subclass:' + this.constructor
+       );
 };
 
 /**
- * Destroys toolbar, removing event handlers and DOM elements.
+ * Handle the tool being selected.
  *
- * Call this whenever you are done using a toolbar.
+ * This is an abstract method that must be overridden in a concrete subclass.
+ *
+ * @abstract
  */
-OO.ui.Toolbar.prototype.destroy = function () {
-       this.reset();
-       this.$element.remove();
+OO.ui.Tool.prototype.onSelect = function () {
+       throw new Error(
+               'OO.ui.Tool.onSelect not implemented in this subclass:' + this.constructor
+       );
 };
 
 /**
- * Check if tool has not been used yet.
+ * Check if the button is active.
  *
- * @param {string} name Symbolic name of tool
- * @return {boolean} Tool is available
+ * @param {boolean} Button is active
  */
-OO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {
-       return !this.tools[name];
+OO.ui.Tool.prototype.isActive = function () {
+       return this.active;
 };
 
 /**
- * Prevent tool from being used again.
+ * Make the button appear active or inactive.
  *
- * @param {OO.ui.Tool} tool Tool to reserve
+ * @param {boolean} state Make button appear active
  */
-OO.ui.Toolbar.prototype.reserveTool = function ( tool ) {
-       this.tools[tool.getName()] = tool;
+OO.ui.Tool.prototype.setActive = function ( state ) {
+       this.active = !!state;
+       if ( this.active ) {
+               this.$element.addClass( 'oo-ui-tool-active' );
+       } else {
+               this.$element.removeClass( 'oo-ui-tool-active' );
+       }
 };
 
 /**
- * Allow tool to be used again.
+ * Get the tool title.
  *
- * @param {OO.ui.Tool} tool Tool to release
+ * @param {string|Function} title Title text or a function that returns text
+ * @chainable
  */
-OO.ui.Toolbar.prototype.releaseTool = function ( tool ) {
-       delete this.tools[tool.getName()];
+OO.ui.Tool.prototype.setTitle = function ( title ) {
+       this.title = OO.ui.resolveMsg( title );
+       this.updateTitle();
+       return this;
 };
 
 /**
- * Get accelerator label for tool.
- *
- * This is a stub that should be overridden to provide access to accelerator information.
+ * Get the tool title.
  *
- * @param {string} name Symbolic name of tool
- * @return {string|undefined} Tool accelerator label if available
+ * @return {string} Title text
  */
-OO.ui.Toolbar.prototype.getToolAccelerator = function () {
-       return undefined;
+OO.ui.Tool.prototype.getTitle = function () {
+       return this.title;
 };
 
 /**
- * Factory for tools.
+ * Get the tool's symbolic name.
  *
- * @class
- * @extends OO.Factory
- * @constructor
+ * @return {string} Symbolic name of tool
  */
-OO.ui.ToolFactory = function OoUiToolFactory() {
-       // Parent constructor
-       OO.ui.ToolFactory.super.call( this );
+OO.ui.Tool.prototype.getName = function () {
+       return this.constructor.static.name;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.ToolFactory, OO.Factory );
-
-/* Methods */
-
-/** */
-OO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {
-       var i, len, included, promoted, demoted,
-               auto = [],
-               used = {};
-
-       // Collect included and not excluded tools
-       included = OO.simpleArrayDifference( this.extract( include ), this.extract( exclude ) );
+/**
+ * Update the title.
+ */
+OO.ui.Tool.prototype.updateTitle = function () {
+       var titleTooltips = this.toolGroup.constructor.static.titleTooltips,
+               accelTooltips = this.toolGroup.constructor.static.accelTooltips,
+               accel = this.toolbar.getToolAccelerator( this.constructor.static.name ),
+               tooltipParts = [];
 
-       // Promotion
-       promoted = this.extract( promote, used );
-       demoted = this.extract( demote, used );
+       this.$title.empty()
+               .text( this.title )
+               .append(
+                       this.$( '<span>' )
+                               .addClass( 'oo-ui-tool-accel' )
+                               .text( accel )
+               );
 
-       // Auto
-       for ( i = 0, len = included.length; i < len; i++ ) {
-               if ( !used[included[i]] ) {
-                       auto.push( included[i] );
-               }
+       if ( titleTooltips && typeof this.title === 'string' && this.title.length ) {
+               tooltipParts.push( this.title );
+       }
+       if ( accelTooltips && typeof accel === 'string' && accel.length ) {
+               tooltipParts.push( accel );
+       }
+       if ( tooltipParts.length ) {
+               this.$link.attr( 'title', tooltipParts.join( ' ' ) );
+       } else {
+               this.$link.removeAttr( 'title' );
        }
+};
 
-       return promoted.concat( auto ).concat( demoted );
+/**
+ * Destroy tool.
+ */
+OO.ui.Tool.prototype.destroy = function () {
+       this.toolbar.disconnect( this );
+       this.$element.remove();
 };
 
 /**
- * Get a flat list of names from a list of names or groups.
- *
- * Tools can be specified in the following ways:
+ * Collection of tool groups.
  *
- * - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ 'group': 'group-name' }`
- * - All tools: `'*'`
+ * @class
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
+ * @mixins OO.ui.GroupElement
  *
- * @private
- * @param {Array|string} collection List of tools
- * @param {Object} [used] Object with names that should be skipped as properties; extracted
- *  names will be added as properties
- * @return {string[]} List of extracted names
- */
-OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
-       var i, len, item, name, tool,
-               names = [];
-
-       if ( collection === '*' ) {
-               for ( name in this.registry ) {
-                       tool = this.registry[name];
-                       if (
-                               // Only add tools by group name when auto-add is enabled
-                               tool.static.autoAddToCatchall &&
-                               // Exclude already used tools
-                               ( !used || !used[name] )
-                       ) {
-                               names.push( name );
-                               if ( used ) {
-                                       used[name] = true;
-                               }
-                       }
-               }
-       } else if ( $.isArray( collection ) ) {
-               for ( i = 0, len = collection.length; i < len; i++ ) {
-                       item = collection[i];
-                       // Allow plain strings as shorthand for named tools
-                       if ( typeof item === 'string' ) {
-                               item = { 'name': item };
+ * @constructor
+ * @param {OO.ui.ToolFactory} toolFactory Factory for creating tools
+ * @param {OO.ui.ToolGroupFactory} toolGroupFactory Factory for creating tool groups
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [actions] Add an actions section opposite to the tools
+ * @cfg {boolean} [shadow] Add a shadow below the toolbar
+ */
+OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Toolbar.super.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+       OO.ui.GroupElement.call( this, this.$( '<div>' ), config );
+
+       // Properties
+       this.toolFactory = toolFactory;
+       this.toolGroupFactory = toolGroupFactory;
+       this.groups = [];
+       this.tools = {};
+       this.$bar = this.$( '<div>' );
+       this.$actions = this.$( '<div>' );
+       this.initialized = false;
+
+       // Events
+       this.$element
+               .add( this.$bar ).add( this.$group ).add( this.$actions )
+               .on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
+
+       // Initialization
+       this.$group.addClass( 'oo-ui-toolbar-tools' );
+       this.$bar.addClass( 'oo-ui-toolbar-bar' ).append( this.$group );
+       if ( config.actions ) {
+               this.$actions.addClass( 'oo-ui-toolbar-actions' );
+               this.$bar.append( this.$actions );
+       }
+       this.$bar.append( '<div style="clear:both"></div>' );
+       if ( config.shadow ) {
+               this.$bar.append( '<div class="oo-ui-toolbar-shadow"></div>' );
+       }
+       this.$element.addClass( 'oo-ui-toolbar' ).append( this.$bar );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.Toolbar, OO.ui.Element );
+OO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );
+OO.mixinClass( OO.ui.Toolbar, OO.ui.GroupElement );
+
+/* Methods */
+
+/**
+ * Get the tool factory.
+ *
+ * @return {OO.ui.ToolFactory} Tool factory
+ */
+OO.ui.Toolbar.prototype.getToolFactory = function () {
+       return this.toolFactory;
+};
+
+/**
+ * Get the tool group factory.
+ *
+ * @return {OO.Factory} Tool group factory
+ */
+OO.ui.Toolbar.prototype.getToolGroupFactory = function () {
+       return this.toolGroupFactory;
+};
+
+/**
+ * Handles mouse down events.
+ *
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.Toolbar.prototype.onMouseDown = function ( e ) {
+       var $closestWidgetToEvent = this.$( e.target ).closest( '.oo-ui-widget' ),
+               $closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );
+       if ( !$closestWidgetToEvent.length || $closestWidgetToEvent[0] === $closestWidgetToToolbar[0] ) {
+               return false;
+       }
+};
+
+/**
+ * Sets up handles and preloads required information for the toolbar to work.
+ * This must be called immediately after it is attached to a visible document.
+ */
+OO.ui.Toolbar.prototype.initialize = function () {
+       this.initialized = true;
+};
+
+/**
+ * Setup toolbar.
+ *
+ * Tools can be specified in the following ways:
+ *
+ * - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
+ * - All tools in a group: `{ 'group': 'group-name' }`
+ * - All tools: `'*'` - Using this will make the group a list with a "More" label by default
+ *
+ * @param {Object.<string,Array>} groups List of tool group configurations
+ * @param {Array|string} [groups.include] Tools to include
+ * @param {Array|string} [groups.exclude] Tools to exclude
+ * @param {Array|string} [groups.promote] Tools to promote to the beginning
+ * @param {Array|string} [groups.demote] Tools to demote to the end
+ */
+OO.ui.Toolbar.prototype.setup = function ( groups ) {
+       var i, len, type, group,
+               items = [],
+               defaultType = 'bar';
+
+       // Cleanup previous groups
+       this.reset();
+
+       // Build out new groups
+       for ( i = 0, len = groups.length; i < len; i++ ) {
+               group = groups[i];
+               if ( group.include === '*' ) {
+                       // Apply defaults to catch-all groups
+                       if ( group.type === undefined ) {
+                               group.type = 'list';
                        }
-                       if ( OO.isPlainObject( item ) ) {
-                               if ( item.group ) {
-                                       for ( name in this.registry ) {
-                                               tool = this.registry[name];
-                                               if (
-                                                       // Include tools with matching group
-                                                       tool.static.group === item.group &&
-                                                       // Only add tools by group name when auto-add is enabled
-                                                       tool.static.autoAddToGroup &&
-                                                       // Exclude already used tools
-                                                       ( !used || !used[name] )
-                                               ) {
-                                                       names.push( name );
-                                                       if ( used ) {
-                                                               used[name] = true;
-                                                       }
-                                               }
-                                       }
-                               // Include tools with matching name and exclude already used tools
-                               } else if ( item.name && ( !used || !used[item.name] ) ) {
-                                       names.push( item.name );
-                                       if ( used ) {
-                                               used[item.name] = true;
-                                       }
-                               }
+                       if ( group.label === undefined ) {
+                               group.label = 'ooui-toolbar-more';
                        }
                }
+               // Check type has been registered
+               type = this.getToolGroupFactory().lookup( group.type ) ? group.type : defaultType;
+               items.push(
+                       this.getToolGroupFactory().create( type, this, $.extend( { '$': this.$ }, group ) )
+               );
        }
-       return names;
+       this.addItems( items );
+};
+
+/**
+ * Remove all tools and groups from the toolbar.
+ */
+OO.ui.Toolbar.prototype.reset = function () {
+       var i, len;
+
+       this.groups = [];
+       this.tools = {};
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               this.items[i].destroy();
+       }
+       this.clearItems();
+};
+
+/**
+ * Destroys toolbar, removing event handlers and DOM elements.
+ *
+ * Call this whenever you are done using a toolbar.
+ */
+OO.ui.Toolbar.prototype.destroy = function () {
+       this.reset();
+       this.$element.remove();
+};
+
+/**
+ * Check if tool has not been used yet.
+ *
+ * @param {string} name Symbolic name of tool
+ * @return {boolean} Tool is available
+ */
+OO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {
+       return !this.tools[name];
+};
+
+/**
+ * Prevent tool from being used again.
+ *
+ * @param {OO.ui.Tool} tool Tool to reserve
+ */
+OO.ui.Toolbar.prototype.reserveTool = function ( tool ) {
+       this.tools[tool.getName()] = tool;
+};
+
+/**
+ * Allow tool to be used again.
+ *
+ * @param {OO.ui.Tool} tool Tool to release
+ */
+OO.ui.Toolbar.prototype.releaseTool = function ( tool ) {
+       delete this.tools[tool.getName()];
+};
+
+/**
+ * Get accelerator label for tool.
+ *
+ * This is a stub that should be overridden to provide access to accelerator information.
+ *
+ * @param {string} name Symbolic name of tool
+ * @return {string|undefined} Tool accelerator label if available
+ */
+OO.ui.Toolbar.prototype.getToolAccelerator = function () {
+       return undefined;
 };
 
 /**
@@ -3797,9 +4926,9 @@ OO.ui.ToolGroup.prototype.onMouseDown = function ( e ) {
                        this.getElementDocument().addEventListener(
                                'mouseup', this.onCapturedMouseUpHandler, true
                        );
-                       return false;
                }
        }
+       return false;
 };
 
 /**
@@ -3974,367 +5103,440 @@ OO.ui.ToolGroup.prototype.destroy = function () {
 };
 
 /**
- * Factory for tool groups.
+ * Dialog for showing a message.
+ *
+ * User interface:
+ * - Registers two actions by default (safe and primary).
+ * - Renders action widgets in the footer.
  *
  * @class
- * @extends OO.Factory
+ * @extends OO.ui.Dialog
+ *
  * @constructor
+ * @param {Object} [config] Configuration options
  */
-OO.ui.ToolGroupFactory = function OoUiToolGroupFactory() {
+OO.ui.MessageDialog = function OoUiMessageDialog( manager, config ) {
        // Parent constructor
-       OO.Factory.call( this );
+       OO.ui.MessageDialog.super.call( this, manager, config );
 
-       var i, l,
-               defaultClasses = this.constructor.static.getDefaultClasses();
+       // Properties
+       this.verticalActionLayout = null;
 
-       // Register default toolgroups
-       for ( i = 0, l = defaultClasses.length; i < l; i++ ) {
-               this.register( defaultClasses[i] );
-       }
+       // Initialization
+       this.$element.addClass( 'oo-ui-messageDialog' );
 };
 
-/* Setup */
+/* Inheritance */
 
-OO.inheritClass( OO.ui.ToolGroupFactory, OO.Factory );
+OO.inheritClass( OO.ui.MessageDialog, OO.ui.Dialog );
 
-/* Static Methods */
+/* Static Properties */
+
+OO.ui.MessageDialog.static.name = 'message';
+
+OO.ui.MessageDialog.static.size = 'small';
+
+OO.ui.MessageDialog.static.verbose = false;
 
 /**
- * Get a default set of classes to be registered on construction
+ * Dialog title.
  *
- * @return {Function[]} Default classes
+ * A confirmation dialog's title should describe what the progressive action will do. An alert
+ * dialog's title should describe what event occured.
+ *
+ * @static
+ * inheritable
+ * @property {jQuery|string|Function|null}
  */
-OO.ui.ToolGroupFactory.static.getDefaultClasses = function () {
-       return [
-               OO.ui.BarToolGroup,
-               OO.ui.ListToolGroup,
-               OO.ui.MenuToolGroup
-       ];
-};
+OO.ui.MessageDialog.static.title = null;
 
 /**
- * Layout made of a fieldset and optional legend.
- *
- * Just add OO.ui.FieldLayout items.
- *
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.LabeledElement
- * @mixins OO.ui.IconedElement
- * @mixins OO.ui.GroupElement
+ * A confirmation dialog's message should describe the consequences of the progressive action. An
+ * alert dialog's message should describe why the event occured.
  *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [icon] Symbolic icon name
- * @cfg {OO.ui.FieldLayout[]} [items] Items to add
+ * @static
+ * inheritable
+ * @property {jQuery|string|Function|null}
  */
-OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
-       // Config initialization
-       config = config || {};
+OO.ui.MessageDialog.static.message = null;
 
-       // Parent constructor
-       OO.ui.FieldsetLayout.super.call( this, config );
+OO.ui.MessageDialog.static.actions = [
+       { 'action': 'accept', 'label': OO.ui.deferMsg( 'ooui-dialog-message-accept' ), 'flags': 'primary' },
+       { 'action': 'reject', 'label': OO.ui.deferMsg( 'ooui-dialog-message-reject' ), 'flags': 'safe' }
+];
 
-       // Mixin constructors
-       OO.ui.IconedElement.call( this, this.$( '<div>' ), config );
-       OO.ui.LabeledElement.call( this, this.$( '<div>' ), config );
-       OO.ui.GroupElement.call( this, this.$( '<div>' ), config );
+/* Methods */
 
-       // Initialization
-       this.$element
-               .addClass( 'oo-ui-fieldsetLayout' )
-               .prepend( this.$icon, this.$label, this.$group );
-       if ( $.isArray( config.items ) ) {
-               this.addItems( config.items );
-       }
+/**
+ * @inheritdoc
+ */
+OO.ui.MessageDialog.prototype.onActionResize = function ( action ) {
+       this.fitActions();
+       return OO.ui.ProcessDialog.super.prototype.onActionResize.call( this, action );
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.IconedElement );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.LabeledElement );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.GroupElement );
-
-/* Static Properties */
-
-OO.ui.FieldsetLayout.static.tagName = 'div';
-
 /**
- * Layout made of a field and optional label.
- *
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.LabeledElement
- *
- * Available label alignment modes include:
- *  - 'left': Label is before the field and aligned away from it, best for when the user will be
- *    scanning for a specific label in a form with many fields
- *  - 'right': Label is before the field and aligned toward it, best for forms the user is very
- *    familiar with and will tab through field checking quickly to verify which field they are in
- *  - 'top': Label is before the field and above it, best for when the use will need to fill out all
- *    fields from top to bottom in a form with few fields
- *  - 'inline': Label is after the field and aligned toward it, best for small boolean fields like
- *    checkboxes or radio buttons
+ * Toggle action layout between vertical and horizontal.
  *
- * @constructor
- * @param {OO.ui.Widget} field Field widget
- * @param {Object} [config] Configuration options
- * @cfg {string} [align='left'] Alignment mode, either 'left', 'right', 'top' or 'inline'
+ * @param {boolean} [value] Layout actions vertically, omit to toggle
+ * @chainable
  */
-OO.ui.FieldLayout = function OoUiFieldLayout( field, config ) {
-       // Config initialization
-       config = $.extend( { 'align': 'left' }, config );
-
-       // Parent constructor
-       OO.ui.FieldLayout.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.LabeledElement.call( this, this.$( '<label>' ), config );
-
-       // Properties
-       this.$field = this.$( '<div>' );
-       this.field = field;
-       this.align = null;
+OO.ui.MessageDialog.prototype.toggleVerticalActionLayout = function ( value ) {
+       value = value === undefined ? !this.verticalActionLayout : !!value;
 
-       // Events
-       if ( this.field instanceof OO.ui.InputWidget ) {
-               this.$label.on( 'click', OO.ui.bind( this.onLabelClick, this ) );
+       if ( value !== this.verticalActionLayout ) {
+               this.verticalActionLayout = value;
+               this.$actions
+                       .toggleClass( 'oo-ui-messageDialog-actions-vertical', value )
+                       .toggleClass( 'oo-ui-messageDialog-actions-horizontal', !value );
        }
-       this.field.connect( this, { 'disable': 'onFieldDisable' } );
 
-       // Initialization
-       this.$element.addClass( 'oo-ui-fieldLayout' );
-       this.$field
-               .addClass( 'oo-ui-fieldLayout-field' )
-               .toggleClass( 'oo-ui-fieldLayout-disable', this.field.isDisabled() )
-               .append( this.field.$element );
-       this.setAlignment( config.align );
+       return this;
 };
 
-/* Setup */
+/**
+ * @inheritdoc
+ */
+OO.ui.MessageDialog.prototype.getActionProcess = function ( action ) {
+       if ( action ) {
+               return new OO.ui.Process( function () {
+                       this.close( { 'action': action } );
+               }, this );
+       }
+       return OO.ui.MessageDialog.super.prototype.getActionProcess.call( this, action );
+};
 
-OO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FieldLayout, OO.ui.LabeledElement );
+/**
+ * @inheritdoc
+ *
+ * @param {Object} [data] Dialog opening data
+ * @param {jQuery|string|Function|null} [data.title] Description of the action being confirmed
+ * @param {jQuery|string|Function|null} [data.message] Description of the action's consequence
+ * @param {boolean} [data.verbose] Message is verbose and should be styled as a long message
+ * @param {Object[]} [data.actions] List of OO.ui.ActionOptionWidget configuration options for each
+ *   action item
+ */
+OO.ui.MessageDialog.prototype.getSetupProcess = function ( data ) {
+       data = data || {};
 
-/* Methods */
+       // Parent method
+       return OO.ui.MessageDialog.super.prototype.getSetupProcess.call( this, data )
+               .next( function () {
+                       this.title.setLabel(
+                               data.title !== undefined ? data.title : this.constructor.static.title
+                       );
+                       this.message.setLabel(
+                               data.message !== undefined ? data.message : this.constructor.static.message
+                       );
+                       this.message.$element.toggleClass(
+                               'oo-ui-messageDialog-message-verbose',
+                               data.verbose !== undefined ? data.verbose : this.constructor.static.verbose
+                       );
+               }, this );
+};
 
 /**
- * Handle field disable events.
- *
- * @param {boolean} value Field is disabled
+ * @inheritdoc
  */
-OO.ui.FieldLayout.prototype.onFieldDisable = function ( value ) {
-       this.$element.toggleClass( 'oo-ui-fieldLayout-disabled', value );
+OO.ui.MessageDialog.prototype.getBodyHeight = function () {
+       return Math.round( this.text.$element.outerHeight( true ) );
 };
 
 /**
- * Handle label mouse click events.
- *
- * @param {jQuery.Event} e Mouse click event
+ * @inheritdoc
  */
-OO.ui.FieldLayout.prototype.onLabelClick = function () {
-       this.field.simulateLabelClick();
-       return false;
+OO.ui.MessageDialog.prototype.initialize = function () {
+       // Parent method
+       OO.ui.MessageDialog.super.prototype.initialize.call( this );
+
+       // Properties
+       this.$actions = this.$( '<div>' );
+       this.container = new OO.ui.PanelLayout( {
+               '$': this.$, 'scrollable': true, 'classes': [ 'oo-ui-messageDialog-container' ]
+       } );
+       this.text = new OO.ui.PanelLayout( {
+               '$': this.$, 'padded': true, 'expanded': false, 'classes': [ 'oo-ui-messageDialog-text' ]
+       } );
+       this.message = new OO.ui.LabelWidget( {
+               '$': this.$, 'classes': [ 'oo-ui-messageDialog-message' ]
+       } );
+
+       // Initialization
+       this.title.$element.addClass( 'oo-ui-messageDialog-title' );
+       this.frame.$content.addClass( 'oo-ui-messageDialog-content' );
+       this.container.$element.append( this.text.$element );
+       this.text.$element.append( this.title.$element, this.message.$element );
+       this.$body.append( this.container.$element );
+       this.$actions.addClass( 'oo-ui-messageDialog-actions' );
+       this.$foot.append( this.$actions );
 };
 
 /**
- * Get the field.
- *
- * @return {OO.ui.Widget} Field widget
+ * @inheritdoc
  */
-OO.ui.FieldLayout.prototype.getField = function () {
-       return this.field;
+OO.ui.MessageDialog.prototype.attachActions = function () {
+       var i, len, other, special, others;
+
+       // Parent method
+       OO.ui.MessageDialog.super.prototype.attachActions.call( this );
+
+       special = this.actions.getSpecial();
+       others = this.actions.getOthers();
+       if ( special.safe ) {
+               this.$actions.append( special.safe.$element );
+               special.safe.toggleFramed( false );
+       }
+       if ( others.length ) {
+               for ( i = 0, len = others.length; i < len; i++ ) {
+                       other = others[i];
+                       this.$actions.append( other.$element );
+                       other.toggleFramed( false );
+               }
+       }
+       if ( special.primary ) {
+               this.$actions.append( special.primary.$element );
+               special.primary.toggleFramed( false );
+       }
+
+       this.fitActions();
+       if ( !this.isOpening() ) {
+               this.manager.updateWindowSize( this );
+       }
+       this.$body.css( 'bottom', this.$foot.outerHeight( true ) );
 };
 
 /**
- * Set the field alignment mode.
+ * Fit action actions into columns or rows.
  *
- * @param {string} value Alignment mode, either 'left', 'right', 'top' or 'inline'
- * @chainable
+ * Columns will be used if all labels can fit without overflow, otherwise rows will be used.
  */
-OO.ui.FieldLayout.prototype.setAlignment = function ( value ) {
-       if ( value !== this.align ) {
-               // Default to 'left'
-               if ( [ 'left', 'right', 'top', 'inline' ].indexOf( value ) === -1 ) {
-                       value = 'left';
-               }
-               // Reorder elements
-               if ( value === 'inline' ) {
-                       this.$element.append( this.$field, this.$label );
-               } else {
-                       this.$element.append( this.$label, this.$field );
-               }
-               // Set classes
-               if ( this.align ) {
-                       this.$element.removeClass( 'oo-ui-fieldLayout-align-' + this.align );
+OO.ui.MessageDialog.prototype.fitActions = function () {
+       var i, len, action,
+               actions = this.actions.get();
+
+       // Detect clipping
+       this.toggleVerticalActionLayout( false );
+       for ( i = 0, len = actions.length; i < len; i++ ) {
+               action = actions[i];
+               if ( action.$element.innerWidth() < action.$label.outerWidth( true ) ) {
+                       this.toggleVerticalActionLayout( true );
+                       break;
                }
-               this.align = value;
-               this.$element.addClass( 'oo-ui-fieldLayout-align-' + this.align );
        }
-
-       return this;
 };
 
 /**
- * Layout made of proportionally sized columns and rows.
+ * Navigation dialog window.
+ *
+ * Logic:
+ * - Show and hide errors.
+ * - Retry an action.
+ *
+ * User interface:
+ * - Renders header with dialog title and one action widget on either side
+ *   (a 'safe' button on the left, and a 'primary' button on the right, both of
+ *   which close the dialog).
+ * - Displays any action widgets in the footer (none by default).
+ * - Ability to dismiss errors.
+ *
+ * Subclass responsibilities:
+ * - Register a 'safe' action.
+ * - Register a 'primary' action.
+ * - Add content to the dialog.
  *
+ * @abstract
  * @class
- * @extends OO.ui.Layout
+ * @extends OO.ui.Dialog
  *
  * @constructor
- * @param {OO.ui.PanelLayout[]} panels Panels in the grid
  * @param {Object} [config] Configuration options
- * @cfg {number[]} [widths] Widths of columns as ratios
- * @cfg {number[]} [heights] Heights of columns as ratios
  */
-OO.ui.GridLayout = function OoUiGridLayout( panels, config ) {
-       var i, len, widths;
-
-       // Config initialization
-       config = config || {};
-
+OO.ui.ProcessDialog = function OoUiProcessDialog( manager, config ) {
        // Parent constructor
-       OO.ui.GridLayout.super.call( this, config );
-
-       // Properties
-       this.panels = [];
-       this.widths = [];
-       this.heights = [];
+       OO.ui.ProcessDialog.super.call( this, manager, config );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-gridLayout' );
-       for ( i = 0, len = panels.length; i < len; i++ ) {
-               this.panels.push( panels[i] );
-               this.$element.append( panels[i].$element );
-       }
-       if ( config.widths || config.heights ) {
-               this.layout( config.widths || [ 1 ], config.heights || [ 1 ] );
-       } else {
-               // Arrange in columns by default
-               widths = [];
-               for ( i = 0, len = this.panels.length; i < len; i++ ) {
-                       widths[i] = 1;
-               }
-               this.layout( widths, [ 1 ] );
-       }
+       this.$element.addClass( 'oo-ui-processDialog' );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.GridLayout, OO.ui.Layout );
+OO.inheritClass( OO.ui.ProcessDialog, OO.ui.Dialog );
 
-/* Events */
+/* Methods */
 
 /**
- * @event layout
+ * Handle dismiss button click events.
+ *
+ * Hides errors.
  */
+OO.ui.ProcessDialog.prototype.onDismissErrorButtonClick = function () {
+       this.hideErrors();
+};
 
 /**
- * @event update
+ * Handle retry button click events.
+ *
+ * Hides errors and then tries again.
  */
+OO.ui.ProcessDialog.prototype.onRetryButtonClick = function () {
+       this.hideErrors();
+       this.executeAction( this.currentAction.getAction() );
+};
 
-/* Static Properties */
-
-OO.ui.GridLayout.static.tagName = 'div';
-
-/* Methods */
+/**
+ * @inheritdoc
+ */
+OO.ui.ProcessDialog.prototype.onActionResize = function ( action ) {
+       if ( this.actions.isSpecial( action ) ) {
+               this.fitLabel();
+       }
+       return OO.ui.ProcessDialog.super.prototype.onActionResize.call( this, action );
+};
 
 /**
- * Set grid dimensions.
- *
- * @param {number[]} widths Widths of columns as ratios
- * @param {number[]} heights Heights of rows as ratios
- * @fires layout
- * @throws {Error} If grid is not large enough to fit all panels
+ * @inheritdoc
  */
-OO.ui.GridLayout.prototype.layout = function ( widths, heights ) {
-       var x, y,
-               xd = 0,
-               yd = 0,
-               cols = widths.length,
-               rows = heights.length;
+OO.ui.ProcessDialog.prototype.initialize = function () {
+       // Parent method
+       OO.ui.ProcessDialog.super.prototype.initialize.call( this );
 
-       // Verify grid is big enough to fit panels
-       if ( cols * rows < this.panels.length ) {
-               throw new Error( 'Grid is not large enough to fit ' + this.panels.length + 'panels' );
-       }
+       // Properties
+       this.$navigation = this.$( '<div>' );
+       this.$location = this.$( '<div>' );
+       this.$safeActions = this.$( '<div>' );
+       this.$primaryActions = this.$( '<div>' );
+       this.$otherActions = this.$( '<div>' );
+       this.dismissButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'label': OO.ui.msg( 'ooui-dialog-process-dismiss' )
+       } );
+       this.retryButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'label': OO.ui.msg( 'ooui-dialog-process-retry' )
+       } );
+       this.$errors = this.$( '<div>' );
+       this.$errorsTitle = this.$( '<div>' );
 
-       // Sum up denominators
-       for ( x = 0; x < cols; x++ ) {
-               xd += widths[x];
-       }
-       for ( y = 0; y < rows; y++ ) {
-               yd += heights[y];
-       }
-       // Store factors
-       this.widths = [];
-       this.heights = [];
-       for ( x = 0; x < cols; x++ ) {
-               this.widths[x] = widths[x] / xd;
-       }
-       for ( y = 0; y < rows; y++ ) {
-               this.heights[y] = heights[y] / yd;
-       }
-       // Synchronize view
-       this.update();
-       this.emit( 'layout' );
+       // Events
+       this.dismissButton.connect( this, { 'click': 'onDismissErrorButtonClick' } );
+       this.retryButton.connect( this, { 'click': 'onRetryButtonClick' } );
+
+       // Initialization
+       this.title.$element.addClass( 'oo-ui-processDialog-title' );
+       this.$location
+               .append( this.title.$element )
+               .addClass( 'oo-ui-processDialog-location' );
+       this.$safeActions.addClass( 'oo-ui-processDialog-actions-safe' );
+       this.$primaryActions.addClass( 'oo-ui-processDialog-actions-primary' );
+       this.$otherActions.addClass( 'oo-ui-processDialog-actions-other' );
+       this.$errorsTitle
+               .addClass( 'oo-ui-processDialog-errors-title' )
+               .text( OO.ui.msg( 'ooui-dialog-process-error' ) );
+       this.$errors
+               .addClass( 'oo-ui-processDialog-errors' )
+               .append( this.$errorsTitle, this.dismissButton.$element, this.retryButton.$element );
+       this.frame.$content
+               .addClass( 'oo-ui-processDialog-content' )
+               .append( this.$errors );
+       this.$navigation
+               .addClass( 'oo-ui-processDialog-navigation' )
+               .append( this.$safeActions, this.$location, this.$primaryActions );
+       this.$head.append( this.$navigation );
+       this.$foot.append( this.$otherActions );
 };
 
 /**
- * Update panel positions and sizes.
- *
- * @fires update
+ * @inheritdoc
  */
-OO.ui.GridLayout.prototype.update = function () {
-       var x, y, panel,
-               i = 0,
-               left = 0,
-               top = 0,
-               dimensions,
-               width = 0,
-               height = 0,
-               cols = this.widths.length,
-               rows = this.heights.length;
+OO.ui.ProcessDialog.prototype.attachActions = function () {
+       var i, len, other, special, others;
 
-       for ( y = 0; y < rows; y++ ) {
-               for ( x = 0; x < cols; x++ ) {
-                       panel = this.panels[i];
-                       width = this.widths[x];
-                       height = this.heights[y];
-                       dimensions = {
-                               'width': Math.round( width * 100 ) + '%',
-                               'height': Math.round( height * 100 ) + '%',
-                               'top': Math.round( top * 100 ) + '%'
-                       };
-                       // If RTL, reverse:
-                       if ( OO.ui.Element.getDir( this.$.context ) === 'rtl' ) {
-                               dimensions.right = Math.round( left * 100 ) + '%';
-                       } else {
-                               dimensions.left = Math.round( left * 100 ) + '%';
-                       }
-                       panel.$element.css( dimensions );
-                       i++;
-                       left += width;
+       // Parent method
+       OO.ui.ProcessDialog.super.prototype.attachActions.call( this );
+
+       special = this.actions.getSpecial();
+       others = this.actions.getOthers();
+       if ( special.primary ) {
+               this.$primaryActions.append( special.primary.$element );
+               special.primary.toggleFramed( true );
+       }
+       if ( others.length ) {
+               for ( i = 0, len = others.length; i < len; i++ ) {
+                       other = others[i];
+                       this.$otherActions.append( other.$element );
+                       other.toggleFramed( true );
                }
-               top += height;
-               left = 0;
+       }
+       if ( special.safe ) {
+               this.$safeActions.append( special.safe.$element );
+               special.safe.toggleFramed( true );
        }
 
-       this.emit( 'update' );
+       this.fitLabel();
+       this.$body.css( 'bottom', this.$foot.outerHeight( true ) );
 };
 
 /**
- * Get a panel at a given position.
+ * @inheritdoc
+ */
+OO.ui.ProcessDialog.prototype.executeAction = function ( action ) {
+       OO.ui.ProcessDialog.super.prototype.executeAction.call( this, action )
+               .fail( OO.ui.bind( this.showErrors, this ) );
+};
+
+/**
+ * Fit label between actions.
  *
- * The x and y position is affected by the current grid layout.
+ * @chainable
+ */
+OO.ui.ProcessDialog.prototype.fitLabel = function () {
+       var width = Math.max(
+               this.$safeActions.is( ':visible' ) ? this.$safeActions.width() : 0,
+               this.$primaryActions.is( ':visible' ) ? this.$primaryActions.width() : 0
+       );
+       this.$location.css( { 'padding-left': width, 'padding-right': width } );
+
+       return this;
+};
+
+/**
+ * Handle errors that occured durring accept or reject processes.
  *
- * @param {number} x Horizontal position
- * @param {number} y Vertical position
- * @return {OO.ui.PanelLayout} The panel at the given postion
+ * @param {OO.ui.Error[]} errors Errors to be handled
  */
-OO.ui.GridLayout.prototype.getPanel = function ( x, y ) {
-       return this.panels[( x * this.widths.length ) + y];
+OO.ui.ProcessDialog.prototype.showErrors = function ( errors ) {
+       var i, len, $item,
+               items = [],
+               recoverable = true;
+
+       for ( i = 0, len = errors.length; i < len; i++ ) {
+               if ( !errors[i].isRecoverable() ) {
+                       recoverable = false;
+               }
+               $item = this.$( '<div>' )
+                       .addClass( 'oo-ui-processDialog-error' )
+                       .append( errors[i].getMessage() );
+               items.push( $item[0] );
+       }
+       this.$errorItems = this.$( items );
+       if ( recoverable ) {
+               this.retryButton.clearFlags().setFlags( this.currentAction.getFlags() );
+       } else {
+               this.currentAction.setDisabled( true );
+       }
+       this.retryButton.toggle( recoverable );
+       this.$errorsTitle.after( this.$errorItems );
+       this.$errors.show().scrollTop( 0 );
+};
+
+/**
+ * Hide errors.
+ */
+OO.ui.ProcessDialog.prototype.hideErrors = function () {
+       this.$errors.hide();
+       this.$errorItems.remove();
+       this.$errorItems = null;
 };
 
 /**
@@ -4362,7 +5564,7 @@ OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
        this.pages = {};
        this.ignoreFocus = false;
        this.stackLayout = new OO.ui.StackLayout( { '$': this.$, 'continuous': !!config.continuous } );
-       this.autoFocus = config.autoFocus === undefined ? true : !!config.autoFocus;
+       this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
        this.outlineVisible = false;
        this.outlined = !!config.outlined;
        if ( this.outlined ) {
@@ -4459,15 +5661,19 @@ OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {
  * @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel
  */
 OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {
+       var $input, layout = this;
        if ( page ) {
-               page.scrollElementIntoView( { 'complete': OO.ui.bind( function () {
-                       if ( this.autoFocus ) {
+               page.scrollElementIntoView( { 'complete': function () {
+                       if ( layout.autoFocus ) {
                                // Set focus to the first input if nothing on the page is focused yet
                                if ( !page.$element.find( ':focus' ).length ) {
-                                       page.$element.find( ':input:first' ).focus();
+                                       $input = page.$element.find( ':input:first' );
+                                       if ( $input.length ) {
+                                               $input[0].focus();
+                                       }
                                }
                        }
-               }, this ) } );
+               } } );
        }
 };
 
@@ -4702,58 +5908,456 @@ OO.ui.BookletLayout.prototype.clearPages = function () {
        }
        this.stackLayout.clearItems();
 
-       this.emit( 'remove', pages );
+       this.emit( 'remove', pages );
+
+       return this;
+};
+
+/**
+ * Set the current page by name.
+ *
+ * @fires set
+ * @param {string} name Symbolic name of page
+ */
+OO.ui.BookletLayout.prototype.setPage = function ( name ) {
+       var selectedItem,
+               $focused,
+               page = this.pages[name];
+
+       if ( name !== this.currentPageName ) {
+               if ( this.outlined ) {
+                       selectedItem = this.outlineWidget.getSelectedItem();
+                       if ( selectedItem && selectedItem.getData() !== name ) {
+                               this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) );
+                       }
+               }
+               if ( page ) {
+                       if ( this.currentPageName && this.pages[this.currentPageName] ) {
+                               this.pages[this.currentPageName].setActive( false );
+                               // Blur anything focused if the next page doesn't have anything focusable - this
+                               // is not needed if the next page has something focusable because once it is focused
+                               // this blur happens automatically
+                               if ( this.autoFocus && !page.$element.find( ':input' ).length ) {
+                                       $focused = this.pages[this.currentPageName].$element.find( ':focus' );
+                                       if ( $focused.length ) {
+                                               $focused[0].blur();
+                                       }
+                               }
+                       }
+                       this.currentPageName = name;
+                       this.stackLayout.setItem( page );
+                       page.setActive( true );
+                       this.emit( 'set', page );
+               }
+       }
+};
+
+/**
+ * Call this after adding or removing items from the OutlineWidget.
+ *
+ * @chainable
+ */
+OO.ui.BookletLayout.prototype.updateOutlineWidget = function () {
+       // Auto-select first item when nothing is selected anymore
+       if ( !this.outlineWidget.getSelectedItem() ) {
+               this.outlineWidget.selectItem( this.outlineWidget.getFirstSelectableItem() );
+       }
+
+       return this;
+};
+
+/**
+ * Layout made of a field and optional label.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ * @mixins OO.ui.LabeledElement
+ *
+ * Available label alignment modes include:
+ *  - 'left': Label is before the field and aligned away from it, best for when the user will be
+ *    scanning for a specific label in a form with many fields
+ *  - 'right': Label is before the field and aligned toward it, best for forms the user is very
+ *    familiar with and will tab through field checking quickly to verify which field they are in
+ *  - 'top': Label is before the field and above it, best for when the use will need to fill out all
+ *    fields from top to bottom in a form with few fields
+ *  - 'inline': Label is after the field and aligned toward it, best for small boolean fields like
+ *    checkboxes or radio buttons
+ *
+ * @constructor
+ * @param {OO.ui.Widget} field Field widget
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [align='left'] Alignment mode, either 'left', 'right', 'top' or 'inline'
+ * @cfg {string} [help] Explanatory text shown as a '?' icon.
+ */
+OO.ui.FieldLayout = function OoUiFieldLayout( field, config ) {
+       var popupButtonWidget;
+       // Config initialization
+       config = $.extend( { 'align': 'left' }, config );
+
+       // Parent constructor
+       OO.ui.FieldLayout.super.call( this, config );
+
+       // Mixin constructors
+       this.$help = this.$( '<div>' );
+       OO.ui.LabeledElement.call( this, this.$( '<label>' ), config );
+       if ( config.help ) {
+               popupButtonWidget = new OO.ui.PopupButtonWidget( $.extend(
+                       {
+                               '$': this.$,
+                               'frameless': true,
+                               'icon': 'info',
+                               'title': config.help
+                       },
+                       config,
+                       { label: null }
+               ) );
+               popupButtonWidget.getPopup().$body.append( this.getElementDocument().createTextNode( config.help ) );
+               this.$help = popupButtonWidget.$element;
+       }
+
+       // Properties
+       this.$field = this.$( '<div>' );
+       this.field = field;
+       this.align = null;
+
+       // Events
+       if ( this.field instanceof OO.ui.InputWidget ) {
+               this.$label.on( 'click', OO.ui.bind( this.onLabelClick, this ) );
+       }
+       this.field.connect( this, { 'disable': 'onFieldDisable' } );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-fieldLayout' );
+       this.$field
+               .addClass( 'oo-ui-fieldLayout-field' )
+               .toggleClass( 'oo-ui-fieldLayout-disable', this.field.isDisabled() )
+               .append( this.field.$element );
+       this.setAlignment( config.align );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );
+OO.mixinClass( OO.ui.FieldLayout, OO.ui.LabeledElement );
+
+/* Methods */
+
+/**
+ * Handle field disable events.
+ *
+ * @param {boolean} value Field is disabled
+ */
+OO.ui.FieldLayout.prototype.onFieldDisable = function ( value ) {
+       this.$element.toggleClass( 'oo-ui-fieldLayout-disabled', value );
+};
+
+/**
+ * Handle label mouse click events.
+ *
+ * @param {jQuery.Event} e Mouse click event
+ */
+OO.ui.FieldLayout.prototype.onLabelClick = function () {
+       this.field.simulateLabelClick();
+       return false;
+};
+
+/**
+ * Get the field.
+ *
+ * @return {OO.ui.Widget} Field widget
+ */
+OO.ui.FieldLayout.prototype.getField = function () {
+       return this.field;
+};
+
+/**
+ * Set the field alignment mode.
+ *
+ * @param {string} value Alignment mode, either 'left', 'right', 'top' or 'inline'
+ * @chainable
+ */
+OO.ui.FieldLayout.prototype.setAlignment = function ( value ) {
+       if ( value !== this.align ) {
+               // Default to 'left'
+               if ( [ 'left', 'right', 'top', 'inline' ].indexOf( value ) === -1 ) {
+                       value = 'left';
+               }
+               // Reorder elements
+               if ( value === 'inline' ) {
+                       this.$element.append( this.$field, this.$label, this.$help );
+               } else {
+                       this.$element.append( this.$help, this.$label, this.$field );
+               }
+               // Set classes
+               if ( this.align ) {
+                       this.$element.removeClass( 'oo-ui-fieldLayout-align-' + this.align );
+               }
+               this.align = value;
+               this.$element.addClass( 'oo-ui-fieldLayout-align-' + this.align );
+       }
+
+       return this;
+};
+
+/**
+ * Layout made of a fieldset and optional legend.
+ *
+ * Just add OO.ui.FieldLayout items.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ * @mixins OO.ui.LabeledElement
+ * @mixins OO.ui.IconedElement
+ * @mixins OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [icon] Symbolic icon name
+ * @cfg {OO.ui.FieldLayout[]} [items] Items to add
+ */
+OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
+       // Config initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.FieldsetLayout.super.call( this, config );
+
+       // Mixin constructors
+       OO.ui.IconedElement.call( this, this.$( '<div>' ), config );
+       OO.ui.LabeledElement.call( this, this.$( '<div>' ), config );
+       OO.ui.GroupElement.call( this, this.$( '<div>' ), config );
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-fieldsetLayout' )
+               .prepend( this.$icon, this.$label, this.$group );
+       if ( $.isArray( config.items ) ) {
+               this.addItems( config.items );
+       }
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.LabeledElement );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.GroupElement );
+
+/* Static Properties */
+
+OO.ui.FieldsetLayout.static.tagName = 'div';
+
+/**
+ * Layout with an HTML form.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.FormLayout = function OoUiFormLayout( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.FormLayout.super.call( this, config );
+
+       // Events
+       this.$element.on( 'submit', OO.ui.bind( this.onFormSubmit, this ) );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-formLayout' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.FormLayout, OO.ui.Layout );
+
+/* Events */
+
+/**
+ * @event submit
+ */
+
+/* Static Properties */
+
+OO.ui.FormLayout.static.tagName = 'form';
+
+/* Methods */
+
+/**
+ * Handle form submit events.
+ *
+ * @param {jQuery.Event} e Submit event
+ * @fires submit
+ */
+OO.ui.FormLayout.prototype.onFormSubmit = function () {
+       this.emit( 'submit' );
+       return false;
+};
+
+/**
+ * Layout made of proportionally sized columns and rows.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ *
+ * @constructor
+ * @param {OO.ui.PanelLayout[]} panels Panels in the grid
+ * @param {Object} [config] Configuration options
+ * @cfg {number[]} [widths] Widths of columns as ratios
+ * @cfg {number[]} [heights] Heights of columns as ratios
+ */
+OO.ui.GridLayout = function OoUiGridLayout( panels, config ) {
+       var i, len, widths;
+
+       // Config initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.GridLayout.super.call( this, config );
+
+       // Properties
+       this.panels = [];
+       this.widths = [];
+       this.heights = [];
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-gridLayout' );
+       for ( i = 0, len = panels.length; i < len; i++ ) {
+               this.panels.push( panels[i] );
+               this.$element.append( panels[i].$element );
+       }
+       if ( config.widths || config.heights ) {
+               this.layout( config.widths || [ 1 ], config.heights || [ 1 ] );
+       } else {
+               // Arrange in columns by default
+               widths = [];
+               for ( i = 0, len = this.panels.length; i < len; i++ ) {
+                       widths[i] = 1;
+               }
+               this.layout( widths, [ 1 ] );
+       }
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.GridLayout, OO.ui.Layout );
+
+/* Events */
+
+/**
+ * @event layout
+ */
+
+/**
+ * @event update
+ */
+
+/* Static Properties */
+
+OO.ui.GridLayout.static.tagName = 'div';
+
+/* Methods */
+
+/**
+ * Set grid dimensions.
+ *
+ * @param {number[]} widths Widths of columns as ratios
+ * @param {number[]} heights Heights of rows as ratios
+ * @fires layout
+ * @throws {Error} If grid is not large enough to fit all panels
+ */
+OO.ui.GridLayout.prototype.layout = function ( widths, heights ) {
+       var x, y,
+               xd = 0,
+               yd = 0,
+               cols = widths.length,
+               rows = heights.length;
+
+       // Verify grid is big enough to fit panels
+       if ( cols * rows < this.panels.length ) {
+               throw new Error( 'Grid is not large enough to fit ' + this.panels.length + 'panels' );
+       }
 
-       return this;
+       // Sum up denominators
+       for ( x = 0; x < cols; x++ ) {
+               xd += widths[x];
+       }
+       for ( y = 0; y < rows; y++ ) {
+               yd += heights[y];
+       }
+       // Store factors
+       this.widths = [];
+       this.heights = [];
+       for ( x = 0; x < cols; x++ ) {
+               this.widths[x] = widths[x] / xd;
+       }
+       for ( y = 0; y < rows; y++ ) {
+               this.heights[y] = heights[y] / yd;
+       }
+       // Synchronize view
+       this.update();
+       this.emit( 'layout' );
 };
 
 /**
- * Set the current page by name.
+ * Update panel positions and sizes.
  *
- * @fires set
- * @param {string} name Symbolic name of page
+ * @fires update
  */
-OO.ui.BookletLayout.prototype.setPage = function ( name ) {
-       var selectedItem,
-               page = this.pages[name];
+OO.ui.GridLayout.prototype.update = function () {
+       var x, y, panel,
+               i = 0,
+               left = 0,
+               top = 0,
+               dimensions,
+               width = 0,
+               height = 0,
+               cols = this.widths.length,
+               rows = this.heights.length;
 
-       if ( name !== this.currentPageName ) {
-               if ( this.outlined ) {
-                       selectedItem = this.outlineWidget.getSelectedItem();
-                       if ( selectedItem && selectedItem.getData() !== name ) {
-                               this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) );
-                       }
-               }
-               if ( page ) {
-                       if ( this.currentPageName && this.pages[this.currentPageName] ) {
-                               this.pages[this.currentPageName].setActive( false );
-                               // Blur anything focused if the next page doesn't have anything focusable - this
-                               // is not needed if the next page has something focusable because once it is focused
-                               // this blur happens automatically
-                               if ( this.autoFocus && !page.$element.find( ':input' ).length ) {
-                                       this.pages[this.currentPageName].$element.find( ':focus' ).blur();
-                               }
+       for ( y = 0; y < rows; y++ ) {
+               height = this.heights[y];
+               for ( x = 0; x < cols; x++ ) {
+                       panel = this.panels[i];
+                       width = this.widths[x];
+                       dimensions = {
+                               'width': Math.round( width * 100 ) + '%',
+                               'height': Math.round( height * 100 ) + '%',
+                               'top': Math.round( top * 100 ) + '%',
+                               // HACK: Work around IE bug by setting visibility: hidden; if width or height is zero
+                               'visibility': width === 0 || height === 0 ? 'hidden' : ''
+                       };
+                       // If RTL, reverse:
+                       if ( OO.ui.Element.getDir( this.$.context ) === 'rtl' ) {
+                               dimensions.right = Math.round( left * 100 ) + '%';
+                       } else {
+                               dimensions.left = Math.round( left * 100 ) + '%';
                        }
-                       this.currentPageName = name;
-                       this.stackLayout.setItem( page );
-                       page.setActive( true );
-                       this.emit( 'set', page );
+                       panel.$element.css( dimensions );
+                       i++;
+                       left += width;
                }
+               top += height;
+               left = 0;
        }
+
+       this.emit( 'update' );
 };
 
 /**
- * Call this after adding or removing items from the OutlineWidget.
+ * Get a panel at a given position.
  *
- * @chainable
+ * The x and y position is affected by the current grid layout.
+ *
+ * @param {number} x Horizontal position
+ * @param {number} y Vertical position
+ * @return {OO.ui.PanelLayout} The panel at the given postion
  */
-OO.ui.BookletLayout.prototype.updateOutlineWidget = function () {
-       // Auto-select first item when nothing is selected anymore
-       if ( !this.outlineWidget.getSelectedItem() ) {
-               this.outlineWidget.selectItem( this.outlineWidget.getFirstSelectableItem() );
-       }
-
-       return this;
+OO.ui.GridLayout.prototype.getPanel = function ( x, y ) {
+       return this.panels[( x * this.widths.length ) + y];
 };
 
 /**
@@ -4764,8 +6368,9 @@ OO.ui.BookletLayout.prototype.updateOutlineWidget = function () {
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {boolean} [scrollable] Allow vertical scrolling
- * @cfg {boolean} [padded] Pad the content from the edges
+ * @cfg {boolean} [scrollable=false] Allow vertical scrolling
+ * @cfg {boolean} [padded=false] Pad the content from the edges
+ * @cfg {boolean} [expanded=true] Expand size to fill the entire parent element
  */
 OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
        // Config initialization
@@ -4783,6 +6388,10 @@ OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
        if ( config.padded ) {
                this.$element.addClass( 'oo-ui-panelLayout-padded' );
        }
+
+       if ( config.expanded === undefined || config.expanded ) {
+               this.$element.addClass( 'oo-ui-panelLayout-expanded' );
+       }
 };
 
 /* Setup */
@@ -4857,13 +6466,33 @@ OO.ui.PageLayout.prototype.getOutlineItem = function () {
 };
 
 /**
- * Get outline item.
+ * Set outline item.
+ *
+ * @localdoc Subclasses should override #setupOutlineItem instead of this method to adjust the
+ *   outline item as desired; this method is called for setting (with an object) and unsetting
+ *   (with null) and overriding methods would have to check the value of `outlineItem` to avoid
+ *   operating on null instead of an OO.ui.OutlineItemWidget object.
  *
  * @param {OO.ui.OutlineItemWidget|null} outlineItem Outline item widget, null to clear
  * @chainable
  */
 OO.ui.PageLayout.prototype.setOutlineItem = function ( outlineItem ) {
-       this.outlineItem = outlineItem;
+       this.outlineItem = outlineItem || null;
+       if ( outlineItem ) {
+               this.setupOutlineItem();
+       }
+       return this;
+};
+
+/**
+ * Setup outline item.
+ *
+ * @localdoc Subclasses should override this method to adjust the outline item as desired.
+ *
+ * @param {OO.ui.OutlineItemWidget} outlineItem Outline item widget to setup
+ * @chainable
+ */
+OO.ui.PageLayout.prototype.setupOutlineItem = function () {
        return this;
 };
 
@@ -5166,388 +6795,724 @@ OO.ui.PopupToolGroup.prototype.setDisabled = function () {
        // Parent method
        OO.ui.PopupToolGroup.super.prototype.setDisabled.apply( this, arguments );
 
-       if ( this.isDisabled() && this.isElementAttached() ) {
-               this.setActive( false );
+       if ( this.isDisabled() && this.isElementAttached() ) {
+               this.setActive( false );
+       }
+};
+
+/**
+ * Handle focus being lost.
+ *
+ * The event is actually generated from a mouseup, so it is not a normal blur event object.
+ *
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
+       // Only deactivate when clicking outside the dropdown element
+       if ( this.$( e.target ).closest( '.oo-ui-popupToolGroup' )[0] !== this.$element[0] ) {
+               this.setActive( false );
+       }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.PopupToolGroup.prototype.onMouseUp = function ( e ) {
+       if ( !this.isDisabled() && e.which === 1 ) {
+               this.setActive( false );
+       }
+       return OO.ui.PopupToolGroup.super.prototype.onMouseUp.call( this, e );
+};
+
+/**
+ * Handle mouse up events.
+ *
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.PopupToolGroup.prototype.onHandleMouseUp = function () {
+       return false;
+};
+
+/**
+ * Handle mouse down events.
+ *
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.PopupToolGroup.prototype.onHandleMouseDown = function ( e ) {
+       if ( !this.isDisabled() && e.which === 1 ) {
+               this.setActive( !this.active );
+       }
+       return false;
+};
+
+/**
+ * Switch into active mode.
+ *
+ * When active, mouseup events anywhere in the document will trigger deactivation.
+ */
+OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
+       value = !!value;
+       if ( this.active !== value ) {
+               this.active = value;
+               if ( value ) {
+                       this.setClipping( true );
+                       this.$element.addClass( 'oo-ui-popupToolGroup-active' );
+                       this.getElementDocument().addEventListener( 'mouseup', this.onBlurHandler, true );
+               } else {
+                       this.setClipping( false );
+                       this.$element.removeClass( 'oo-ui-popupToolGroup-active' );
+                       this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
+               }
+       }
+};
+
+/**
+ * Drop down list layout of tools as labeled icon buttons.
+ *
+ * @class
+ * @extends OO.ui.PopupToolGroup
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
+       // Parent constructor
+       OO.ui.ListToolGroup.super.call( this, toolbar, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-listToolGroup' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );
+
+/* Static Properties */
+
+OO.ui.ListToolGroup.static.accelTooltips = true;
+
+OO.ui.ListToolGroup.static.name = 'list';
+
+/**
+ * Drop down menu layout of tools as selectable menu items.
+ *
+ * @class
+ * @extends OO.ui.PopupToolGroup
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.MenuToolGroup.super.call( this, toolbar, config );
+
+       // Events
+       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-menuToolGroup' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );
+
+/* Static Properties */
+
+OO.ui.MenuToolGroup.static.accelTooltips = true;
+
+OO.ui.MenuToolGroup.static.name = 'menu';
+
+/* Methods */
+
+/**
+ * Handle the toolbar state being updated.
+ *
+ * When the state changes, the title of each active item in the menu will be joined together and
+ * used as a label for the group. The label will be empty if none of the items are active.
+ */
+OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
+       var name,
+               labelTexts = [];
+
+       for ( name in this.tools ) {
+               if ( this.tools[name].isActive() ) {
+                       labelTexts.push( this.tools[name].getTitle() );
+               }
        }
+
+       this.setLabel( labelTexts.join( ', ' ) || ' ' );
 };
 
 /**
- * Handle focus being lost.
+ * Tool that shows a popup when selected.
  *
- * The event is actually generated from a mouseup, so it is not a normal blur event object.
+ * @abstract
+ * @class
+ * @extends OO.ui.Tool
+ * @mixins OO.ui.PopuppableElement
  *
- * @param {jQuery.Event} e Mouse up event
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
  */
-OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
-       // Only deactivate when clicking outside the dropdown element
-       if ( this.$( e.target ).closest( '.oo-ui-popupToolGroup' )[0] !== this.$element[0] ) {
-               this.setActive( false );
-       }
+OO.ui.PopupTool = function OoUiPopupTool( toolbar, config ) {
+       // Parent constructor
+       OO.ui.PopupTool.super.call( this, toolbar, config );
+
+       // Mixin constructors
+       OO.ui.PopuppableElement.call( this, config );
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-popupTool' )
+               .append( this.popup.$element );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );
+OO.mixinClass( OO.ui.PopupTool, OO.ui.PopuppableElement );
+
+/* Methods */
+
 /**
+ * Handle the tool being selected.
+ *
  * @inheritdoc
  */
-OO.ui.PopupToolGroup.prototype.onMouseUp = function ( e ) {
-       if ( !this.isDisabled() && e.which === 1 ) {
-               this.setActive( false );
+OO.ui.PopupTool.prototype.onSelect = function () {
+       if ( !this.isDisabled() ) {
+               this.popup.toggle();
        }
-       return OO.ui.PopupToolGroup.super.prototype.onMouseUp.call( this, e );
+       this.setActive( false );
+       return false;
 };
 
 /**
- * Handle mouse up events.
+ * Handle the toolbar state being updated.
  *
- * @param {jQuery.Event} e Mouse up event
+ * @inheritdoc
  */
-OO.ui.PopupToolGroup.prototype.onHandleMouseUp = function () {
-       return false;
+OO.ui.PopupTool.prototype.onUpdateState = function () {
+       this.setActive( false );
 };
 
 /**
- * Handle mouse down events.
+ * Mixin for OO.ui.Widget subclasses to provide OO.ui.GroupElement.
  *
- * @param {jQuery.Event} e Mouse down event
+ * Use together with OO.ui.ItemWidget to make disabled state inheritable.
+ *
+ * @abstract
+ * @class
+ * @extends OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {jQuery} $group Container node, assigned to #$group
+ * @param {Object} [config] Configuration options
  */
-OO.ui.PopupToolGroup.prototype.onHandleMouseDown = function ( e ) {
-       if ( !this.isDisabled() && e.which === 1 ) {
-               this.setActive( !this.active );
-       }
-       return false;
+OO.ui.GroupWidget = function OoUiGroupWidget( $element, config ) {
+       // Parent constructor
+       OO.ui.GroupWidget.super.call( this, $element, config );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.GroupWidget, OO.ui.GroupElement );
+
+/* Methods */
+
 /**
- * Switch into active mode.
+ * Set the disabled state of the widget.
  *
- * When active, mouseup events anywhere in the document will trigger deactivation.
+ * This will also update the disabled state of child widgets.
+ *
+ * @param {boolean} disabled Disable widget
+ * @chainable
  */
-OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
-       value = !!value;
-       if ( this.active !== value ) {
-               this.active = value;
-               if ( value ) {
-                       this.setClipping( true );
-                       this.$element.addClass( 'oo-ui-popupToolGroup-active' );
-                       this.getElementDocument().addEventListener( 'mouseup', this.onBlurHandler, true );
-               } else {
-                       this.setClipping( false );
-                       this.$element.removeClass( 'oo-ui-popupToolGroup-active' );
-                       this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
+OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
+       var i, len;
+
+       // Parent method
+       // Note: Calling #setDisabled this way assumes this is mixed into an OO.ui.Widget
+       OO.ui.Widget.prototype.setDisabled.call( this, disabled );
+
+       // During construction, #setDisabled is called before the OO.ui.GroupElement constructor
+       if ( this.items ) {
+               for ( i = 0, len = this.items.length; i < len; i++ ) {
+                       this.items[i].updateDisabled();
                }
        }
+
+       return this;
 };
 
 /**
- * Drop down list layout of tools as labeled icon buttons.
+ * Mixin for widgets used as items in widgets that inherit OO.ui.GroupWidget.
  *
+ * Item widgets have a reference to a OO.ui.GroupWidget while they are attached to the group. This
+ * allows bidrectional communication.
+ *
+ * Use together with OO.ui.GroupWidget to make disabled state inheritable.
+ *
+ * @abstract
  * @class
- * @extends OO.ui.PopupToolGroup
  *
  * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
  */
-OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
-       // Parent constructor
-       OO.ui.ListToolGroup.super.call( this, toolbar, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-listToolGroup' );
+OO.ui.ItemWidget = function OoUiItemWidget() {
+       //
 };
 
-/* Setup */
+/* Methods */
 
-OO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );
+/**
+ * Check if widget is disabled.
+ *
+ * Checks parent if present, making disabled state inheritable.
+ *
+ * @return {boolean} Widget is disabled
+ */
+OO.ui.ItemWidget.prototype.isDisabled = function () {
+       return this.disabled ||
+               ( this.elementGroup instanceof OO.ui.Widget && this.elementGroup.isDisabled() );
+};
 
-/* Static Properties */
+/**
+ * Set group element is in.
+ *
+ * @param {OO.ui.GroupElement|null} group Group element, null if none
+ * @chainable
+ */
+OO.ui.ItemWidget.prototype.setElementGroup = function ( group ) {
+       // Parent method
+       // Note: Calling #setElementGroup this way assumes this is mixed into an OO.ui.Element
+       OO.ui.Element.prototype.setElementGroup.call( this, group );
 
-OO.ui.ListToolGroup.static.accelTooltips = true;
+       // Initialize item disabled states
+       this.updateDisabled();
 
-OO.ui.ListToolGroup.static.name = 'list';
+       return this;
+};
 
 /**
- * Drop down menu layout of tools as selectable menu items.
+ * Mixin that adds a menu showing suggested values for a text input.
+ *
+ * Subclasses must handle `select` and `choose` events on #lookupMenu to make use of selections.
  *
  * @class
- * @extends OO.ui.PopupToolGroup
+ * @abstract
  *
  * @constructor
- * @param {OO.ui.Toolbar} toolbar
+ * @param {OO.ui.TextInputWidget} input Input widget
  * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$overlay=this.$( 'body' )] Overlay layer
  */
-OO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {
-       // Configuration initialization
+OO.ui.LookupInputWidget = function OoUiLookupInputWidget( input, config ) {
+       // Config intialization
        config = config || {};
 
-       // Parent constructor
-       OO.ui.MenuToolGroup.super.call( this, toolbar, config );
+       // Properties
+       this.lookupInput = input;
+       this.$overlay = config.$overlay || this.$( 'body,.oo-ui-window-overlay' ).last();
+       this.lookupMenu = new OO.ui.TextInputMenuWidget( this, {
+               '$': OO.ui.Element.getJQuery( this.$overlay ),
+               'input': this.lookupInput,
+               '$container': config.$container
+       } );
+       this.lookupCache = {};
+       this.lookupQuery = null;
+       this.lookupRequest = null;
+       this.populating = false;
 
        // Events
-       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
+       this.$overlay.append( this.lookupMenu.$element );
+
+       this.lookupInput.$input.on( {
+               'focus': OO.ui.bind( this.onLookupInputFocus, this ),
+               'blur': OO.ui.bind( this.onLookupInputBlur, this ),
+               'mousedown': OO.ui.bind( this.onLookupInputMouseDown, this )
+       } );
+       this.lookupInput.connect( this, { 'change': 'onLookupInputChange' } );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-menuToolGroup' );
+       this.$element.addClass( 'oo-ui-lookupWidget' );
+       this.lookupMenu.$element.addClass( 'oo-ui-lookupWidget-menu' );
 };
 
-/* Setup */
+/* Methods */
 
-OO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );
+/**
+ * Handle input focus event.
+ *
+ * @param {jQuery.Event} e Input focus event
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputFocus = function () {
+       this.openLookupMenu();
+};
 
-/* Static Properties */
+/**
+ * Handle input blur event.
+ *
+ * @param {jQuery.Event} e Input blur event
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputBlur = function () {
+       this.lookupMenu.toggle( false );
+};
 
-OO.ui.MenuToolGroup.static.accelTooltips = true;
+/**
+ * Handle input mouse down event.
+ *
+ * @param {jQuery.Event} e Input mouse down event
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputMouseDown = function () {
+       this.openLookupMenu();
+};
+
+/**
+ * Handle input change event.
+ *
+ * @param {string} value New input value
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputChange = function () {
+       this.openLookupMenu();
+};
+
+/**
+ * Get lookup menu.
+ *
+ * @return {OO.ui.TextInputMenuWidget}
+ */
+OO.ui.LookupInputWidget.prototype.getLookupMenu = function () {
+       return this.lookupMenu;
+};
+
+/**
+ * Open the menu.
+ *
+ * @chainable
+ */
+OO.ui.LookupInputWidget.prototype.openLookupMenu = function () {
+       var value = this.lookupInput.getValue();
 
-OO.ui.MenuToolGroup.static.name = 'menu';
+       if ( this.lookupMenu.$input.is( ':focus' ) && $.trim( value ) !== '' ) {
+               this.populateLookupMenu();
+               this.lookupMenu.toggle( true );
+       } else {
+               this.lookupMenu
+                       .clearItems()
+                       .toggle( false );
+       }
 
-/* Methods */
+       return this;
+};
 
 /**
- * Handle the toolbar state being updated.
+ * Populate lookup menu with current information.
  *
- * When the state changes, the title of each active item in the menu will be joined together and
- * used as a label for the group. The label will be empty if none of the items are active.
+ * @chainable
  */
-OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
-       var name,
-               labelTexts = [];
+OO.ui.LookupInputWidget.prototype.populateLookupMenu = function () {
+       var widget = this;
 
-       for ( name in this.tools ) {
-               if ( this.tools[name].isActive() ) {
-                       labelTexts.push( this.tools[name].getTitle() );
-               }
+       if ( !this.populating ) {
+               this.populating = true;
+               this.getLookupMenuItems()
+                       .done( function ( items ) {
+                               widget.lookupMenu.clearItems();
+                               if ( items.length ) {
+                                       widget.lookupMenu
+                                               .addItems( items )
+                                               .toggle( true );
+                                       widget.initializeLookupMenuSelection();
+                                       widget.openLookupMenu();
+                               } else {
+                                       widget.lookupMenu.toggle( true );
+                               }
+                               widget.populating = false;
+                       } )
+                       .fail( function () {
+                               widget.lookupMenu.clearItems();
+                               widget.populating = false;
+                       } );
        }
 
-       this.setLabel( labelTexts.join( ', ' ) || ' ' );
+       return this;
 };
 
 /**
- * Tool that shows a popup when selected.
- *
- * @abstract
- * @class
- * @extends OO.ui.Tool
- * @mixins OO.ui.PopuppableElement
+ * Set selection in the lookup menu with current information.
  *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
+ * @chainable
  */
-OO.ui.PopupTool = function OoUiPopupTool( toolbar, config ) {
-       // Parent constructor
-       OO.ui.PopupTool.super.call( this, toolbar, config );
-
-       // Mixin constructors
-       OO.ui.PopuppableElement.call( this, config );
-
-       // Initialization
-       this.$element
-               .addClass( 'oo-ui-popupTool' )
-               .append( this.popup.$element );
+OO.ui.LookupInputWidget.prototype.initializeLookupMenuSelection = function () {
+       if ( !this.lookupMenu.getSelectedItem() ) {
+               this.lookupMenu.selectItem( this.lookupMenu.getFirstSelectableItem() );
+       }
+       this.lookupMenu.highlightItem( this.lookupMenu.getSelectedItem() );
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );
-OO.mixinClass( OO.ui.PopupTool, OO.ui.PopuppableElement );
-
-/* Methods */
-
 /**
- * Handle the tool being selected.
+ * Get lookup menu items for the current query.
  *
- * @inheritdoc
+ * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument
+ * of the done event
  */
-OO.ui.PopupTool.prototype.onSelect = function () {
-       if ( !this.isDisabled() ) {
-               if ( this.popup.isVisible() ) {
-                       this.hidePopup();
+OO.ui.LookupInputWidget.prototype.getLookupMenuItems = function () {
+       var widget = this,
+               value = this.lookupInput.getValue(),
+               deferred = $.Deferred();
+
+       if ( value && value !== this.lookupQuery ) {
+               // Abort current request if query has changed
+               if ( this.lookupRequest ) {
+                       this.lookupRequest.abort();
+                       this.lookupQuery = null;
+                       this.lookupRequest = null;
+               }
+               if ( value in this.lookupCache ) {
+                       deferred.resolve( this.getLookupMenuItemsFromData( this.lookupCache[value] ) );
                } else {
-                       this.showPopup();
+                       this.lookupQuery = value;
+                       this.lookupRequest = this.getLookupRequest()
+                               .always( function () {
+                                       widget.lookupQuery = null;
+                                       widget.lookupRequest = null;
+                               } )
+                               .done( function ( data ) {
+                                       widget.lookupCache[value] = widget.getLookupCacheItemFromData( data );
+                                       deferred.resolve( widget.getLookupMenuItemsFromData( widget.lookupCache[value] ) );
+                               } )
+                               .fail( function () {
+                                       deferred.reject();
+                               } );
+                       this.pushPending();
+                       this.lookupRequest.always( function () {
+                               widget.popPending();
+                       } );
                }
        }
-       this.setActive( false );
-       return false;
+       return deferred.promise();
 };
 
 /**
- * Handle the toolbar state being updated.
+ * Get a new request object of the current lookup query value.
  *
- * @inheritdoc
+ * @abstract
+ * @return {jqXHR} jQuery AJAX object, or promise object with an .abort() method
  */
-OO.ui.PopupTool.prototype.onUpdateState = function () {
-       this.setActive( false );
+OO.ui.LookupInputWidget.prototype.getLookupRequest = function () {
+       // Stub, implemented in subclass
+       return null;
 };
 
 /**
- * Group widget.
- *
- * Mixin for OO.ui.Widget subclasses.
+ * Handle successful lookup request.
  *
- * Use together with OO.ui.ItemWidget to make disabled state inheritable.
+ * Overriding methods should call #populateLookupMenu when results are available and cache results
+ * for future lookups in #lookupCache as an array of #OO.ui.MenuItemWidget objects.
  *
  * @abstract
- * @class
- * @extends OO.ui.GroupElement
- *
- * @constructor
- * @param {jQuery} $group Container node, assigned to #$group
- * @param {Object} [config] Configuration options
+ * @param {Mixed} data Response from server
  */
-OO.ui.GroupWidget = function OoUiGroupWidget( $element, config ) {
-       // Parent constructor
-       OO.ui.GroupWidget.super.call( this, $element, config );
+OO.ui.LookupInputWidget.prototype.onLookupRequestDone = function () {
+       // Stub, implemented in subclass
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.GroupWidget, OO.ui.GroupElement );
-
-/* Methods */
-
 /**
- * Set the disabled state of the widget.
- *
- * This will also update the disabled state of child widgets.
+ * Get a list of menu item widgets from the data stored by the lookup request's done handler.
  *
- * @param {boolean} disabled Disable widget
- * @chainable
+ * @abstract
+ * @param {Mixed} data Cached result data, usually an array
+ * @return {OO.ui.MenuItemWidget[]} Menu items
  */
-OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
-       var i, len;
-
-       // Parent method
-       // Note: Calling #setDisabled this way assumes this is mixed into an OO.ui.Widget
-       OO.ui.Widget.prototype.setDisabled.call( this, disabled );
-
-       // During construction, #setDisabled is called before the OO.ui.GroupElement constructor
-       if ( this.items ) {
-               for ( i = 0, len = this.items.length; i < len; i++ ) {
-                       this.items[i].updateDisabled();
-               }
-       }
-
-       return this;
+OO.ui.LookupInputWidget.prototype.getLookupMenuItemsFromData = function () {
+       // Stub, implemented in subclass
+       return [];
 };
 
 /**
- * Item widget.
+ * Set of controls for an OO.ui.OutlineWidget.
  *
- * Use together with OO.ui.GroupWidget to make disabled state inheritable.
+ * Controls include moving items up and down, removing items, and adding different kinds of items.
  *
- * @abstract
  * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.IconedElement
  *
  * @constructor
+ * @param {OO.ui.OutlineWidget} outline Outline to control
+ * @param {Object} [config] Configuration options
  */
-OO.ui.ItemWidget = function OoUiItemWidget() {
-       //
+OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {
+       // Configuration initialization
+       config = $.extend( { 'icon': 'add-item' }, config );
+
+       // Parent constructor
+       OO.ui.OutlineControlsWidget.super.call( this, config );
+
+       // Mixin constructors
+       OO.ui.GroupElement.call( this, this.$( '<div>' ), config );
+       OO.ui.IconedElement.call( this, this.$( '<div>' ), config );
+
+       // Properties
+       this.outline = outline;
+       this.$movers = this.$( '<div>' );
+       this.upButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'framed': false,
+               'icon': 'collapse',
+               'title': OO.ui.msg( 'ooui-outline-control-move-up' )
+       } );
+       this.downButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'framed': false,
+               'icon': 'expand',
+               'title': OO.ui.msg( 'ooui-outline-control-move-down' )
+       } );
+       this.removeButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'framed': false,
+               'icon': 'remove',
+               'title': OO.ui.msg( 'ooui-outline-control-remove' )
+       } );
+
+       // Events
+       outline.connect( this, {
+               'select': 'onOutlineChange',
+               'add': 'onOutlineChange',
+               'remove': 'onOutlineChange'
+       } );
+       this.upButton.connect( this, { 'click': [ 'emit', 'move', -1 ] } );
+       this.downButton.connect( this, { 'click': [ 'emit', 'move', 1 ] } );
+       this.removeButton.connect( this, { 'click': [ 'emit', 'remove' ] } );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-outlineControlsWidget' );
+       this.$group.addClass( 'oo-ui-outlineControlsWidget-items' );
+       this.$movers
+               .addClass( 'oo-ui-outlineControlsWidget-movers' )
+               .append( this.removeButton.$element, this.upButton.$element, this.downButton.$element );
+       this.$element.append( this.$icon, this.$group, this.$movers );
 };
 
-/* Methods */
+/* Setup */
+
+OO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.IconedElement );
+
+/* Events */
 
 /**
- * Check if widget is disabled.
- *
- * Checks parent if present, making disabled state inheritable.
- *
- * @return {boolean} Widget is disabled
+ * @event move
+ * @param {number} places Number of places to move
  */
-OO.ui.ItemWidget.prototype.isDisabled = function () {
-       return this.disabled ||
-               ( this.elementGroup instanceof OO.ui.Widget && this.elementGroup.isDisabled() );
-};
 
 /**
- * Set group element is in.
- *
- * @param {OO.ui.GroupElement|null} group Group element, null if none
- * @chainable
+ * @event remove
  */
-OO.ui.ItemWidget.prototype.setElementGroup = function ( group ) {
-       // Parent method
-       // Note: Calling #setElementGroup this way assumes this is mixed into an OO.ui.Element
-       OO.ui.Element.prototype.setElementGroup.call( this, group );
 
-       // Initialize item disabled states
-       this.updateDisabled();
+/* Methods */
 
-       return this;
+/**
+ * Handle outline change events.
+ */
+OO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {
+       var i, len, firstMovable, lastMovable,
+               items = this.outline.getItems(),
+               selectedItem = this.outline.getSelectedItem(),
+               movable = selectedItem && selectedItem.isMovable(),
+               removable = selectedItem && selectedItem.isRemovable();
+
+       if ( movable ) {
+               i = -1;
+               len = items.length;
+               while ( ++i < len ) {
+                       if ( items[i].isMovable() ) {
+                               firstMovable = items[i];
+                               break;
+                       }
+               }
+               i = len;
+               while ( i-- ) {
+                       if ( items[i].isMovable() ) {
+                               lastMovable = items[i];
+                               break;
+                       }
+               }
+       }
+       this.upButton.setDisabled( !movable || selectedItem === firstMovable );
+       this.downButton.setDisabled( !movable || selectedItem === lastMovable );
+       this.removeButton.setDisabled( !removable );
 };
 
 /**
- * Icon widget.
+ * Mixin for widgets with a boolean on/off state.
  *
+ * @abstract
  * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconedElement
- * @mixins OO.ui.TitledElement
  *
  * @constructor
  * @param {Object} [config] Configuration options
+ * @cfg {boolean} [value=false] Initial value
  */
-OO.ui.IconWidget = function OoUiIconWidget( config ) {
-       // Config intialization
+OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
+       // Configuration initialization
        config = config || {};
 
-       // Parent constructor
-       OO.ui.IconWidget.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.IconedElement.call( this, this.$element, config );
-       OO.ui.TitledElement.call( this, this.$element, config );
+       // Properties
+       this.value = null;
 
        // Initialization
-       this.$element.addClass( 'oo-ui-iconWidget' );
+       this.$element.addClass( 'oo-ui-toggleWidget' );
+       this.setValue( !!config.value );
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.IconWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.IconWidget, OO.ui.IconedElement );
-OO.mixinClass( OO.ui.IconWidget, OO.ui.TitledElement );
+/* Events */
 
-/* Static Properties */
+/**
+ * @event change
+ * @param {boolean} value Changed value
+ */
 
-OO.ui.IconWidget.static.tagName = 'span';
+/* Methods */
 
 /**
- * Indicator widget.
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IndicatedElement
- * @mixins OO.ui.TitledElement
+ * Get the value of the toggle.
  *
- * @constructor
- * @param {Object} [config] Configuration options
+ * @return {boolean}
  */
-OO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.IndicatorWidget.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.IndicatedElement.call( this, this.$element, config );
-       OO.ui.TitledElement.call( this, this.$element, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-indicatorWidget' );
+OO.ui.ToggleWidget.prototype.getValue = function () {
+       return this.value;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.IndicatorWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.IndicatedElement );
-OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.TitledElement );
-
-/* Static Properties */
-
-OO.ui.IndicatorWidget.static.tagName = 'span';
+/**
+ * Set the value of the toggle.
+ *
+ * @param {boolean} value New value
+ * @fires change
+ * @chainable
+ */
+OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
+       value = !!value;
+       if ( this.value !== value ) {
+               this.value = value;
+               this.emit( 'change', value );
+               this.$element.toggleClass( 'oo-ui-toggleWidget-on', value );
+               this.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );
+       }
+       return this;
+};
 
 /**
- * Container for multiple related buttons.
+ * Group widget for multiple related buttons.
  *
  * Use together with OO.ui.ButtonWidget.
  *
@@ -5579,7 +7544,7 @@ OO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );
 OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
 
 /**
- * Button widget.
+ * Generic widget for buttons.
  *
  * @class
  * @extends OO.ui.Widget
@@ -5592,7 +7557,6 @@ OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {string} [title=''] Title text
  * @cfg {string} [href] Hyperlink to visit when clicked
  * @cfg {string} [target] Target to open hyperlink in
  */
@@ -5612,7 +7576,9 @@ OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
        OO.ui.FlaggableElement.call( this, config );
 
        // Properties
-       this.isHyperlink = typeof config.href === 'string';
+       this.href = null;
+       this.target = null;
+       this.isHyperlink = false;
 
        // Events
        this.$button.on( {
@@ -5621,12 +7587,12 @@ OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
        } );
 
        // Initialization
-       this.$button
-               .append( this.$icon, this.$label, this.$indicator )
-               .attr( { 'href': config.href, 'target': config.target } );
+       this.$button.append( this.$icon, this.$label, this.$indicator );
        this.$element
                .addClass( 'oo-ui-buttonWidget' )
                .append( this.$button );
+       this.setHref( config.href );
+       this.setTarget( config.target );
 };
 
 /* Setup */
@@ -5646,2754 +7612,2779 @@ OO.mixinClass( OO.ui.ButtonWidget, OO.ui.FlaggableElement );
  */
 
 /* Methods */
-
-/**
- * Handles mouse click events.
- *
- * @param {jQuery.Event} e Mouse click event
- * @fires click
- */
-OO.ui.ButtonWidget.prototype.onClick = function () {
-       if ( !this.isDisabled() ) {
-               this.emit( 'click' );
-               if ( this.isHyperlink ) {
-                       return true;
-               }
-       }
-       return false;
-};
-
-/**
- * Handles keypress events.
- *
- * @param {jQuery.Event} e Keypress event
- * @fires click
- */
-OO.ui.ButtonWidget.prototype.onKeyPress = function ( e ) {
-       if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
-               this.onClick();
-               if ( this.isHyperlink ) {
-                       return true;
-               }
-       }
-       return false;
-};
-
-/**
- * Input widget.
- *
- * @abstract
- * @class
- * @extends OO.ui.Widget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [name=''] HTML input name
- * @cfg {string} [value=''] Input value
- * @cfg {boolean} [readOnly=false] Prevent changes
- * @cfg {Function} [inputFilter] Filter function to apply to the input. Takes a string argument and returns a string.
- */
-OO.ui.InputWidget = function OoUiInputWidget( config ) {
-       // Config intialization
-       config = $.extend( { 'readOnly': false }, config );
-
-       // Parent constructor
-       OO.ui.InputWidget.super.call( this, config );
-
-       // Properties
-       this.$input = this.getInputElement( config );
-       this.value = '';
-       this.readOnly = false;
-       this.inputFilter = config.inputFilter;
-
-       // Events
-       this.$input.on( 'keydown mouseup cut paste change input select', OO.ui.bind( this.onEdit, this ) );
-
-       // Initialization
-       this.$input
-               .attr( 'name', config.name )
-               .prop( 'disabled', this.isDisabled() );
-       this.setReadOnly( config.readOnly );
-       this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input );
-       this.setValue( config.value );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
-
-/* Events */
-
-/**
- * @event change
- * @param value
- */
-
-/* Methods */
-
-/**
- * Get input element.
- *
- * @param {Object} [config] Configuration options
- * @return {jQuery} Input element
- */
-OO.ui.InputWidget.prototype.getInputElement = function () {
-       return this.$( '<input>' );
-};
-
-/**
- * Handle potentially value-changing events.
- *
- * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event
- */
-OO.ui.InputWidget.prototype.onEdit = function () {
-       if ( !this.isDisabled() ) {
-               // Allow the stack to clear so the value will be updated
-               setTimeout( OO.ui.bind( function () {
-                       this.setValue( this.$input.val() );
-               }, this ) );
-       }
-};
-
-/**
- * Get the value of the input.
- *
- * @return {string} Input value
- */
-OO.ui.InputWidget.prototype.getValue = function () {
-       return this.value;
-};
-
-/**
- * Sets the direction of the current input, either RTL or LTR
- *
- * @param {boolean} isRTL
- */
-OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) {
-       if ( isRTL ) {
-               this.$input.removeClass( 'oo-ui-ltr' );
-               this.$input.addClass( 'oo-ui-rtl' );
-       } else {
-               this.$input.removeClass( 'oo-ui-rtl' );
-               this.$input.addClass( 'oo-ui-ltr' );
-       }
-};
-
-/**
- * Set the value of the input.
- *
- * @param {string} value New value
- * @fires change
- * @chainable
- */
-OO.ui.InputWidget.prototype.setValue = function ( value ) {
-       value = this.sanitizeValue( value );
-       if ( this.value !== value ) {
-               this.value = value;
-               this.emit( 'change', this.value );
-       }
-       // Update the DOM if it has changed. Note that with sanitizeValue, it
-       // is possible for the DOM value to change without this.value changing.
-       if ( this.$input.val() !== this.value ) {
-               this.$input.val( this.value );
-       }
-       return this;
-};
-
-/**
- * Sanitize incoming value.
- *
- * Ensures value is a string, and converts undefined and null to empty strings.
+
+/**
+ * Handles mouse click events.
  *
- * @param {string} value Original value
- * @return {string} Sanitized value
+ * @param {jQuery.Event} e Mouse click event
+ * @fires click
  */
-OO.ui.InputWidget.prototype.sanitizeValue = function ( value ) {
-       if ( value === undefined || value === null ) {
-               return '';
-       } else if ( this.inputFilter ) {
-               return this.inputFilter( String( value ) );
-       } else {
-               return String( value );
+OO.ui.ButtonWidget.prototype.onClick = function () {
+       if ( !this.isDisabled() ) {
+               this.emit( 'click' );
+               if ( this.isHyperlink ) {
+                       return true;
+               }
        }
+       return false;
 };
 
 /**
- * Simulate the behavior of clicking on a label bound to this input.
+ * Handles keypress events.
+ *
+ * @param {jQuery.Event} e Keypress event
+ * @fires click
  */
-OO.ui.InputWidget.prototype.simulateLabelClick = function () {
-       if ( !this.isDisabled() ) {
-               if ( this.$input.is( ':checkbox,:radio' ) ) {
-                       this.$input.click();
-               } else if ( this.$input.is( ':input' ) ) {
-                       this.$input.focus();
+OO.ui.ButtonWidget.prototype.onKeyPress = function ( e ) {
+       if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
+               this.onClick();
+               if ( this.isHyperlink ) {
+                       return true;
                }
        }
+       return false;
 };
 
 /**
- * Check if the widget is read-only.
+ * Get hyperlink location.
  *
- * @return {boolean}
+ * @return {string} Hyperlink location
  */
-OO.ui.InputWidget.prototype.isReadOnly = function () {
-       return this.readOnly;
+OO.ui.ButtonWidget.prototype.getHref = function () {
+       return this.href;
 };
 
 /**
- * Set the read-only state of the widget.
- *
- * This should probably change the widgets's appearance and prevent it from being used.
+ * Get hyperlink target.
  *
- * @param {boolean} state Make input read-only
- * @chainable
+ * @return {string} Hyperlink target
  */
-OO.ui.InputWidget.prototype.setReadOnly = function ( state ) {
-       this.readOnly = !!state;
-       this.$input.prop( 'readOnly', this.readOnly );
-       return this;
+OO.ui.ButtonWidget.prototype.getTarget = function () {
+       return this.target;
 };
 
 /**
- * @inheritdoc
+ * Set hyperlink location.
+ *
+ * @param {string|null} href Hyperlink location, null to remove
  */
-OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
-       OO.ui.InputWidget.super.prototype.setDisabled.call( this, state );
-       if ( this.$input ) {
-               this.$input.prop( 'disabled', this.isDisabled() );
+OO.ui.ButtonWidget.prototype.setHref = function ( href ) {
+       href = typeof href === 'string' ? href : null;
+
+       if ( href !== this.href ) {
+               this.href = href;
+               if ( href !== null ) {
+                       this.$button.attr( 'href', href );
+                       this.isHyperlink = true;
+               } else {
+                       this.$button.removeAttr( 'href' );
+                       this.isHyperlink = false;
+               }
        }
+
        return this;
 };
 
 /**
- * Focus the input.
+ * Set hyperlink target.
  *
- * @chainable
+ * @param {string|null} target Hyperlink target, null to remove
  */
-OO.ui.InputWidget.prototype.focus = function () {
-       this.$input.focus();
+OO.ui.ButtonWidget.prototype.setTarget = function ( target ) {
+       target = typeof target === 'string' ? target : null;
+
+       if ( target !== this.target ) {
+               this.target = target;
+               if ( target !== null ) {
+                       this.$button.attr( 'target', target );
+               } else {
+                       this.$button.removeAttr( 'target' );
+               }
+       }
+
        return this;
 };
 
 /**
- * Checkbox widget.
+ * Button widget that executes an action and is managed by an OO.ui.ActionSet.
  *
  * @class
- * @extends OO.ui.InputWidget
+ * @extends OO.ui.ButtonWidget
  *
  * @constructor
  * @param {Object} [config] Configuration options
+ * @cfg {string} [action] Symbolic action name
+ * @cfg {string[]} [modes] Symbolic mode names
  */
-OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
+OO.ui.ActionWidget = function OoUiActionWidget( config ) {
+       // Config intialization
+       config = $.extend( { 'framed': false }, config );
+
        // Parent constructor
-       OO.ui.CheckboxInputWidget.super.call( this, config );
+       OO.ui.ActionWidget.super.call( this, config );
+
+       // Properties
+       this.action = config.action || '';
+       this.modes = config.modes || [];
+       this.width = 0;
+       this.height = 0;
 
        // Initialization
-       this.$element.addClass( 'oo-ui-checkboxInputWidget' );
+       this.$element.addClass( 'oo-ui-actionWidget' );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
+OO.inheritClass( OO.ui.ActionWidget, OO.ui.ButtonWidget );
 
 /* Events */
 
-/* Methods */
-
 /**
- * Get input element.
- *
- * @return {jQuery} Input element
+ * @event resize
  */
-OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
-       return this.$( '<input type="checkbox" />' );
-};
+
+/* Methods */
 
 /**
- * Get checked state of the checkbox
+ * Check if action is available in a certain mode.
  *
- * @return {boolean} If the checkbox is checked
+ * @param {string} mode Name of mode
+ * @return {boolean} Has mode
  */
-OO.ui.CheckboxInputWidget.prototype.getValue = function () {
-       return this.value;
+OO.ui.ActionWidget.prototype.hasMode = function ( mode ) {
+       return this.modes.indexOf( mode ) !== -1;
 };
 
 /**
- * Set value
+ * Get symbolic action name.
+ *
+ * @return {string}
  */
-OO.ui.CheckboxInputWidget.prototype.setValue = function ( value ) {
-       value = !!value;
-       if ( this.value !== value ) {
-               this.value = value;
-               this.$input.prop( 'checked', this.value );
-               this.emit( 'change', this.value );
-       }
+OO.ui.ActionWidget.prototype.getAction = function () {
+       return this.action;
 };
 
 /**
- * @inheritdoc
+ * Get symbolic action name.
+ *
+ * @return {string}
  */
-OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
-       if ( !this.isDisabled() ) {
-               // Allow the stack to clear so the value will be updated
-               setTimeout( OO.ui.bind( function () {
-                       this.setValue( this.$input.prop( 'checked' ) );
-               }, this ) );
-       }
+OO.ui.ActionWidget.prototype.getModes = function () {
+       return this.modes.slice();
 };
 
 /**
- * Label widget.
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.LabeledElement
+ * Emit a resize event if the size has changed.
  *
- * @constructor
- * @param {Object} [config] Configuration options
+ * @chainable
  */
-OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.LabelWidget.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.LabeledElement.call( this, this.$element, config );
+OO.ui.ActionWidget.prototype.propagateResize = function () {
+       var width, height;
 
-       // Properties
-       this.input = config.input;
+       if ( this.isElementAttached() ) {
+               width = this.$element.width();
+               height = this.$element.height();
 
-       // Events
-       if ( this.input instanceof OO.ui.InputWidget ) {
-               this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
+               if ( width !== this.width || height !== this.height ) {
+                       this.width = width;
+                       this.height = height;
+                       this.emit( 'resize' );
+               }
        }
 
-       // Initialization
-       this.$element.addClass( 'oo-ui-labelWidget' );
+       return this;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.LabelWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.LabelWidget, OO.ui.LabeledElement );
-
-/* Static Properties */
-
-OO.ui.LabelWidget.static.tagName = 'label';
-
-/* Methods */
-
 /**
- * Handles label mouse click events.
- *
- * @param {jQuery.Event} e Mouse click event
+ * @inheritdoc
  */
-OO.ui.LabelWidget.prototype.onClick = function () {
-       this.input.simulateLabelClick();
-       return false;
+OO.ui.ActionWidget.prototype.setIcon = function () {
+       // Mixin method
+       OO.ui.IconedElement.prototype.setIcon.apply( this, arguments );
+       this.propagateResize();
+
+       return this;
 };
 
 /**
- * Lookup input widget.
- *
- * Mixin that adds a menu showing suggested values to a text input. Subclasses must handle `select`
- * and `choose` events on #lookupMenu to make use of selections.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {OO.ui.TextInputWidget} input Input widget
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$overlay=this.$( 'body' )] Overlay layer
+ * @inheritdoc
  */
-OO.ui.LookupInputWidget = function OoUiLookupInputWidget( input, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Properties
-       this.lookupInput = input;
-       this.$overlay = config.$overlay || this.$( 'body,.oo-ui-window-overlay' ).last();
-       this.lookupMenu = new OO.ui.TextInputMenuWidget( this, {
-               '$': OO.ui.Element.getJQuery( this.$overlay ),
-               'input': this.lookupInput,
-               '$container': config.$container
-       } );
-       this.lookupCache = {};
-       this.lookupQuery = null;
-       this.lookupRequest = null;
-       this.populating = false;
-
-       // Events
-       this.$overlay.append( this.lookupMenu.$element );
-
-       this.lookupInput.$input.on( {
-               'focus': OO.ui.bind( this.onLookupInputFocus, this ),
-               'blur': OO.ui.bind( this.onLookupInputBlur, this ),
-               'mousedown': OO.ui.bind( this.onLookupInputMouseDown, this )
-       } );
-       this.lookupInput.connect( this, { 'change': 'onLookupInputChange' } );
+OO.ui.ActionWidget.prototype.setLabel = function () {
+       // Mixin method
+       OO.ui.LabeledElement.prototype.setLabel.apply( this, arguments );
+       this.propagateResize();
 
-       // Initialization
-       this.$element.addClass( 'oo-ui-lookupWidget' );
-       this.lookupMenu.$element.addClass( 'oo-ui-lookupWidget-menu' );
+       return this;
 };
 
-/* Methods */
-
 /**
- * Handle input focus event.
- *
- * @param {jQuery.Event} e Input focus event
+ * @inheritdoc
  */
-OO.ui.LookupInputWidget.prototype.onLookupInputFocus = function () {
-       this.openLookupMenu();
-};
+OO.ui.ActionWidget.prototype.setFlags = function () {
+       // Mixin method
+       OO.ui.FlaggableElement.prototype.setFlags.apply( this, arguments );
+       this.propagateResize();
 
-/**
- * Handle input blur event.
- *
- * @param {jQuery.Event} e Input blur event
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputBlur = function () {
-       this.lookupMenu.hide();
+       return this;
 };
 
 /**
- * Handle input mouse down event.
- *
- * @param {jQuery.Event} e Input mouse down event
+ * @inheritdoc
  */
-OO.ui.LookupInputWidget.prototype.onLookupInputMouseDown = function () {
-       this.openLookupMenu();
+OO.ui.ActionWidget.prototype.clearFlags = function () {
+       // Mixin method
+       OO.ui.FlaggableElement.prototype.clearFlags.apply( this, arguments );
+       this.propagateResize();
+
+       return this;
 };
 
 /**
- * Handle input change event.
+ * Toggle visibility of button.
  *
- * @param {string} value New input value
+ * @param {boolean} [show] Show button, omit to toggle visibility
+ * @chainable
  */
-OO.ui.LookupInputWidget.prototype.onLookupInputChange = function () {
-       this.openLookupMenu();
+OO.ui.ActionWidget.prototype.toggle = function () {
+       // Parent method
+       OO.ui.ActionWidget.super.prototype.toggle.apply( this, arguments );
+       this.propagateResize();
+
+       return this;
 };
 
 /**
- * Get lookup menu.
+ * Button that shows and hides a popup.
  *
- * @return {OO.ui.TextInputMenuWidget}
+ * @class
+ * @extends OO.ui.ButtonWidget
+ * @mixins OO.ui.PopuppableElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
  */
-OO.ui.LookupInputWidget.prototype.getLookupMenu = function () {
-       return this.lookupMenu;
+OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
+       // Parent constructor
+       OO.ui.PopupButtonWidget.super.call( this, config );
+
+       // Mixin constructors
+       OO.ui.PopuppableElement.call( this, config );
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-popupButtonWidget' )
+               .append( this.popup.$element );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );
+OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.PopuppableElement );
+
+/* Methods */
+
 /**
- * Open the menu.
+ * Handles mouse click events.
  *
- * @chainable
+ * @param {jQuery.Event} e Mouse click event
  */
-OO.ui.LookupInputWidget.prototype.openLookupMenu = function () {
-       var value = this.lookupInput.getValue();
-
-       if ( this.lookupMenu.$input.is( ':focus' ) && $.trim( value ) !== '' ) {
-               this.populateLookupMenu();
-               if ( !this.lookupMenu.isVisible() ) {
-                       this.lookupMenu.show();
-               }
-       } else {
-               this.lookupMenu.clearItems();
-               this.lookupMenu.hide();
+OO.ui.PopupButtonWidget.prototype.onClick = function ( e ) {
+       // Skip clicks within the popup
+       if ( $.contains( this.popup.$element[0], e.target ) ) {
+               return;
        }
 
-       return this;
+       if ( !this.isDisabled() ) {
+               this.popup.toggle();
+               // Parent method
+               OO.ui.PopupButtonWidget.super.prototype.onClick.call( this );
+       }
+       return false;
 };
 
 /**
- * Populate lookup menu with current information.
+ * Button that toggles on and off.
  *
- * @chainable
+ * @class
+ * @extends OO.ui.ButtonWidget
+ * @mixins OO.ui.ToggleWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [value=false] Initial value
  */
-OO.ui.LookupInputWidget.prototype.populateLookupMenu = function () {
-       if ( !this.populating ) {
-               this.populating = true;
-               this.getLookupMenuItems()
-                       .done( OO.ui.bind( function ( items ) {
-                               this.lookupMenu.clearItems();
-                               if ( items.length ) {
-                                       this.lookupMenu.show();
-                                       this.lookupMenu.addItems( items );
-                                       this.initializeLookupMenuSelection();
-                                       this.openLookupMenu();
-                               } else {
-                                       this.lookupMenu.hide();
-                               }
-                               this.populating = false;
-                       }, this ) )
-                       .fail( OO.ui.bind( function () {
-                               this.lookupMenu.clearItems();
-                               this.populating = false;
-                       }, this ) );
-       }
+OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
+       // Configuration initialization
+       config = config || {};
 
-       return this;
+       // Parent constructor
+       OO.ui.ToggleButtonWidget.super.call( this, config );
+
+       // Mixin constructors
+       OO.ui.ToggleWidget.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-toggleButtonWidget' );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ButtonWidget );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );
+
+/* Methods */
+
 /**
- * Set selection in the lookup menu with current information.
- *
- * @chainable
+ * @inheritdoc
  */
-OO.ui.LookupInputWidget.prototype.initializeLookupMenuSelection = function () {
-       if ( !this.lookupMenu.getSelectedItem() ) {
-               this.lookupMenu.selectItem( this.lookupMenu.getFirstSelectableItem() );
+OO.ui.ToggleButtonWidget.prototype.onClick = function () {
+       if ( !this.isDisabled() ) {
+               this.setValue( !this.value );
        }
-       this.lookupMenu.highlightItem( this.lookupMenu.getSelectedItem() );
+
+       // Parent method
+       return OO.ui.ToggleButtonWidget.super.prototype.onClick.call( this );
 };
 
 /**
- * Get lookup menu items for the current query.
- *
- * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument
- * of the done event
+ * @inheritdoc
  */
-OO.ui.LookupInputWidget.prototype.getLookupMenuItems = function () {
-       var value = this.lookupInput.getValue(),
-               deferred = $.Deferred();
-
-       if ( value && value !== this.lookupQuery ) {
-               // Abort current request if query has changed
-               if ( this.lookupRequest ) {
-                       this.lookupRequest.abort();
-                       this.lookupQuery = null;
-                       this.lookupRequest = null;
-               }
-               if ( value in this.lookupCache ) {
-                       deferred.resolve( this.getLookupMenuItemsFromData( this.lookupCache[value] ) );
-               } else {
-                       this.lookupQuery = value;
-                       this.lookupRequest = this.getLookupRequest()
-                               .always( OO.ui.bind( function () {
-                                       this.lookupQuery = null;
-                                       this.lookupRequest = null;
-                               }, this ) )
-                               .done( OO.ui.bind( function ( data ) {
-                                       this.lookupCache[value] = this.getLookupCacheItemFromData( data );
-                                       deferred.resolve( this.getLookupMenuItemsFromData( this.lookupCache[value] ) );
-                               }, this ) )
-                               .fail( function () {
-                                       deferred.reject();
-                               } );
-                       this.pushPending();
-                       this.lookupRequest.always( OO.ui.bind( function () {
-                               this.popPending();
-                       }, this ) );
-               }
+OO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {
+       value = !!value;
+       if ( value !== this.value ) {
+               this.setActive( value );
        }
-       return deferred.promise();
-};
 
-/**
- * Get a new request object of the current lookup query value.
- *
- * @abstract
- * @return {jqXHR} jQuery AJAX object, or promise object with an .abort() method
- */
-OO.ui.LookupInputWidget.prototype.getLookupRequest = function () {
-       // Stub, implemented in subclass
-       return null;
+       // Parent method (from mixin)
+       OO.ui.ToggleWidget.prototype.setValue.call( this, value );
+
+       return this;
 };
 
 /**
- * Handle successful lookup request.
+ * Icon widget.
  *
- * Overriding methods should call #populateLookupMenu when results are available and cache results
- * for future lookups in #lookupCache as an array of #OO.ui.MenuItemWidget objects.
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.IconedElement
+ * @mixins OO.ui.TitledElement
  *
- * @abstract
- * @param {Mixed} data Response from server
+ * @constructor
+ * @param {Object} [config] Configuration options
  */
-OO.ui.LookupInputWidget.prototype.onLookupRequestDone = function () {
-       // Stub, implemented in subclass
+OO.ui.IconWidget = function OoUiIconWidget( config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.IconWidget.super.call( this, config );
+
+       // Mixin constructors
+       OO.ui.IconedElement.call( this, this.$element, config );
+       OO.ui.TitledElement.call( this, this.$element, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-iconWidget' );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.IconWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.TitledElement );
+
+/* Static Properties */
+
+OO.ui.IconWidget.static.tagName = 'span';
+
 /**
- * Get a list of menu item widgets from the data stored by the lookup request's done handler.
+ * Indicator widget.
  *
- * @abstract
- * @param {Mixed} data Cached result data, usually an array
- * @return {OO.ui.MenuItemWidget[]} Menu items
+ * See OO.ui.IndicatedElement for more information.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.IndicatedElement
+ * @mixins OO.ui.TitledElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
  */
-OO.ui.LookupInputWidget.prototype.getLookupMenuItemsFromData = function () {
-       // Stub, implemented in subclass
-       return [];
+OO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.IndicatorWidget.super.call( this, config );
+
+       // Mixin constructors
+       OO.ui.IndicatedElement.call( this, this.$element, config );
+       OO.ui.TitledElement.call( this, this.$element, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-indicatorWidget' );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.IndicatorWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.IndicatedElement );
+OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.TitledElement );
+
+/* Static Properties */
+
+OO.ui.IndicatorWidget.static.tagName = 'span';
+
 /**
- * Option widget.
+ * Inline menu of options.
  *
- * Use with OO.ui.SelectWidget.
+ * Inline menus provide a control for accessing a menu and compose a menu within the widget, which
+ * can be accessed using the #getMenu method.
+ *
+ * Use with OO.ui.MenuOptionWidget.
  *
  * @class
  * @extends OO.ui.Widget
  * @mixins OO.ui.IconedElement
- * @mixins OO.ui.LabeledElement
  * @mixins OO.ui.IndicatedElement
- * @mixins OO.ui.FlaggableElement
+ * @mixins OO.ui.LabeledElement
+ * @mixins OO.ui.TitledElement
  *
  * @constructor
- * @param {Mixed} data Option data
  * @param {Object} [config] Configuration options
- * @cfg {string} [rel] Value for `rel` attribute in DOM, allowing per-option styling
+ * @cfg {Object} [menu] Configuration options to pass to menu widget
  */
-OO.ui.OptionWidget = function OoUiOptionWidget( data, config ) {
-       // Config intialization
-       config = config || {};
+OO.ui.InlineMenuWidget = function OoUiInlineMenuWidget( config ) {
+       // Configuration initialization
+       config = $.extend( { 'indicator': 'down' }, config );
 
        // Parent constructor
-       OO.ui.OptionWidget.super.call( this, config );
+       OO.ui.InlineMenuWidget.super.call( this, config );
 
        // Mixin constructors
-       OO.ui.ItemWidget.call( this );
        OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
        OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.FlaggableElement.call( this, config );
+       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
+       OO.ui.TitledElement.call( this, this.$label, config );
 
        // Properties
-       this.data = data;
-       this.selected = false;
-       this.highlighted = false;
-       this.pressed = false;
+       this.menu = new OO.ui.MenuWidget( $.extend( { '$': this.$, 'widget': this }, config.menu ) );
+       this.$handle = this.$( '<span>' );
+
+       // Events
+       this.$element.on( { 'click': OO.ui.bind( this.onClick, this ) } );
+       this.menu.connect( this, { 'select': 'onMenuSelect' } );
 
        // Initialization
+       this.$handle
+               .addClass( 'oo-ui-inlineMenuWidget-handle' )
+               .append( this.$icon, this.$label, this.$indicator );
        this.$element
-               .data( 'oo-ui-optionWidget', this )
-               .attr( 'rel', config.rel )
-               .addClass( 'oo-ui-optionWidget' )
-               .append( this.$label );
-       this.$element
-               .prepend( this.$icon )
-               .append( this.$indicator );
+               .addClass( 'oo-ui-inlineMenuWidget' )
+               .append( this.$handle, this.menu.$element );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.ItemWidget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IconedElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.LabeledElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatedElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.FlaggableElement );
-
-/* Static Properties */
-
-OO.ui.OptionWidget.static.tagName = 'li';
-
-OO.ui.OptionWidget.static.selectable = true;
-
-OO.ui.OptionWidget.static.highlightable = true;
-
-OO.ui.OptionWidget.static.pressable = true;
-
-OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
+OO.inheritClass( OO.ui.InlineMenuWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.IndicatedElement );
+OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.LabeledElement );
+OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.TitledElement );
 
 /* Methods */
 
 /**
- * Check if option can be selected.
+ * Get the menu.
  *
- * @return {boolean} Item is selectable
+ * @return {OO.ui.MenuWidget} Menu of widget
  */
-OO.ui.OptionWidget.prototype.isSelectable = function () {
-       return this.constructor.static.selectable && !this.isDisabled();
+OO.ui.InlineMenuWidget.prototype.getMenu = function () {
+       return this.menu;
 };
 
 /**
- * Check if option can be highlighted.
+ * Handles menu select events.
  *
- * @return {boolean} Item is highlightable
+ * @param {OO.ui.MenuItemWidget} item Selected menu item
  */
-OO.ui.OptionWidget.prototype.isHighlightable = function () {
-       return this.constructor.static.highlightable && !this.isDisabled();
-};
+OO.ui.InlineMenuWidget.prototype.onMenuSelect = function ( item ) {
+       var selectedLabel;
 
-/**
- * Check if option can be pressed.
- *
- * @return {boolean} Item is pressable
- */
-OO.ui.OptionWidget.prototype.isPressable = function () {
-       return this.constructor.static.pressable && !this.isDisabled();
+       if ( !item ) {
+               return;
+       }
+
+       selectedLabel = item.getLabel();
+
+       // If the label is a DOM element, clone it, because setLabel will append() it
+       if ( selectedLabel instanceof jQuery ) {
+               selectedLabel = selectedLabel.clone();
+       }
+
+       this.setLabel( selectedLabel );
 };
 
 /**
- * Check if option is selected.
+ * Handles mouse click events.
  *
- * @return {boolean} Item is selected
+ * @param {jQuery.Event} e Mouse click event
  */
-OO.ui.OptionWidget.prototype.isSelected = function () {
-       return this.selected;
+OO.ui.InlineMenuWidget.prototype.onClick = function ( e ) {
+       // Skip clicks within the menu
+       if ( $.contains( this.menu.$element[0], e.target ) ) {
+               return;
+       }
+
+       if ( !this.isDisabled() ) {
+               if ( this.menu.isVisible() ) {
+                       this.menu.toggle( false );
+               } else {
+                       this.menu.toggle( true );
+               }
+       }
+       return false;
 };
 
 /**
- * Check if option is highlighted.
+ * Base class for input widgets.
  *
- * @return {boolean} Item is highlighted
+ * @abstract
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [name=''] HTML input name
+ * @cfg {string} [value=''] Input value
+ * @cfg {boolean} [readOnly=false] Prevent changes
+ * @cfg {Function} [inputFilter] Filter function to apply to the input. Takes a string argument and returns a string.
  */
-OO.ui.OptionWidget.prototype.isHighlighted = function () {
-       return this.highlighted;
+OO.ui.InputWidget = function OoUiInputWidget( config ) {
+       // Config intialization
+       config = $.extend( { 'readOnly': false }, config );
+
+       // Parent constructor
+       OO.ui.InputWidget.super.call( this, config );
+
+       // Properties
+       this.$input = this.getInputElement( config );
+       this.value = '';
+       this.readOnly = false;
+       this.inputFilter = config.inputFilter;
+
+       // Events
+       this.$input.on( 'keydown mouseup cut paste change input select', OO.ui.bind( this.onEdit, this ) );
+
+       // Initialization
+       this.$input
+               .attr( 'name', config.name )
+               .prop( 'disabled', this.isDisabled() );
+       this.setReadOnly( config.readOnly );
+       this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input );
+       this.setValue( config.value );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
+
+/* Events */
+
 /**
- * Check if option is pressed.
- *
- * @return {boolean} Item is pressed
+ * @event change
+ * @param value
  */
-OO.ui.OptionWidget.prototype.isPressed = function () {
-       return this.pressed;
-};
+
+/* Methods */
 
 /**
- * Set selected state.
+ * Get input element.
  *
- * @param {boolean} [state=false] Select option
- * @chainable
+ * @param {Object} [config] Configuration options
+ * @return {jQuery} Input element
  */
-OO.ui.OptionWidget.prototype.setSelected = function ( state ) {
-       if ( this.constructor.static.selectable ) {
-               this.selected = !!state;
-               if ( this.selected ) {
-                       this.$element.addClass( 'oo-ui-optionWidget-selected' );
-                       if ( this.constructor.static.scrollIntoViewOnSelect ) {
-                               this.scrollElementIntoView();
-                       }
-               } else {
-                       this.$element.removeClass( 'oo-ui-optionWidget-selected' );
-               }
-       }
-       return this;
+OO.ui.InputWidget.prototype.getInputElement = function () {
+       return this.$( '<input>' );
 };
 
 /**
- * Set highlighted state.
+ * Handle potentially value-changing events.
  *
- * @param {boolean} [state=false] Highlight option
- * @chainable
+ * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event
  */
-OO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
-       if ( this.constructor.static.highlightable ) {
-               this.highlighted = !!state;
-               if ( this.highlighted ) {
-                       this.$element.addClass( 'oo-ui-optionWidget-highlighted' );
-               } else {
-                       this.$element.removeClass( 'oo-ui-optionWidget-highlighted' );
-               }
+OO.ui.InputWidget.prototype.onEdit = function () {
+       var widget = this;
+       if ( !this.isDisabled() ) {
+               // Allow the stack to clear so the value will be updated
+               setTimeout( function () {
+                       widget.setValue( widget.$input.val() );
+               } );
        }
-       return this;
 };
 
 /**
- * Set pressed state.
+ * Get the value of the input.
  *
- * @param {boolean} [state=false] Press option
- * @chainable
+ * @return {string} Input value
  */
-OO.ui.OptionWidget.prototype.setPressed = function ( state ) {
-       if ( this.constructor.static.pressable ) {
-               this.pressed = !!state;
-               if ( this.pressed ) {
-                       this.$element.addClass( 'oo-ui-optionWidget-pressed' );
-               } else {
-                       this.$element.removeClass( 'oo-ui-optionWidget-pressed' );
-               }
-       }
-       return this;
+OO.ui.InputWidget.prototype.getValue = function () {
+       return this.value;
 };
 
 /**
- * Make the option's highlight flash.
- *
- * While flashing, the visual style of the pressed state is removed if present.
+ * Sets the direction of the current input, either RTL or LTR
  *
- * @return {jQuery.Promise} Promise resolved when flashing is done
+ * @param {boolean} isRTL
  */
-OO.ui.OptionWidget.prototype.flash = function () {
-       var $this = this.$element,
-               deferred = $.Deferred();
-
-       if ( !this.isDisabled() && this.constructor.static.pressable ) {
-               $this.removeClass( 'oo-ui-optionWidget-highlighted oo-ui-optionWidget-pressed' );
-               setTimeout( OO.ui.bind( function () {
-                       // Restore original classes
-                       $this
-                               .toggleClass( 'oo-ui-optionWidget-highlighted', this.highlighted )
-                               .toggleClass( 'oo-ui-optionWidget-pressed', this.pressed );
-                       setTimeout( function () {
-                               deferred.resolve();
-                       }, 100 );
-               }, this ), 100 );
+OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) {
+       if ( isRTL ) {
+               this.$input.removeClass( 'oo-ui-ltr' );
+               this.$input.addClass( 'oo-ui-rtl' );
+       } else {
+               this.$input.removeClass( 'oo-ui-rtl' );
+               this.$input.addClass( 'oo-ui-ltr' );
        }
-
-       return deferred.promise();
 };
 
 /**
- * Get option data.
+ * Set the value of the input.
  *
- * @return {Mixed} Option data
+ * @param {string} value New value
+ * @fires change
+ * @chainable
  */
-OO.ui.OptionWidget.prototype.getData = function () {
-       return this.data;
+OO.ui.InputWidget.prototype.setValue = function ( value ) {
+       value = this.sanitizeValue( value );
+       if ( this.value !== value ) {
+               this.value = value;
+               this.emit( 'change', this.value );
+       }
+       // Update the DOM if it has changed. Note that with sanitizeValue, it
+       // is possible for the DOM value to change without this.value changing.
+       if ( this.$input.val() !== this.value ) {
+               this.$input.val( this.value );
+       }
+       return this;
 };
 
 /**
- * Selection of options.
- *
- * Use together with OO.ui.OptionWidget.
+ * Sanitize incoming value.
  *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
+ * Ensures value is a string, and converts undefined and null to empty strings.
  *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.OptionWidget[]} [items] Options to add
+ * @param {string} value Original value
+ * @return {string} Sanitized value
  */
-OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.SelectWidget.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.GroupWidget.call( this, this.$element, config );
-
-       // Properties
-       this.pressed = false;
-       this.selecting = null;
-       this.hashes = {};
-       this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
-       this.onMouseMoveHandler = OO.ui.bind( this.onMouseMove, this );
-
-       // Events
-       this.$element.on( {
-               'mousedown': OO.ui.bind( this.onMouseDown, this ),
-               'mouseover': OO.ui.bind( this.onMouseOver, this ),
-               'mouseleave': OO.ui.bind( this.onMouseLeave, this )
-       } );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-selectWidget oo-ui-selectWidget-depressed' );
-       if ( $.isArray( config.items ) ) {
-               this.addItems( config.items );
-       }
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );
-
-// Need to mixin base class as well
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupElement );
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupWidget );
-
-/* Events */
+OO.ui.InputWidget.prototype.sanitizeValue = function ( value ) {
+       if ( value === undefined || value === null ) {
+               return '';
+       } else if ( this.inputFilter ) {
+               return this.inputFilter( String( value ) );
+       } else {
+               return String( value );
+       }
+};
 
 /**
- * @event highlight
- * @param {OO.ui.OptionWidget|null} item Highlighted item
+ * Simulate the behavior of clicking on a label bound to this input.
  */
+OO.ui.InputWidget.prototype.simulateLabelClick = function () {
+       if ( !this.isDisabled() ) {
+               if ( this.$input.is( ':checkbox,:radio' ) ) {
+                       this.$input.click();
+               } else if ( this.$input.is( ':input' ) ) {
+                       this.$input[0].focus();
+               }
+       }
+};
 
 /**
- * @event press
- * @param {OO.ui.OptionWidget|null} item Pressed item
+ * Check if the widget is read-only.
+ *
+ * @return {boolean}
  */
+OO.ui.InputWidget.prototype.isReadOnly = function () {
+       return this.readOnly;
+};
 
 /**
- * @event select
- * @param {OO.ui.OptionWidget|null} item Selected item
+ * Set the read-only state of the widget.
+ *
+ * This should probably change the widgets's appearance and prevent it from being used.
+ *
+ * @param {boolean} state Make input read-only
+ * @chainable
  */
+OO.ui.InputWidget.prototype.setReadOnly = function ( state ) {
+       this.readOnly = !!state;
+       this.$input.prop( 'readOnly', this.readOnly );
+       return this;
+};
 
 /**
- * @event choose
- * @param {OO.ui.OptionWidget|null} item Chosen item
+ * @inheritdoc
  */
+OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
+       OO.ui.InputWidget.super.prototype.setDisabled.call( this, state );
+       if ( this.$input ) {
+               this.$input.prop( 'disabled', this.isDisabled() );
+       }
+       return this;
+};
 
 /**
- * @event add
- * @param {OO.ui.OptionWidget[]} items Added items
- * @param {number} index Index items were added at
+ * Focus the input.
+ *
+ * @chainable
  */
+OO.ui.InputWidget.prototype.focus = function () {
+       this.$input[0].focus();
+       return this;
+};
 
 /**
- * @event remove
- * @param {OO.ui.OptionWidget[]} items Removed items
+ * Blur the input.
+ *
+ * @chainable
  */
-
-/* Static Properties */
-
-OO.ui.SelectWidget.static.tagName = 'ul';
-
-/* Methods */
+OO.ui.InputWidget.prototype.blur = function () {
+       this.$input[0].blur();
+       return this;
+};
 
 /**
- * Handle mouse down events.
+ * Checkbox input widget.
  *
- * @private
- * @param {jQuery.Event} e Mouse down event
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
  */
-OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
-       var item;
+OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
+       // Parent constructor
+       OO.ui.CheckboxInputWidget.super.call( this, config );
 
-       if ( !this.isDisabled() && e.which === 1 ) {
-               this.togglePressed( true );
-               item = this.getTargetItem( e );
-               if ( item && item.isSelectable() ) {
-                       this.pressItem( item );
-                       this.selecting = item;
-                       this.getElementDocument().addEventListener(
-                               'mouseup', this.onMouseUpHandler, true
-                       );
-                       this.getElementDocument().addEventListener(
-                               'mousemove', this.onMouseMoveHandler, true
-                       );
-               }
-       }
-       return false;
+       // Initialization
+       this.$element.addClass( 'oo-ui-checkboxInputWidget' );
 };
 
-/**
- * Handle mouse up events.
- *
- * @private
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.SelectWidget.prototype.onMouseUp = function ( e ) {
-       var item;
+/* Setup */
 
-       this.togglePressed( false );
-       if ( !this.selecting ) {
-               item = this.getTargetItem( e );
-               if ( item && item.isSelectable() ) {
-                       this.selecting = item;
-               }
-       }
-       if ( !this.isDisabled() && e.which === 1 && this.selecting ) {
-               this.pressItem( null );
-               this.chooseItem( this.selecting );
-               this.selecting = null;
-       }
+OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
 
-       this.getElementDocument().removeEventListener(
-               'mouseup', this.onMouseUpHandler, true
-       );
-       this.getElementDocument().removeEventListener(
-               'mousemove', this.onMouseMoveHandler, true
-       );
+/* Events */
 
-       return false;
-};
+/* Methods */
 
 /**
- * Handle mouse move events.
+ * Get input element.
  *
- * @private
- * @param {jQuery.Event} e Mouse move event
+ * @return {jQuery} Input element
  */
-OO.ui.SelectWidget.prototype.onMouseMove = function ( e ) {
-       var item;
-
-       if ( !this.isDisabled() && this.pressed ) {
-               item = this.getTargetItem( e );
-               if ( item && item !== this.selecting && item.isSelectable() ) {
-                       this.pressItem( item );
-                       this.selecting = item;
-               }
-       }
-       return false;
+OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
+       return this.$( '<input type="checkbox" />' );
 };
 
 /**
- * Handle mouse over events.
+ * Get checked state of the checkbox
  *
- * @private
- * @param {jQuery.Event} e Mouse over event
+ * @return {boolean} If the checkbox is checked
  */
-OO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {
-       var item;
-
-       if ( !this.isDisabled() ) {
-               item = this.getTargetItem( e );
-               this.highlightItem( item && item.isHighlightable() ? item : null );
-       }
-       return false;
+OO.ui.CheckboxInputWidget.prototype.getValue = function () {
+       return this.value;
 };
 
 /**
- * Handle mouse leave events.
- *
- * @private
- * @param {jQuery.Event} e Mouse over event
+ * Set value
  */
-OO.ui.SelectWidget.prototype.onMouseLeave = function () {
-       if ( !this.isDisabled() ) {
-               this.highlightItem( null );
+OO.ui.CheckboxInputWidget.prototype.setValue = function ( value ) {
+       value = !!value;
+       if ( this.value !== value ) {
+               this.value = value;
+               this.$input.prop( 'checked', this.value );
+               this.emit( 'change', this.value );
        }
-       return false;
 };
 
 /**
- * Get the closest item to a jQuery.Event.
- *
- * @private
- * @param {jQuery.Event} e
- * @return {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found
+ * @inheritdoc
  */
-OO.ui.SelectWidget.prototype.getTargetItem = function ( e ) {
-       var $item = this.$( e.target ).closest( '.oo-ui-optionWidget' );
-       if ( $item.length ) {
-               return $item.data( 'oo-ui-optionWidget' );
+OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
+       var widget = this;
+       if ( !this.isDisabled() ) {
+               // Allow the stack to clear so the value will be updated
+               setTimeout( function () {
+                       widget.setValue( widget.$input.prop( 'checked' ) );
+               } );
        }
-       return null;
 };
 
 /**
- * Get selected item.
+ * Input widget with a text field.
  *
- * @return {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [placeholder] Placeholder text
+ * @cfg {string} [icon] Symbolic name of icon
+ * @cfg {boolean} [multiline=false] Allow multiple lines of text
+ * @cfg {boolean} [autosize=false] Automatically resize to fit content
+ * @cfg {boolean} [maxRows=10] Maximum number of rows to make visible when autosizing
  */
-OO.ui.SelectWidget.prototype.getSelectedItem = function () {
-       var i, len;
+OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
+       var widget = this;
+       config = $.extend( { 'maxRows': 10 }, config );
 
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               if ( this.items[i].isSelected() ) {
-                       return this.items[i];
-               }
-       }
-       return null;
-};
+       // Parent constructor
+       OO.ui.TextInputWidget.super.call( this, config );
 
-/**
- * Get highlighted item.
- *
- * @return {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted
- */
-OO.ui.SelectWidget.prototype.getHighlightedItem = function () {
-       var i, len;
+       // Properties
+       this.pending = 0;
+       this.multiline = !!config.multiline;
+       this.autosize = !!config.autosize;
+       this.maxRows = config.maxRows;
 
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               if ( this.items[i].isHighlighted() ) {
-                       return this.items[i];
-               }
+       // Events
+       this.$input.on( 'keypress', OO.ui.bind( this.onKeyPress, this ) );
+       this.$element.on( 'DOMNodeInsertedIntoDocument', OO.ui.bind( this.onElementAttach, this ) );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-textInputWidget' );
+       if ( config.icon ) {
+               this.$element.addClass( 'oo-ui-textInputWidget-decorated' );
+               this.$element.append(
+                       this.$( '<span>' )
+                               .addClass( 'oo-ui-textInputWidget-icon oo-ui-icon-' + config.icon )
+                               .mousedown( function () {
+                                       widget.$input[0].focus();
+                                       return false;
+                               } )
+               );
        }
-       return null;
+       if ( config.placeholder ) {
+               this.$input.attr( 'placeholder', config.placeholder );
+       }
+       this.$element.attr( 'role', 'textbox' );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );
+
+/* Events */
+
 /**
- * Get an existing item with equivilant data.
+ * User presses enter inside the text box.
+ *
+ * Not called if input is multiline.
  *
- * @param {Object} data Item data to search for
- * @return {OO.ui.OptionWidget|null} Item with equivilent value, `null` if none exists
+ * @event enter
  */
-OO.ui.SelectWidget.prototype.getItemFromData = function ( data ) {
-       var hash = OO.getHash( data );
-
-       if ( hash in this.hashes ) {
-               return this.hashes[hash];
-       }
 
-       return null;
-};
+/* Methods */
 
 /**
- * Toggle pressed state.
+ * Handle key press events.
  *
- * @param {boolean} pressed An option is being pressed
+ * @param {jQuery.Event} e Key press event
+ * @fires enter If enter key is pressed and input is not multiline
  */
-OO.ui.SelectWidget.prototype.togglePressed = function ( pressed ) {
-       if ( pressed === undefined ) {
-               pressed = !this.pressed;
-       }
-       if ( pressed !== this.pressed ) {
-               this.$element.toggleClass( 'oo-ui-selectWidget-pressed', pressed );
-               this.$element.toggleClass( 'oo-ui-selectWidget-depressed', !pressed );
-               this.pressed = pressed;
+OO.ui.TextInputWidget.prototype.onKeyPress = function ( e ) {
+       if ( e.which === OO.ui.Keys.ENTER && !this.multiline ) {
+               this.emit( 'enter' );
        }
 };
 
 /**
- * Highlight an item.
- *
- * Highlighting is mutually exclusive.
+ * Handle element attach events.
  *
- * @param {OO.ui.OptionWidget} [item] Item to highlight, omit to deselect all
- * @fires highlight
- * @chainable
+ * @param {jQuery.Event} e Element attach event
  */
-OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
-       var i, len, highlighted,
-               changed = false;
+OO.ui.TextInputWidget.prototype.onElementAttach = function () {
+       this.adjustSize();
+};
 
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               highlighted = this.items[i] === item;
-               if ( this.items[i].isHighlighted() !== highlighted ) {
-                       this.items[i].setHighlighted( highlighted );
-                       changed = true;
-               }
-       }
-       if ( changed ) {
-               this.emit( 'highlight', item );
-       }
+/**
+ * @inheritdoc
+ */
+OO.ui.TextInputWidget.prototype.onEdit = function () {
+       this.adjustSize();
 
-       return this;
+       // Parent method
+       return OO.ui.TextInputWidget.super.prototype.onEdit.call( this );
 };
 
 /**
- * Select an item.
+ * Automatically adjust the size of the text input.
+ *
+ * This only affects multi-line inputs that are auto-sized.
  *
- * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
- * @fires select
  * @chainable
  */
-OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
-       var i, len, selected,
-               changed = false;
+OO.ui.TextInputWidget.prototype.adjustSize = function () {
+       var $clone, scrollHeight, innerHeight, outerHeight, maxInnerHeight, idealHeight;
 
-       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 ) {
-               this.emit( 'select', item );
+       if ( this.multiline && this.autosize ) {
+               $clone = this.$input.clone()
+                       .val( this.$input.val() )
+                       .css( { 'height': 0 } )
+                       .insertAfter( this.$input );
+               // Set inline height property to 0 to measure scroll height
+               scrollHeight = $clone[0].scrollHeight;
+               // Remove inline height property to measure natural heights
+               $clone.css( 'height', '' );
+               innerHeight = $clone.innerHeight();
+               outerHeight = $clone.outerHeight();
+               // Measure max rows height
+               $clone.attr( 'rows', this.maxRows ).css( 'height', 'auto' );
+               maxInnerHeight = $clone.innerHeight();
+               $clone.removeAttr( 'rows' ).css( 'height', '' );
+               $clone.remove();
+               idealHeight = Math.min( maxInnerHeight, scrollHeight );
+               // Only apply inline height when expansion beyond natural height is needed
+               this.$input.css(
+                       'height',
+                       // Use the difference between the inner and outer height as a buffer
+                       idealHeight > outerHeight ? idealHeight + ( outerHeight - innerHeight ) : ''
+               );
        }
-
        return this;
 };
 
 /**
- * Press an item.
+ * Get input element.
  *
- * @param {OO.ui.OptionWidget} [item] Item to press, omit to depress all
- * @fires press
- * @chainable
+ * @param {Object} [config] Configuration options
+ * @return {jQuery} Input element
  */
-OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
-       var i, len, pressed,
-               changed = false;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               pressed = this.items[i] === item;
-               if ( this.items[i].isPressed() !== pressed ) {
-                       this.items[i].setPressed( pressed );
-                       changed = true;
-               }
-       }
-       if ( changed ) {
-               this.emit( 'press', item );
-       }
-
-       return this;
+OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
+       return config.multiline ? this.$( '<textarea>' ) : this.$( '<input type="text" />' );
 };
 
+/* Methods */
+
 /**
- * Choose an item.
- *
- * Identical to #selectItem, but may vary in subclasses that want to take additional action when
- * an item is selected using the keyboard or mouse.
+ * Check if input supports multiple lines.
  *
- * @param {OO.ui.OptionWidget} item Item to choose
- * @fires choose
- * @chainable
+ * @return {boolean}
  */
-OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
-       this.selectItem( item );
-       this.emit( 'choose', item );
-
-       return this;
+OO.ui.TextInputWidget.prototype.isMultiline = function () {
+       return !!this.multiline;
 };
 
 /**
- * Get an item relative to another one.
+ * Check if input automatically adjusts its size.
  *
- * @param {OO.ui.OptionWidget} item Item to start at
- * @param {number} direction Direction to move in
- * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the menu
+ * @return {boolean}
  */
-OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction ) {
-       var inc = direction > 0 ? 1 : -1,
-               len = this.items.length,
-               index = item instanceof OO.ui.OptionWidget ?
-                       $.inArray( item, this.items ) : ( inc > 0 ? -1 : 0 ),
-               stopAt = Math.max( Math.min( index, len - 1 ), 0 ),
-               i = inc > 0 ?
-                       // Default to 0 instead of -1, if nothing is selected let's start at the beginning
-                       Math.max( index, -1 ) :
-                       // Default to n-1 instead of -1, if nothing is selected let's start at the end
-                       Math.min( index, len );
-
-       while ( true ) {
-               i = ( i + inc + len ) % len;
-               item = this.items[i];
-               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
-                       return item;
-               }
-               // Stop iterating when we've looped all the way around
-               if ( i === stopAt ) {
-                       break;
-               }
-       }
-       return null;
+OO.ui.TextInputWidget.prototype.isAutosizing = function () {
+       return !!this.autosize;
 };
 
 /**
- * Get the next selectable item.
+ * Check if input is pending.
  *
- * @return {OO.ui.OptionWidget|null} Item, `null` if ther aren't any selectable items
+ * @return {boolean}
  */
-OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
-       var i, len, item;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               item = this.items[i];
-               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
-                       return item;
-               }
-       }
-
-       return null;
+OO.ui.TextInputWidget.prototype.isPending = function () {
+       return !!this.pending;
 };
 
 /**
- * Add items.
- *
- * When items are added with the same values as existing items, the existing items will be
- * automatically removed before the new items are added.
+ * Increase the pending stack.
  *
- * @param {OO.ui.OptionWidget[]} items Items to add
- * @param {number} [index] Index to insert items after
- * @fires add
  * @chainable
  */
-OO.ui.SelectWidget.prototype.addItems = function ( items, index ) {
-       var i, len, item, hash,
-               remove = [];
-
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               hash = OO.getHash( item.getData() );
-               if ( hash in this.hashes ) {
-                       // Remove item with same value
-                       remove.push( this.hashes[hash] );
-               }
-               this.hashes[hash] = item;
-       }
-       if ( remove.length ) {
-               this.removeItems( remove );
+OO.ui.TextInputWidget.prototype.pushPending = function () {
+       if ( this.pending === 0 ) {
+               this.$element.addClass( 'oo-ui-textInputWidget-pending' );
+               this.$input.addClass( 'oo-ui-texture-pending' );
        }
-
-       // Mixin method
-       OO.ui.GroupWidget.prototype.addItems.call( this, items, index );
-
-       // Always provide an index, even if it was omitted
-       this.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );
+       this.pending++;
 
        return this;
 };
 
 /**
- * Remove items.
+ * Reduce the pending stack.
  *
- * Items will be detached, not removed, so they can be used later.
+ * Clamped at zero.
  *
- * @param {OO.ui.OptionWidget[]} items Items to remove
- * @fires remove
  * @chainable
  */
-OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
-       var i, len, item, hash;
-
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               hash = OO.getHash( item.getData() );
-               if ( hash in this.hashes ) {
-                       // Remove existing item
-                       delete this.hashes[hash];
-               }
-               if ( item.isSelected() ) {
-                       this.selectItem( null );
-               }
-       }
-
-       // Mixin method
-       OO.ui.GroupWidget.prototype.removeItems.call( this, items );
-
-       this.emit( 'remove', items );
+OO.ui.TextInputWidget.prototype.popPending = function () {
+       if ( this.pending === 1 ) {
+               this.$element.removeClass( 'oo-ui-textInputWidget-pending' );
+               this.$input.removeClass( 'oo-ui-texture-pending' );
+       }
+       this.pending = Math.max( 0, this.pending - 1 );
 
        return this;
 };
 
 /**
- * Clear all items.
- *
- * Items will be detached, not removed, so they can be used later.
+ * Select the contents of the input.
  *
- * @fires remove
  * @chainable
  */
-OO.ui.SelectWidget.prototype.clearItems = function () {
-       var items = this.items.slice();
-
-       // Clear all items
-       this.hashes = {};
-       // Mixin method
-       OO.ui.GroupWidget.prototype.clearItems.call( this );
-       this.selectItem( null );
-
-       this.emit( 'remove', items );
-
+OO.ui.TextInputWidget.prototype.select = function () {
+       this.$input.select();
        return this;
 };
 
 /**
- * Menu item widget.
- *
- * Use with OO.ui.MenuWidget.
+ * Label widget.
  *
  * @class
- * @extends OO.ui.OptionWidget
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.LabeledElement
  *
  * @constructor
- * @param {Mixed} data Item data
  * @param {Object} [config] Configuration options
  */
-OO.ui.MenuItemWidget = function OoUiMenuItemWidget( data, config ) {
-       // Configuration initialization
-       config = $.extend( { 'icon': 'check' }, config );
+OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
+       // Config intialization
+       config = config || {};
 
        // Parent constructor
-       OO.ui.MenuItemWidget.super.call( this, data, config );
+       OO.ui.LabelWidget.super.call( this, config );
+
+       // Mixin constructors
+       OO.ui.LabeledElement.call( this, this.$element, config );
+
+       // Properties
+       this.input = config.input;
+
+       // Events
+       if ( this.input instanceof OO.ui.InputWidget ) {
+               this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
+       }
 
        // Initialization
-       this.$element.addClass( 'oo-ui-menuItemWidget' );
+       this.$element.addClass( 'oo-ui-labelWidget' );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.MenuItemWidget, OO.ui.OptionWidget );
+OO.inheritClass( OO.ui.LabelWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.LabelWidget, OO.ui.LabeledElement );
+
+/* Static Properties */
+
+OO.ui.LabelWidget.static.tagName = 'label';
+
+/* Methods */
 
 /**
- * Menu widget.
+ * Handles label mouse click events.
  *
- * Use together with OO.ui.MenuItemWidget.
+ * @param {jQuery.Event} e Mouse click event
+ */
+OO.ui.LabelWidget.prototype.onClick = function () {
+       this.input.simulateLabelClick();
+       return false;
+};
+
+/**
+ * Generic option widget for use with OO.ui.SelectWidget.
  *
  * @class
- * @extends OO.ui.SelectWidget
- * @mixins OO.ui.ClippableElement
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.LabeledElement
+ * @mixins OO.ui.FlaggableElement
  *
  * @constructor
+ * @param {Mixed} data Option data
  * @param {Object} [config] Configuration options
- * @cfg {OO.ui.InputWidget} [input] Input to bind keyboard handlers to
- * @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu
+ * @cfg {string} [rel] Value for `rel` attribute in DOM, allowing per-option styling
  */
-OO.ui.MenuWidget = function OoUiMenuWidget( config ) {
+OO.ui.OptionWidget = function OoUiOptionWidget( data, config ) {
        // Config intialization
        config = config || {};
 
        // Parent constructor
-       OO.ui.MenuWidget.super.call( this, config );
+       OO.ui.OptionWidget.super.call( this, config );
 
        // Mixin constructors
-       OO.ui.ClippableElement.call( this, this.$group, config );
+       OO.ui.ItemWidget.call( this );
+       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
+       OO.ui.FlaggableElement.call( this, config );
 
        // Properties
-       this.autoHide = config.autoHide === undefined || !!config.autoHide;
-       this.newItems = null;
-       this.$input = config.input ? config.input.$input : null;
-       this.$previousFocus = null;
-       this.isolated = !config.input;
-       this.visible = false;
-       this.flashing = false;
-       this.onKeyDownHandler = OO.ui.bind( this.onKeyDown, this );
-       this.onDocumentMouseDownHandler = OO.ui.bind( this.onDocumentMouseDown, this );
+       this.data = data;
+       this.selected = false;
+       this.highlighted = false;
+       this.pressed = false;
 
        // Initialization
-       this.$element.hide().addClass( 'oo-ui-menuWidget' );
+       this.$element
+               .data( 'oo-ui-optionWidget', this )
+               .attr( 'rel', config.rel )
+               .attr( 'role', 'option' )
+               .addClass( 'oo-ui-optionWidget' )
+               .append( this.$label );
+       this.$element
+               .prepend( this.$icon )
+               .append( this.$indicator );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.MenuWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.MenuWidget, OO.ui.ClippableElement );
+OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.ItemWidget );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.LabeledElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.FlaggableElement );
+
+/* Static Properties */
+
+OO.ui.OptionWidget.static.tagName = 'li';
+
+OO.ui.OptionWidget.static.selectable = true;
+
+OO.ui.OptionWidget.static.highlightable = true;
+
+OO.ui.OptionWidget.static.pressable = true;
+
+OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
 
 /* Methods */
 
 /**
- * Handles document mouse down events.
+ * Check if option can be selected.
  *
- * @param {jQuery.Event} e Key down event
+ * @return {boolean} Item is selectable
  */
-OO.ui.MenuWidget.prototype.onDocumentMouseDown = function ( e ) {
-       if ( !$.contains( this.$element[0], e.target ) ) {
-               this.hide();
-       }
+OO.ui.OptionWidget.prototype.isSelectable = function () {
+       return this.constructor.static.selectable && !this.isDisabled();
 };
 
 /**
- * Handles key down events.
+ * Check if option can be highlighted.
  *
- * @param {jQuery.Event} e Key down event
+ * @return {boolean} Item is highlightable
  */
-OO.ui.MenuWidget.prototype.onKeyDown = function ( e ) {
-       var nextItem,
-               handled = false,
-               highlightItem = this.getHighlightedItem();
+OO.ui.OptionWidget.prototype.isHighlightable = function () {
+       return this.constructor.static.highlightable && !this.isDisabled();
+};
 
-       if ( !this.isDisabled() && this.visible ) {
-               if ( !highlightItem ) {
-                       highlightItem = this.getSelectedItem();
-               }
-               switch ( e.keyCode ) {
-                       case OO.ui.Keys.ENTER:
-                               this.chooseItem( highlightItem );
-                               handled = true;
-                               break;
-                       case OO.ui.Keys.UP:
-                               nextItem = this.getRelativeSelectableItem( highlightItem, -1 );
-                               handled = true;
-                               break;
-                       case OO.ui.Keys.DOWN:
-                               nextItem = this.getRelativeSelectableItem( highlightItem, 1 );
-                               handled = true;
-                               break;
-                       case OO.ui.Keys.ESCAPE:
-                               if ( highlightItem ) {
-                                       highlightItem.setHighlighted( false );
-                               }
-                               this.hide();
-                               handled = true;
-                               break;
-               }
+/**
+ * Check if option can be pressed.
+ *
+ * @return {boolean} Item is pressable
+ */
+OO.ui.OptionWidget.prototype.isPressable = function () {
+       return this.constructor.static.pressable && !this.isDisabled();
+};
 
-               if ( nextItem ) {
-                       this.highlightItem( nextItem );
-                       nextItem.scrollElementIntoView();
-               }
+/**
+ * Check if option is selected.
+ *
+ * @return {boolean} Item is selected
+ */
+OO.ui.OptionWidget.prototype.isSelected = function () {
+       return this.selected;
+};
 
-               if ( handled ) {
-                       e.preventDefault();
-                       e.stopPropagation();
-                       return false;
+/**
+ * Check if option is highlighted.
+ *
+ * @return {boolean} Item is highlighted
+ */
+OO.ui.OptionWidget.prototype.isHighlighted = function () {
+       return this.highlighted;
+};
+
+/**
+ * Check if option is pressed.
+ *
+ * @return {boolean} Item is pressed
+ */
+OO.ui.OptionWidget.prototype.isPressed = function () {
+       return this.pressed;
+};
+
+/**
+ * Set selected state.
+ *
+ * @param {boolean} [state=false] Select option
+ * @chainable
+ */
+OO.ui.OptionWidget.prototype.setSelected = function ( state ) {
+       if ( this.constructor.static.selectable ) {
+               this.selected = !!state;
+               this.$element.toggleClass( 'oo-ui-optionWidget-selected', state );
+               if ( state && this.constructor.static.scrollIntoViewOnSelect ) {
+                       this.scrollElementIntoView();
                }
        }
+       return this;
 };
 
 /**
- * Check if the menu is visible.
+ * Set highlighted state.
  *
- * @return {boolean} Menu is visible
+ * @param {boolean} [state=false] Highlight option
+ * @chainable
  */
-OO.ui.MenuWidget.prototype.isVisible = function () {
-       return this.visible;
+OO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
+       if ( this.constructor.static.highlightable ) {
+               this.highlighted = !!state;
+               this.$element.toggleClass( 'oo-ui-optionWidget-highlighted', state );
+       }
+       return this;
 };
 
 /**
- * Bind key down listener.
+ * Set pressed state.
+ *
+ * @param {boolean} [state=false] Press option
+ * @chainable
  */
-OO.ui.MenuWidget.prototype.bindKeyDownListener = function () {
-       if ( this.$input ) {
-               this.$input.on( 'keydown', this.onKeyDownHandler );
-       } else {
-               // Capture menu navigation keys
-               this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
+OO.ui.OptionWidget.prototype.setPressed = function ( state ) {
+       if ( this.constructor.static.pressable ) {
+               this.pressed = !!state;
+               this.$element.toggleClass( 'oo-ui-optionWidget-pressed', state );
+       }
+       return this;
+};
+
+/**
+ * Make the option's highlight flash.
+ *
+ * While flashing, the visual style of the pressed state is removed if present.
+ *
+ * @return {jQuery.Promise} Promise resolved when flashing is done
+ */
+OO.ui.OptionWidget.prototype.flash = function () {
+       var widget = this,
+               $element = this.$element,
+               deferred = $.Deferred();
+
+       if ( !this.isDisabled() && this.constructor.static.pressable ) {
+               $element.removeClass( 'oo-ui-optionWidget-highlighted oo-ui-optionWidget-pressed' );
+               setTimeout( function () {
+                       // Restore original classes
+                       $element
+                               .toggleClass( 'oo-ui-optionWidget-highlighted', widget.highlighted )
+                               .toggleClass( 'oo-ui-optionWidget-pressed', widget.pressed );
+
+                       setTimeout( function () {
+                               deferred.resolve();
+                       }, 100 );
+
+               }, 100 );
        }
+
+       return deferred.promise();
 };
 
 /**
- * Unbind key down listener.
+ * Get option data.
+ *
+ * @return {Mixed} Option data
  */
-OO.ui.MenuWidget.prototype.unbindKeyDownListener = function () {
-       if ( this.$input ) {
-               this.$input.off( 'keydown' );
-       } else {
-               this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
-       }
+OO.ui.OptionWidget.prototype.getData = function () {
+       return this.data;
 };
 
 /**
- * Choose an item.
+ * Option widget with an option icon and indicator.
  *
- * This will close the menu when done, unlike selectItem which only changes selection.
+ * Use together with OO.ui.SelectWidget.
  *
- * @param {OO.ui.OptionWidget} item Item to choose
- * @chainable
+ * @class
+ * @extends OO.ui.OptionWidget
+ * @mixins OO.ui.IconedElement
+ * @mixins OO.ui.IndicatedElement
+ *
+ * @constructor
+ * @param {Mixed} data Option data
+ * @param {Object} [config] Configuration options
  */
-OO.ui.MenuWidget.prototype.chooseItem = function ( item ) {
-       // Parent method
-       OO.ui.MenuWidget.super.prototype.chooseItem.call( this, item );
+OO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( data, config ) {
+       // Parent constructor
+       OO.ui.DecoratedOptionWidget.super.call( this, data, config );
 
-       if ( item && !this.flashing ) {
-               this.flashing = true;
-               item.flash().done( OO.ui.bind( function () {
-                       this.hide();
-                       this.flashing = false;
-               }, this ) );
-       } else {
-               this.hide();
-       }
+       // Mixin constructors
+       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
+       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
 
-       return this;
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-decoratedOptionWidget' )
+               .prepend( this.$icon )
+               .append( this.$indicator );
 };
 
+/* Setup */
+
+OO.inheritClass( OO.ui.DecoratedOptionWidget, OO.ui.OptionWidget );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatedElement );
+
 /**
- * Add items.
+ * Option widget that looks like a button.
  *
- * Adding an existing item (by value) will move it.
+ * Use together with OO.ui.ButtonSelectWidget.
  *
- * @param {OO.ui.MenuItemWidget[]} items Items to add
- * @param {number} [index] Index to insert items after
- * @chainable
+ * @class
+ * @extends OO.ui.DecoratedOptionWidget
+ * @mixins OO.ui.ButtonedElement
+ *
+ * @constructor
+ * @param {Mixed} data Option data
+ * @param {Object} [config] Configuration options
  */
-OO.ui.MenuWidget.prototype.addItems = function ( items, index ) {
-       var i, len, item;
+OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( data, config ) {
+       // Parent constructor
+       OO.ui.ButtonOptionWidget.super.call( this, data, config );
 
-       // Parent method
-       OO.ui.MenuWidget.super.prototype.addItems.call( this, items, index );
+       // Mixin constructors
+       OO.ui.ButtonedElement.call( this, this.$( '<a>' ), config );
 
-       // Auto-initialize
-       if ( !this.newItems ) {
-               this.newItems = [];
-       }
+       // Initialization
+       this.$element.addClass( 'oo-ui-buttonOptionWidget' );
+       this.$button.append( this.$element.contents() );
+       this.$element.append( this.$button );
+};
 
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               if ( this.visible ) {
-                       // Defer fitting label until
-                       item.fitLabel();
-               } else {
-                       this.newItems.push( item );
-               }
+/* Setup */
+
+OO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.DecoratedOptionWidget );
+OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.ButtonedElement );
+
+/* Static Properties */
+
+// Allow button mouse down events to pass through so they can be handled by the parent select widget
+OO.ui.ButtonOptionWidget.static.cancelButtonMouseDownEvents = false;
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {
+       OO.ui.ButtonOptionWidget.super.prototype.setSelected.call( this, state );
+
+       if ( this.constructor.static.selectable ) {
+               this.setActive( state );
        }
 
        return this;
 };
 
 /**
- * Show the menu.
+ * Item of an OO.ui.MenuWidget.
  *
- * @chainable
+ * @class
+ * @extends OO.ui.DecoratedOptionWidget
+ *
+ * @constructor
+ * @param {Mixed} data Item data
+ * @param {Object} [config] Configuration options
  */
-OO.ui.MenuWidget.prototype.show = function () {
-       var i, len;
-
-       if ( this.items.length ) {
-               this.$element.show();
-               this.visible = true;
-               this.bindKeyDownListener();
+OO.ui.MenuItemWidget = function OoUiMenuItemWidget( data, config ) {
+       // Configuration initialization
+       config = $.extend( { 'icon': 'check' }, config );
 
-               // Change focus to enable keyboard navigation
-               if ( this.isolated && this.$input && !this.$input.is( ':focus' ) ) {
-                       this.$previousFocus = this.$( ':focus' );
-                       this.$input.focus();
-               }
-               if ( this.newItems && this.newItems.length ) {
-                       for ( i = 0, len = this.newItems.length; i < len; i++ ) {
-                               this.newItems[i].fitLabel();
-                       }
-                       this.newItems = null;
-               }
+       // Parent constructor
+       OO.ui.MenuItemWidget.super.call( this, data, config );
 
-               this.setClipping( true );
+       // Initialization
+       this.$element
+               .attr( 'role', 'menuitem' )
+               .addClass( 'oo-ui-menuItemWidget' );
+};
 
-               // Auto-hide
-               if ( this.autoHide ) {
-                       this.getElementDocument().addEventListener(
-                               'mousedown', this.onDocumentMouseDownHandler, true
-                       );
-               }
-       }
+/* Setup */
 
-       return this;
-};
+OO.inheritClass( OO.ui.MenuItemWidget, OO.ui.DecoratedOptionWidget );
 
 /**
- * Hide the menu.
+ * Section to group one or more items in a OO.ui.MenuWidget.
  *
- * @chainable
+ * @class
+ * @extends OO.ui.DecoratedOptionWidget
+ *
+ * @constructor
+ * @param {Mixed} data Item data
+ * @param {Object} [config] Configuration options
  */
-OO.ui.MenuWidget.prototype.hide = function () {
-       this.$element.hide();
-       this.visible = false;
-       this.unbindKeyDownListener();
+OO.ui.MenuSectionItemWidget = function OoUiMenuSectionItemWidget( data, config ) {
+       // Parent constructor
+       OO.ui.MenuSectionItemWidget.super.call( this, data, config );
 
-       if ( this.isolated && this.$previousFocus ) {
-               this.$previousFocus.focus();
-               this.$previousFocus = null;
-       }
+       // Initialization
+       this.$element.addClass( 'oo-ui-menuSectionItemWidget' );
+};
 
-       this.getElementDocument().removeEventListener(
-               'mousedown', this.onDocumentMouseDownHandler, true
-       );
+/* Setup */
 
-       this.setClipping( false );
+OO.inheritClass( OO.ui.MenuSectionItemWidget, OO.ui.DecoratedOptionWidget );
 
-       return this;
-};
+/* Static Properties */
+
+OO.ui.MenuSectionItemWidget.static.selectable = false;
+
+OO.ui.MenuSectionItemWidget.static.highlightable = false;
 
 /**
- * Inline menu of options.
- *
- * Use with OO.ui.MenuOptionWidget.
+ * Items for an OO.ui.OutlineWidget.
  *
  * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconedElement
- * @mixins OO.ui.IndicatedElement
- * @mixins OO.ui.LabeledElement
- * @mixins OO.ui.TitledElement
+ * @extends OO.ui.DecoratedOptionWidget
  *
  * @constructor
+ * @param {Mixed} data Item data
  * @param {Object} [config] Configuration options
- * @cfg {Object} [menu] Configuration options to pass to menu widget
+ * @cfg {number} [level] Indentation level
+ * @cfg {boolean} [movable] Allow modification from outline controls
  */
-OO.ui.InlineMenuWidget = function OoUiInlineMenuWidget( config ) {
-       // Configuration initialization
-       config = $.extend( { 'indicator': 'down' }, config );
+OO.ui.OutlineItemWidget = function OoUiOutlineItemWidget( data, config ) {
+       // Config intialization
+       config = config || {};
 
        // Parent constructor
-       OO.ui.InlineMenuWidget.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
-       OO.ui.TitledElement.call( this, this.$label, config );
+       OO.ui.OutlineItemWidget.super.call( this, data, config );
 
        // Properties
-       this.menu = new OO.ui.MenuWidget( $.extend( { '$': this.$ }, config.menu ) );
-       this.$handle = this.$( '<span>' );
-
-       // Events
-       this.$element.on( { 'click': OO.ui.bind( this.onClick, this ) } );
-       this.menu.connect( this, { 'select': 'onMenuSelect' } );
+       this.level = 0;
+       this.movable = !!config.movable;
+       this.removable = !!config.removable;
 
        // Initialization
-       this.$handle
-               .addClass( 'oo-ui-inlineMenuWidget-handle' )
-               .append( this.$icon, this.$label, this.$indicator );
-       this.$element
-               .addClass( 'oo-ui-inlineMenuWidget' )
-               .append( this.$handle, this.menu.$element );
+       this.$element.addClass( 'oo-ui-outlineItemWidget' );
+       this.setLevel( config.level );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.InlineMenuWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.IconedElement );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.IndicatedElement );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.LabeledElement );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.TitledElement );
+OO.inheritClass( OO.ui.OutlineItemWidget, OO.ui.DecoratedOptionWidget );
+
+/* Static Properties */
+
+OO.ui.OutlineItemWidget.static.highlightable = false;
+
+OO.ui.OutlineItemWidget.static.scrollIntoViewOnSelect = true;
+
+OO.ui.OutlineItemWidget.static.levelClass = 'oo-ui-outlineItemWidget-level-';
+
+OO.ui.OutlineItemWidget.static.levels = 3;
 
 /* Methods */
 
 /**
- * Get the menu.
+ * Check if item is movable.
  *
- * @return {OO.ui.MenuWidget} Menu of widget
+ * Movablilty is used by outline controls.
+ *
+ * @return {boolean} Item is movable
  */
-OO.ui.InlineMenuWidget.prototype.getMenu = function () {
-       return this.menu;
+OO.ui.OutlineItemWidget.prototype.isMovable = function () {
+       return this.movable;
 };
 
 /**
- * Handles menu select events.
+ * Check if item is removable.
  *
- * @param {OO.ui.MenuItemWidget} item Selected menu item
+ * Removablilty is used by outline controls.
+ *
+ * @return {boolean} Item is removable
  */
-OO.ui.InlineMenuWidget.prototype.onMenuSelect = function ( item ) {
-       var selectedLabel;
-
-       if ( !item ) {
-               return;
-       }
-
-       selectedLabel = item.getLabel();
-
-       // If the label is a DOM element, clone it, because setLabel will append() it
-       if ( selectedLabel instanceof jQuery ) {
-               selectedLabel = selectedLabel.clone();
-       }
+OO.ui.OutlineItemWidget.prototype.isRemovable = function () {
+       return this.removable;
+};
 
-       this.setLabel( selectedLabel );
+/**
+ * Get indentation level.
+ *
+ * @return {number} Indentation level
+ */
+OO.ui.OutlineItemWidget.prototype.getLevel = function () {
+       return this.level;
 };
 
 /**
- * Handles mouse click events.
+ * Set movability.
  *
- * @param {jQuery.Event} e Mouse click event
+ * Movablilty is used by outline controls.
+ *
+ * @param {boolean} movable Item is movable
+ * @chainable
  */
-OO.ui.InlineMenuWidget.prototype.onClick = function ( e ) {
-       // Skip clicks within the menu
-       if ( $.contains( this.menu.$element[0], e.target ) ) {
-               return;
-       }
-
-       if ( !this.isDisabled() ) {
-               if ( this.menu.isVisible() ) {
-                       this.menu.hide();
-               } else {
-                       this.menu.show();
-               }
-       }
-       return false;
+OO.ui.OutlineItemWidget.prototype.setMovable = function ( movable ) {
+       this.movable = !!movable;
+       return this;
 };
 
 /**
- * Menu section item widget.
- *
- * Use with OO.ui.MenuWidget.
+ * Set removability.
  *
- * @class
- * @extends OO.ui.OptionWidget
+ * Removablilty is used by outline controls.
  *
- * @constructor
- * @param {Mixed} data Item data
- * @param {Object} [config] Configuration options
+ * @param {boolean} movable Item is removable
+ * @chainable
  */
-OO.ui.MenuSectionItemWidget = function OoUiMenuSectionItemWidget( data, config ) {
-       // Parent constructor
-       OO.ui.MenuSectionItemWidget.super.call( this, data, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-menuSectionItemWidget' );
+OO.ui.OutlineItemWidget.prototype.setRemovable = function ( removable ) {
+       this.removable = !!removable;
+       return this;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.MenuSectionItemWidget, OO.ui.OptionWidget );
-
-/* Static Properties */
-
-OO.ui.MenuSectionItemWidget.static.selectable = false;
-
-OO.ui.MenuSectionItemWidget.static.highlightable = false;
-
 /**
- * Create an OO.ui.OutlineWidget object.
- *
- * Use with OO.ui.OutlineItemWidget.
- *
- * @class
- * @extends OO.ui.SelectWidget
+ * Set indentation level.
  *
- * @constructor
- * @param {Object} [config] Configuration options
+ * @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]
+ * @chainable
  */
-OO.ui.OutlineWidget = function OoUiOutlineWidget( config ) {
-       // Config intialization
-       config = config || {};
+OO.ui.OutlineItemWidget.prototype.setLevel = function ( level ) {
+       var levels = this.constructor.static.levels,
+               levelClass = this.constructor.static.levelClass,
+               i = levels;
 
-       // Parent constructor
-       OO.ui.OutlineWidget.super.call( this, config );
+       this.level = level ? Math.max( 0, Math.min( levels - 1, level ) ) : 0;
+       while ( i-- ) {
+               if ( this.level === i ) {
+                       this.$element.addClass( levelClass + i );
+               } else {
+                       this.$element.removeClass( levelClass + i );
+               }
+       }
 
-       // Initialization
-       this.$element.addClass( 'oo-ui-outlineWidget' );
+       return this;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.OutlineWidget, OO.ui.SelectWidget );
-
 /**
- * Creates an OO.ui.OutlineControlsWidget object.
- *
- * Use together with OO.ui.OutlineWidget.js
+ * Container for content that is overlaid and positioned absolutely.
  *
  * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.LabeledElement
  *
  * @constructor
- * @param {OO.ui.OutlineWidget} outline Outline to control
  * @param {Object} [config] Configuration options
+ * @cfg {number} [width=320] Width of popup in pixels
+ * @cfg {number} [height] Height of popup, omit to use automatic height
+ * @cfg {boolean} [anchor=true] Show anchor pointing to origin of popup
+ * @cfg {string} [align='center'] Alignment of popup to origin
+ * @cfg {jQuery} [$container] Container to prevent popup from rendering outside of
+ * @cfg {jQuery} [$content] Content to append to the popup's body
+ * @cfg {boolean} [autoClose=false] Popup auto-closes when it loses focus
+ * @cfg {jQuery} [$autoCloseIgnore] Elements to not auto close when clicked
+ * @cfg {boolean} [head] Show label and close button at the top
+ * @cfg {boolean} [padded] Add padding to the body
  */
-OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {
-       // Configuration initialization
-       config = $.extend( { 'icon': 'add-item' }, config );
+OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
+       // Config intialization
+       config = config || {};
 
        // Parent constructor
-       OO.ui.OutlineControlsWidget.super.call( this, config );
+       OO.ui.PopupWidget.super.call( this, config );
 
        // Mixin constructors
-       OO.ui.GroupElement.call( this, this.$( '<div>' ), config );
-       OO.ui.IconedElement.call( this, this.$( '<div>' ), config );
+       OO.ui.LabeledElement.call( this, this.$( '<div>' ), config );
+       OO.ui.ClippableElement.call( this, this.$( '<div>' ), config );
 
        // Properties
-       this.outline = outline;
-       this.$movers = this.$( '<div>' );
-       this.upButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'collapse',
-               'title': OO.ui.msg( 'ooui-outline-control-move-up' )
-       } );
-       this.downButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'expand',
-               'title': OO.ui.msg( 'ooui-outline-control-move-down' )
-       } );
-       this.removeButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'remove',
-               'title': OO.ui.msg( 'ooui-outline-control-remove' )
-       } );
+       this.visible = false;
+       this.$popup = this.$( '<div>' );
+       this.$head = this.$( '<div>' );
+       this.$body = this.$clippable;
+       this.$anchor = this.$( '<div>' );
+       this.$container = config.$container || this.$( 'body' );
+       this.autoClose = !!config.autoClose;
+       this.$autoCloseIgnore = config.$autoCloseIgnore;
+       this.transitionTimeout = null;
+       this.anchor = null;
+       this.width = config.width !== undefined ? config.width : 320;
+       this.height = config.height !== undefined ? config.height : null;
+       this.align = config.align || 'center';
+       this.closeButton = new OO.ui.ButtonWidget( { '$': this.$, 'framed': false, 'icon': 'close' } );
+       this.onMouseDownHandler = OO.ui.bind( this.onMouseDown, this );
 
        // Events
-       outline.connect( this, {
-               'select': 'onOutlineChange',
-               'add': 'onOutlineChange',
-               'remove': 'onOutlineChange'
-       } );
-       this.upButton.connect( this, { 'click': [ 'emit', 'move', -1 ] } );
-       this.downButton.connect( this, { 'click': [ 'emit', 'move', 1 ] } );
-       this.removeButton.connect( this, { 'click': [ 'emit', 'remove' ] } );
+       this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-outlineControlsWidget' );
-       this.$group.addClass( 'oo-ui-outlineControlsWidget-items' );
-       this.$movers
-               .addClass( 'oo-ui-outlineControlsWidget-movers' )
-               .append( this.removeButton.$element, this.upButton.$element, this.downButton.$element );
-       this.$element.append( this.$icon, this.$group, this.$movers );
+       this.toggleAnchor( config.anchor === undefined || config.anchor );
+       this.$body.addClass( 'oo-ui-popupWidget-body' );
+       this.$anchor.addClass( 'oo-ui-popupWidget-anchor' );
+       this.$head
+               .addClass( 'oo-ui-popupWidget-head' )
+               .append( this.$label, this.closeButton.$element );
+       if ( !config.head ) {
+               this.$head.hide();
+       }
+       this.$popup
+               .addClass( 'oo-ui-popupWidget-popup' )
+               .append( this.$head, this.$body );
+       this.$element
+               .hide()
+               .addClass( 'oo-ui-popupWidget' )
+               .append( this.$popup, this.$anchor );
+       // Move content, which was added to #$element by OO.ui.Widget, to the body
+       if ( config.$content instanceof jQuery ) {
+               this.$body.append( config.$content );
+       }
+       if ( config.padded ) {
+               this.$body.addClass( 'oo-ui-popupWidget-body-padded' );
+       }
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.GroupElement );
-OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.IconedElement );
+OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabeledElement );
+OO.mixinClass( OO.ui.PopupWidget, OO.ui.ClippableElement );
 
 /* Events */
 
 /**
- * @event move
- * @param {number} places Number of places to move
+ * @event hide
  */
 
 /**
- * @event remove
+ * @event show
  */
 
 /* Methods */
 
 /**
- * Handle outline change events.
+ * Handles mouse down events.
+ *
+ * @param {jQuery.Event} e Mouse down event
  */
-OO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {
-       var i, len, firstMovable, lastMovable,
-               items = this.outline.getItems(),
-               selectedItem = this.outline.getSelectedItem(),
-               movable = selectedItem && selectedItem.isMovable(),
-               removable = selectedItem && selectedItem.isRemovable();
-
-       if ( movable ) {
-               i = -1;
-               len = items.length;
-               while ( ++i < len ) {
-                       if ( items[i].isMovable() ) {
-                               firstMovable = items[i];
-                               break;
-                       }
-               }
-               i = len;
-               while ( i-- ) {
-                       if ( items[i].isMovable() ) {
-                               lastMovable = items[i];
-                               break;
-                       }
-               }
+OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
+       if (
+               this.isVisible() &&
+               !$.contains( this.$element[0], e.target ) &&
+               ( !this.$autoCloseIgnore || !this.$autoCloseIgnore.has( e.target ).length )
+       ) {
+               this.toggle( false );
        }
-       this.upButton.setDisabled( !movable || selectedItem === firstMovable );
-       this.downButton.setDisabled( !movable || selectedItem === lastMovable );
-       this.removeButton.setDisabled( !removable );
 };
 
 /**
- * Creates an OO.ui.OutlineItemWidget object.
- *
- * Use with OO.ui.OutlineWidget.
- *
- * @class
- * @extends OO.ui.OptionWidget
- *
- * @constructor
- * @param {Mixed} data Item data
- * @param {Object} [config] Configuration options
- * @cfg {number} [level] Indentation level
- * @cfg {boolean} [movable] Allow modification from outline controls
+ * Bind mouse down listener.
  */
-OO.ui.OutlineItemWidget = function OoUiOutlineItemWidget( data, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.OutlineItemWidget.super.call( this, data, config );
-
-       // Properties
-       this.level = 0;
-       this.movable = !!config.movable;
-       this.removable = !!config.removable;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-outlineItemWidget' );
-       this.setLevel( config.level );
+OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
+       // Capture clicks outside popup
+       this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true );
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.OutlineItemWidget, OO.ui.OptionWidget );
-
-/* Static Properties */
-
-OO.ui.OutlineItemWidget.static.highlightable = false;
-
-OO.ui.OutlineItemWidget.static.scrollIntoViewOnSelect = true;
-
-OO.ui.OutlineItemWidget.static.levelClass = 'oo-ui-outlineItemWidget-level-';
-
-OO.ui.OutlineItemWidget.static.levels = 3;
-
-/* Methods */
+/**
+ * Handles close button click events.
+ */
+OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
+       if ( this.isVisible() ) {
+               this.toggle( false );
+       }
+};
 
 /**
- * Check if item is movable.
- *
- * Movablilty is used by outline controls.
- *
- * @return {boolean} Item is movable
+ * Unbind mouse down listener.
  */
-OO.ui.OutlineItemWidget.prototype.isMovable = function () {
-       return this.movable;
+OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
+       this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
 };
 
 /**
- * Check if item is removable.
- *
- * Removablilty is used by outline controls.
+ * Set whether to show a anchor.
  *
- * @return {boolean} Item is removable
+ * @param {boolean} [show] Show anchor, omit to toggle
  */
-OO.ui.OutlineItemWidget.prototype.isRemovable = function () {
-       return this.removable;
+OO.ui.PopupWidget.prototype.toggleAnchor = function ( show ) {
+       show = show === undefined ? !this.anchored : !!show;
+
+       if ( this.anchored !== show ) {
+               if ( show ) {
+                       this.$element.addClass( 'oo-ui-popupWidget-anchored' );
+               } else {
+                       this.$element.removeClass( 'oo-ui-popupWidget-anchored' );
+               }
+               this.anchored = show;
+       }
 };
 
 /**
- * Get indentation level.
+ * Check if showing a anchor.
  *
- * @return {number} Indentation level
+ * @return {boolean} anchor is visible
  */
-OO.ui.OutlineItemWidget.prototype.getLevel = function () {
-       return this.level;
+OO.ui.PopupWidget.prototype.hasAnchor = function () {
+       return this.anchor;
 };
 
 /**
- * Set movability.
- *
- * Movablilty is used by outline controls.
- *
- * @param {boolean} movable Item is movable
- * @chainable
+ * @inheritdoc
  */
-OO.ui.OutlineItemWidget.prototype.setMovable = function ( movable ) {
-       this.movable = !!movable;
+OO.ui.PopupWidget.prototype.toggle = function ( show ) {
+       show = show === undefined ? !this.isVisible() : !!show;
+
+       var change = show !== this.isVisible();
+
+       // Parent method
+       OO.ui.PopupWidget.super.prototype.toggle.call( this, show );
+
+       if ( change ) {
+               if ( show ) {
+                       this.setClipping( true );
+                       if ( this.autoClose ) {
+                               this.bindMouseDownListener();
+                       }
+                       this.updateDimensions();
+               } else {
+                       this.setClipping( false );
+                       if ( this.autoClose ) {
+                               this.unbindMouseDownListener();
+                       }
+               }
+       }
+
        return this;
 };
 
 /**
- * Set removability.
+ * Set the size of the popup.
  *
- * Removablilty is used by outline controls.
+ * Changing the size may also change the popup's position depending on the alignment.
  *
- * @param {boolean} movable Item is removable
+ * @param {number} width Width
+ * @param {number} height Height
+ * @param {boolean} [transition=false] Use a smooth transition
  * @chainable
  */
-OO.ui.OutlineItemWidget.prototype.setRemovable = function ( removable ) {
-       this.removable = !!removable;
-       return this;
+OO.ui.PopupWidget.prototype.setSize = function ( width, height, transition ) {
+       this.width = width;
+       this.height = height !== undefined ? height : null;
+       if ( this.isVisible() ) {
+               this.updateDimensions( transition );
+       }
 };
 
 /**
- * Set indentation level.
+ * Update the size and position.
  *
- * @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]
+ * Only use this to keep the popup properly anchored. Use #setSize to change the size, and this will
+ * be called automatically.
+ *
+ * @param {boolean} [transition=false] Use a smooth transition
  * @chainable
  */
-OO.ui.OutlineItemWidget.prototype.setLevel = function ( level ) {
-       var levels = this.constructor.static.levels,
-               levelClass = this.constructor.static.levelClass,
-               i = levels;
+OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
+       var widget = this,
+               padding = 10,
+               originOffset = Math.round( this.$element.offset().left ),
+               containerLeft = Math.round( this.$container.offset().left ),
+               containerWidth = this.$container.innerWidth(),
+               containerRight = containerLeft + containerWidth,
+               popupOffset = this.width * ( { 'left': 0, 'center': -0.5, 'right': -1 } )[this.align],
+               anchorWidth = this.$anchor.width(),
+               popupLeft = popupOffset - padding,
+               popupRight = popupOffset + padding + this.width + padding,
+               overlapLeft = ( originOffset + popupLeft ) - containerLeft,
+               overlapRight = containerRight - ( originOffset + popupRight );
 
-       this.level = level ? Math.max( 0, Math.min( levels - 1, level ) ) : 0;
-       while ( i-- ) {
-               if ( this.level === i ) {
-                       this.$element.addClass( levelClass + i );
-               } else {
-                       this.$element.removeClass( levelClass + i );
-               }
+       // Prevent transition from being interrupted
+       clearTimeout( this.transitionTimeout );
+       if ( transition ) {
+               // Enable transition
+               this.$element.addClass( 'oo-ui-popupWidget-transitioning' );
+       }
+
+       if ( overlapRight < 0 ) {
+               popupOffset += overlapRight;
+       } else if ( overlapLeft < 0 ) {
+               popupOffset -= overlapLeft;
+       }
+
+       // Adjust offset to avoid anchor being rendered too close to the edge
+       if ( this.align === 'right' ) {
+               popupOffset += anchorWidth;
+       } else if ( this.align === 'left' ) {
+               popupOffset -= anchorWidth;
+       }
+
+       // Position body relative to anchor and resize
+       this.$popup.css( {
+               'left': popupOffset,
+               'width': this.width,
+               'height': this.height !== null ? this.height : 'auto'
+       } );
+
+       if ( transition ) {
+               // Prevent transitioning after transition is complete
+               this.transitionTimeout = setTimeout( function () {
+                       widget.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
+               }, 200 );
+       } else {
+               // Prevent transitioning immediately
+               this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
        }
 
        return this;
 };
 
 /**
- * Option widget that looks like a button.
+ * Search widget.
  *
- * Use together with OO.ui.ButtonSelectWidget.
+ * Search widgets combine a query input, placed above, and a results selection widget, placed below.
+ * Results are cleared and populated each time the query is changed.
  *
  * @class
- * @extends OO.ui.OptionWidget
- * @mixins OO.ui.ButtonedElement
- * @mixins OO.ui.FlaggableElement
+ * @extends OO.ui.Widget
  *
  * @constructor
- * @param {Mixed} data Option data
  * @param {Object} [config] Configuration options
+ * @cfg {string|jQuery} [placeholder] Placeholder text for query input
+ * @cfg {string} [value] Initial query value
  */
-OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( data, config ) {
+OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
+       // Configuration intialization
+       config = config || {};
+
        // Parent constructor
-       OO.ui.ButtonOptionWidget.super.call( this, data, config );
+       OO.ui.SearchWidget.super.call( this, config );
 
-       // Mixin constructors
-       OO.ui.ButtonedElement.call( this, this.$( '<a>' ), config );
-       OO.ui.FlaggableElement.call( this, config );
+       // Properties
+       this.query = new OO.ui.TextInputWidget( {
+               '$': this.$,
+               'icon': 'search',
+               'placeholder': config.placeholder,
+               'value': config.value
+       } );
+       this.results = new OO.ui.SelectWidget( { '$': this.$ } );
+       this.$query = this.$( '<div>' );
+       this.$results = this.$( '<div>' );
+
+       // Events
+       this.query.connect( this, {
+               'change': 'onQueryChange',
+               'enter': 'onQueryEnter'
+       } );
+       this.results.connect( this, {
+               'highlight': 'onResultsHighlight',
+               'select': 'onResultsSelect'
+       } );
+       this.query.$input.on( 'keydown', OO.ui.bind( this.onQueryKeydown, this ) );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-buttonOptionWidget' );
-       this.$button.append( this.$element.contents() );
-       this.$element.append( this.$button );
+       this.$query
+               .addClass( 'oo-ui-searchWidget-query' )
+               .append( this.query.$element );
+       this.$results
+               .addClass( 'oo-ui-searchWidget-results' )
+               .append( this.results.$element );
+       this.$element
+               .addClass( 'oo-ui-searchWidget' )
+               .append( this.$results, this.$query );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.OptionWidget );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.ButtonedElement );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.FlaggableElement );
+OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
 
-/* Static Properties */
+/* Events */
 
-// Allow button mouse down events to pass through so they can be handled by the parent select widget
-OO.ui.ButtonOptionWidget.static.cancelButtonMouseDownEvents = false;
+/**
+ * @event highlight
+ * @param {Object|null} item Item data or null if no item is highlighted
+ */
+
+/**
+ * @event select
+ * @param {Object|null} item Item data or null if no item is selected
+ */
 
 /* Methods */
 
 /**
- * @inheritdoc
+ * Handle query key down events.
+ *
+ * @param {jQuery.Event} e Key down event
  */
-OO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {
-       OO.ui.ButtonOptionWidget.super.prototype.setSelected.call( this, state );
+OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
+       var highlightedItem, nextItem,
+               dir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );
 
-       if ( this.constructor.static.selectable ) {
-               this.setActive( state );
+       if ( dir ) {
+               highlightedItem = this.results.getHighlightedItem();
+               if ( !highlightedItem ) {
+                       highlightedItem = this.results.getSelectedItem();
+               }
+               nextItem = this.results.getRelativeSelectableItem( highlightedItem, dir );
+               this.results.highlightItem( nextItem );
+               nextItem.scrollElementIntoView();
        }
+};
 
-       return this;
+/**
+ * Handle select widget select events.
+ *
+ * Clears existing results. Subclasses should repopulate items according to new query.
+ *
+ * @param {string} value New value
+ */
+OO.ui.SearchWidget.prototype.onQueryChange = function () {
+       // Reset
+       this.results.clearItems();
 };
 
 /**
- * Select widget containing button options.
+ * Handle select widget enter key events.
  *
- * Use together with OO.ui.ButtonOptionWidget.
+ * Selects highlighted item.
  *
- * @class
- * @extends OO.ui.SelectWidget
+ * @param {string} value New value
+ */
+OO.ui.SearchWidget.prototype.onQueryEnter = function () {
+       // Reset
+       this.results.selectItem( this.results.getHighlightedItem() );
+};
+
+/**
+ * Handle select widget highlight events.
  *
- * @constructor
- * @param {Object} [config] Configuration options
+ * @param {OO.ui.OptionWidget} item Highlighted item
+ * @fires highlight
  */
-OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
-       // Parent constructor
-       OO.ui.ButtonSelectWidget.super.call( this, config );
+OO.ui.SearchWidget.prototype.onResultsHighlight = function ( item ) {
+       this.emit( 'highlight', item ? item.getData() : null );
+};
 
-       // Initialization
-       this.$element.addClass( 'oo-ui-buttonSelectWidget' );
+/**
+ * Handle select widget select events.
+ *
+ * @param {OO.ui.OptionWidget} item Selected item
+ * @fires select
+ */
+OO.ui.SearchWidget.prototype.onResultsSelect = function ( item ) {
+       this.emit( 'select', item ? item.getData() : null );
+};
+
+/**
+ * Get the query input.
+ *
+ * @return {OO.ui.TextInputWidget} Query input
+ */
+OO.ui.SearchWidget.prototype.getQuery = function () {
+       return this.query;
+};
+
+/**
+ * Get the results list.
+ *
+ * @return {OO.ui.SelectWidget} Select list
+ */
+OO.ui.SearchWidget.prototype.getResults = function () {
+       return this.results;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );
-
 /**
- * Container for content that is overlaid and positioned absolutely.
+ * Generic selection of options.
+ *
+ * Items can contain any rendering, and are uniquely identified by a has of thier data. Any widget
+ * that provides options, from which the user must choose one, should be built on this class.
+ *
+ * Use together with OO.ui.OptionWidget.
  *
  * @class
  * @extends OO.ui.Widget
- * @mixins OO.ui.LabeledElement
+ * @mixins OO.ui.GroupElement
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {boolean} [tail=true] Show tail pointing to origin of popup
- * @cfg {string} [align='center'] Alignment of popup to origin
- * @cfg {jQuery} [$container] Container to prevent popup from rendering outside of
- * @cfg {boolean} [autoClose=false] Popup auto-closes when it loses focus
- * @cfg {jQuery} [$autoCloseIgnore] Elements to not auto close when clicked
- * @cfg {boolean} [head] Show label and close button at the top
+ * @cfg {OO.ui.OptionWidget[]} [items] Options to add
  */
-OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
+OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
        // Config intialization
        config = config || {};
 
        // Parent constructor
-       OO.ui.PopupWidget.super.call( this, config );
+       OO.ui.SelectWidget.super.call( this, config );
 
        // Mixin constructors
-       OO.ui.LabeledElement.call( this, this.$( '<div>' ), config );
-       OO.ui.ClippableElement.call( this, this.$( '<div>' ), config );
+       OO.ui.GroupWidget.call( this, this.$element, config );
 
        // Properties
-       this.visible = false;
-       this.$popup = this.$( '<div>' );
-       this.$head = this.$( '<div>' );
-       this.$body = this.$clippable;
-       this.$tail = this.$( '<div>' );
-       this.$container = config.$container || this.$( 'body' );
-       this.autoClose = !!config.autoClose;
-       this.$autoCloseIgnore = config.$autoCloseIgnore;
-       this.transitionTimeout = null;
-       this.tail = false;
-       this.align = config.align || 'center';
-       this.closeButton = new OO.ui.ButtonWidget( { '$': this.$, 'frameless': true, 'icon': 'close' } );
-       this.onMouseDownHandler = OO.ui.bind( this.onMouseDown, this );
+       this.pressed = false;
+       this.selecting = null;
+       this.hashes = {};
+       this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
+       this.onMouseMoveHandler = OO.ui.bind( this.onMouseMove, this );
 
        // Events
-       this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
+       this.$element.on( {
+               'mousedown': OO.ui.bind( this.onMouseDown, this ),
+               'mouseover': OO.ui.bind( this.onMouseOver, this ),
+               'mouseleave': OO.ui.bind( this.onMouseLeave, this )
+       } );
 
        // Initialization
-       this.useTail( config.tail !== undefined ? !!config.tail : true );
-       this.$body.addClass( 'oo-ui-popupWidget-body' );
-       this.$tail.addClass( 'oo-ui-popupWidget-tail' );
-       this.$head
-               .addClass( 'oo-ui-popupWidget-head' )
-               .append( this.$label, this.closeButton.$element );
-       if ( !config.head ) {
-               this.$head.hide();
+       this.$element.addClass( 'oo-ui-selectWidget oo-ui-selectWidget-depressed' );
+       if ( $.isArray( config.items ) ) {
+               this.addItems( config.items );
        }
-       this.$popup
-               .addClass( 'oo-ui-popupWidget-popup' )
-               .append( this.$head, this.$body );
-       this.$element.hide()
-               .addClass( 'oo-ui-popupWidget' )
-               .append( this.$popup, this.$tail );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabeledElement );
-OO.mixinClass( OO.ui.PopupWidget, OO.ui.ClippableElement );
+OO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );
+
+// Need to mixin base class as well
+OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupWidget );
 
 /* Events */
 
 /**
- * @event hide
+ * @event highlight
+ * @param {OO.ui.OptionWidget|null} item Highlighted item
  */
 
 /**
- * @event show
+ * @event press
+ * @param {OO.ui.OptionWidget|null} item Pressed item
+ */
+
+/**
+ * @event select
+ * @param {OO.ui.OptionWidget|null} item Selected item
+ */
+
+/**
+ * @event choose
+ * @param {OO.ui.OptionWidget|null} item Chosen item
+ */
+
+/**
+ * @event add
+ * @param {OO.ui.OptionWidget[]} items Added items
+ * @param {number} index Index items were added at
  */
 
+/**
+ * @event remove
+ * @param {OO.ui.OptionWidget[]} items Removed items
+ */
+
+/* Static Properties */
+
+OO.ui.SelectWidget.static.tagName = 'ul';
+
 /* Methods */
 
 /**
- * Handles mouse down events.
+ * Handle mouse down events.
  *
+ * @private
  * @param {jQuery.Event} e Mouse down event
  */
-OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
-       if (
-               this.visible &&
-               !$.contains( this.$element[0], e.target ) &&
-               ( !this.$autoCloseIgnore || !this.$autoCloseIgnore.has( e.target ).length )
-       ) {
-               this.hide();
+OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
+       var item;
+
+       if ( !this.isDisabled() && e.which === 1 ) {
+               this.togglePressed( true );
+               item = this.getTargetItem( e );
+               if ( item && item.isSelectable() ) {
+                       this.pressItem( item );
+                       this.selecting = item;
+                       this.getElementDocument().addEventListener(
+                               'mouseup',
+                               this.onMouseUpHandler,
+                               true
+                       );
+                       this.getElementDocument().addEventListener(
+                               'mousemove',
+                               this.onMouseMoveHandler,
+                               true
+                       );
+               }
        }
+       return false;
 };
 
 /**
- * Bind mouse down listener.
+ * Handle mouse up events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse up event
  */
-OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
-       // Capture clicks outside popup
-       this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true );
+OO.ui.SelectWidget.prototype.onMouseUp = function ( e ) {
+       var item;
+
+       this.togglePressed( false );
+       if ( !this.selecting ) {
+               item = this.getTargetItem( e );
+               if ( item && item.isSelectable() ) {
+                       this.selecting = item;
+               }
+       }
+       if ( !this.isDisabled() && e.which === 1 && this.selecting ) {
+               this.pressItem( null );
+               this.chooseItem( this.selecting );
+               this.selecting = null;
+       }
+
+       this.getElementDocument().removeEventListener(
+               'mouseup',
+               this.onMouseUpHandler,
+               true
+       );
+       this.getElementDocument().removeEventListener(
+               'mousemove',
+               this.onMouseMoveHandler,
+               true
+       );
+
+       return false;
 };
 
 /**
- * Handles close button click events.
+ * Handle mouse move events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse move event
  */
-OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
-       if ( this.visible ) {
-               this.hide();
+OO.ui.SelectWidget.prototype.onMouseMove = function ( e ) {
+       var item;
+
+       if ( !this.isDisabled() && this.pressed ) {
+               item = this.getTargetItem( e );
+               if ( item && item !== this.selecting && item.isSelectable() ) {
+                       this.pressItem( item );
+                       this.selecting = item;
+               }
        }
+       return false;
 };
 
 /**
- * Unbind mouse down listener.
+ * Handle mouse over events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse over event
  */
-OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
-       this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
+OO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {
+       var item;
+
+       if ( !this.isDisabled() ) {
+               item = this.getTargetItem( e );
+               this.highlightItem( item && item.isHighlightable() ? item : null );
+       }
+       return false;
 };
 
 /**
- * Check if the popup is visible.
+ * Handle mouse leave events.
  *
- * @return {boolean} Popup is visible
+ * @private
+ * @param {jQuery.Event} e Mouse over event
  */
-OO.ui.PopupWidget.prototype.isVisible = function () {
-       return this.visible;
+OO.ui.SelectWidget.prototype.onMouseLeave = function () {
+       if ( !this.isDisabled() ) {
+               this.highlightItem( null );
+       }
+       return false;
+};
+
+/**
+ * Get the closest item to a jQuery.Event.
+ *
+ * @private
+ * @param {jQuery.Event} e
+ * @return {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found
+ */
+OO.ui.SelectWidget.prototype.getTargetItem = function ( e ) {
+       var $item = this.$( e.target ).closest( '.oo-ui-optionWidget' );
+       if ( $item.length ) {
+               return $item.data( 'oo-ui-optionWidget' );
+       }
+       return null;
 };
 
 /**
- * Set whether to show a tail.
+ * Get selected item.
  *
- * @return {boolean} Make tail visible
+ * @return {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected
  */
-OO.ui.PopupWidget.prototype.useTail = function ( value ) {
-       value = !!value;
-       if ( this.tail !== value ) {
-               this.tail = value;
-               if ( value ) {
-                       this.$element.addClass( 'oo-ui-popupWidget-tailed' );
-               } else {
-                       this.$element.removeClass( 'oo-ui-popupWidget-tailed' );
+OO.ui.SelectWidget.prototype.getSelectedItem = 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;
+};
+
+/**
+ * Get highlighted item.
+ *
+ * @return {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted
+ */
+OO.ui.SelectWidget.prototype.getHighlightedItem = function () {
+       var i, len;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               if ( this.items[i].isHighlighted() ) {
+                       return this.items[i];
                }
        }
+       return null;
+};
+
+/**
+ * Get an existing item with equivilant data.
+ *
+ * @param {Object} data Item data to search for
+ * @return {OO.ui.OptionWidget|null} Item with equivilent value, `null` if none exists
+ */
+OO.ui.SelectWidget.prototype.getItemFromData = function ( data ) {
+       var hash = OO.getHash( data );
+
+       if ( hash in this.hashes ) {
+               return this.hashes[hash];
+       }
+
+       return null;
 };
 
 /**
- * Check if showing a tail.
+ * Toggle pressed state.
  *
- * @return {boolean} tail is visible
+ * @param {boolean} pressed An option is being pressed
  */
-OO.ui.PopupWidget.prototype.hasTail = function () {
-       return this.tail;
+OO.ui.SelectWidget.prototype.togglePressed = function ( pressed ) {
+       if ( pressed === undefined ) {
+               pressed = !this.pressed;
+       }
+       if ( pressed !== this.pressed ) {
+               this.$element
+                       .toggleClass( 'oo-ui-selectWidget-pressed', pressed )
+                       .toggleClass( 'oo-ui-selectWidget-depressed', !pressed );
+               this.pressed = pressed;
+       }
 };
 
 /**
- * Show the context.
+ * Highlight an item.
+ *
+ * Highlighting is mutually exclusive.
  *
- * @fires show
+ * @param {OO.ui.OptionWidget} [item] Item to highlight, omit to deselect all
+ * @fires highlight
  * @chainable
  */
-OO.ui.PopupWidget.prototype.show = function () {
-       if ( !this.visible ) {
-               this.setClipping( true );
-               this.$element.show();
-               this.visible = true;
-               this.emit( 'show' );
-               if ( this.autoClose ) {
-                       this.bindMouseDownListener();
+OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
+       var i, len, highlighted,
+               changed = false;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               highlighted = this.items[i] === item;
+               if ( this.items[i].isHighlighted() !== highlighted ) {
+                       this.items[i].setHighlighted( highlighted );
+                       changed = true;
                }
        }
+       if ( changed ) {
+               this.emit( 'highlight', item );
+       }
+
        return this;
 };
 
 /**
- * Hide the context.
+ * Select an item.
  *
- * @fires hide
+ * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
+ * @fires select
  * @chainable
  */
-OO.ui.PopupWidget.prototype.hide = function () {
-       if ( this.visible ) {
-               this.setClipping( false );
-               this.$element.hide();
-               this.visible = false;
-               this.emit( 'hide' );
-               if ( this.autoClose ) {
-                       this.unbindMouseDownListener();
+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 ( changed ) {
+               this.emit( 'select', item );
+       }
+
        return this;
 };
 
 /**
- * Updates the position and size.
+ * Press an item.
  *
- * @param {number} width Width
- * @param {number} height Height
- * @param {boolean} [transition=false] Use a smooth transition
+ * @param {OO.ui.OptionWidget} [item] Item to press, omit to depress all
+ * @fires press
  * @chainable
  */
-OO.ui.PopupWidget.prototype.display = function ( width, height, transition ) {
-       var padding = 10,
-               originOffset = Math.round( this.$element.offset().left ),
-               containerLeft = Math.round( this.$container.offset().left ),
-               containerWidth = this.$container.innerWidth(),
-               containerRight = containerLeft + containerWidth,
-               popupOffset = width * ( { 'left': 0, 'center': -0.5, 'right': -1 } )[this.align],
-               popupLeft = popupOffset - padding,
-               popupRight = popupOffset + padding + width + padding,
-               overlapLeft = ( originOffset + popupLeft ) - containerLeft,
-               overlapRight = containerRight - ( originOffset + popupRight );
-
-       // Prevent transition from being interrupted
-       clearTimeout( this.transitionTimeout );
-       if ( transition ) {
-               // Enable transition
-               this.$element.addClass( 'oo-ui-popupWidget-transitioning' );
-       }
+OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
+       var i, len, pressed,
+               changed = false;
 
-       if ( overlapRight < 0 ) {
-               popupOffset += overlapRight;
-       } else if ( overlapLeft < 0 ) {
-               popupOffset -= overlapLeft;
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               pressed = this.items[i] === item;
+               if ( this.items[i].isPressed() !== pressed ) {
+                       this.items[i].setPressed( pressed );
+                       changed = true;
+               }
        }
-
-       // Position body relative to anchor and resize
-       this.$popup.css( {
-               'left': popupOffset,
-               'width': width,
-               'height': height === undefined ? 'auto' : height
-       } );
-
-       if ( transition ) {
-               // Prevent transitioning after transition is complete
-               this.transitionTimeout = setTimeout( OO.ui.bind( function () {
-                       this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
-               }, this ), 200 );
-       } else {
-               // Prevent transitioning immediately
-               this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
+       if ( changed ) {
+               this.emit( 'press', item );
        }
 
        return this;
 };
 
 /**
- * Button that shows and hides a popup.
+ * Choose an item.
  *
- * @class
- * @extends OO.ui.ButtonWidget
- * @mixins OO.ui.PopuppableElement
+ * Identical to #selectItem, but may vary in subclasses that want to take additional action when
+ * an item is selected using the keyboard or mouse.
  *
- * @constructor
- * @param {Object} [config] Configuration options
+ * @param {OO.ui.OptionWidget} item Item to choose
+ * @fires choose
+ * @chainable
  */
-OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
-       // Parent constructor
-       OO.ui.PopupButtonWidget.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.PopuppableElement.call( this, config );
+OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
+       this.selectItem( item );
+       this.emit( 'choose', item );
 
-       // Initialization
-       this.$element
-               .addClass( 'oo-ui-popupButtonWidget' )
-               .append( this.popup.$element );
+       return this;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );
-OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.PopuppableElement );
-
-/* Methods */
-
 /**
- * Handles mouse click events.
+ * Get an item relative to another one.
  *
- * @param {jQuery.Event} e Mouse click event
+ * @param {OO.ui.OptionWidget} item Item to start at
+ * @param {number} direction Direction to move in
+ * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the menu
  */
-OO.ui.PopupButtonWidget.prototype.onClick = function ( e ) {
-       // Skip clicks within the popup
-       if ( $.contains( this.popup.$element[0], e.target ) ) {
-               return;
-       }
+OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction ) {
+       var inc = direction > 0 ? 1 : -1,
+               len = this.items.length,
+               index = item instanceof OO.ui.OptionWidget ?
+                       $.inArray( item, this.items ) : ( inc > 0 ? -1 : 0 ),
+               stopAt = Math.max( Math.min( index, len - 1 ), 0 ),
+               i = inc > 0 ?
+                       // Default to 0 instead of -1, if nothing is selected let's start at the beginning
+                       Math.max( index, -1 ) :
+                       // Default to n-1 instead of -1, if nothing is selected let's start at the end
+                       Math.min( index, len );
 
-       if ( !this.isDisabled() ) {
-               if ( this.popup.isVisible() ) {
-                       this.hidePopup();
-               } else {
-                       this.showPopup();
+       while ( true ) {
+               i = ( i + inc + len ) % len;
+               item = this.items[i];
+               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
+                       return item;
+               }
+               // Stop iterating when we've looped all the way around
+               if ( i === stopAt ) {
+                       break;
                }
-               OO.ui.PopupButtonWidget.super.prototype.onClick.call( this );
        }
-       return false;
+       return null;
 };
 
 /**
- * Search widget.
- *
- * Combines query and results selection widgets.
- *
- * @class
- * @extends OO.ui.Widget
+ * Get the next selectable item.
  *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string|jQuery} [placeholder] Placeholder text for query input
- * @cfg {string} [value] Initial query value
+ * @return {OO.ui.OptionWidget|null} Item, `null` if ther aren't any selectable items
  */
-OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
-       // Configuration intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.SearchWidget.super.call( this, config );
-
-       // Properties
-       this.query = new OO.ui.TextInputWidget( {
-               '$': this.$,
-               'icon': 'search',
-               'placeholder': config.placeholder,
-               'value': config.value
-       } );
-       this.results = new OO.ui.SelectWidget( { '$': this.$ } );
-       this.$query = this.$( '<div>' );
-       this.$results = this.$( '<div>' );
+OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
+       var i, len, item;
 
-       // Events
-       this.query.connect( this, {
-               'change': 'onQueryChange',
-               'enter': 'onQueryEnter'
-       } );
-       this.results.connect( this, {
-               'highlight': 'onResultsHighlight',
-               'select': 'onResultsSelect'
-       } );
-       this.query.$input.on( 'keydown', OO.ui.bind( this.onQueryKeydown, this ) );
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               item = this.items[i];
+               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
+                       return item;
+               }
+       }
 
-       // Initialization
-       this.$query
-               .addClass( 'oo-ui-searchWidget-query' )
-               .append( this.query.$element );
-       this.$results
-               .addClass( 'oo-ui-searchWidget-results' )
-               .append( this.results.$element );
-       this.$element
-               .addClass( 'oo-ui-searchWidget' )
-               .append( this.$results, this.$query );
+       return null;
 };
 
-/* Setup */
-
-OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
-
-/* Events */
-
-/**
- * @event highlight
- * @param {Object|null} item Item data or null if no item is highlighted
- */
-
-/**
- * @event select
- * @param {Object|null} item Item data or null if no item is selected
- */
-
-/* Methods */
-
 /**
- * Handle query key down events.
+ * Add items.
  *
- * @param {jQuery.Event} e Key down event
+ * When items are added with the same values as existing items, the existing items will be
+ * automatically removed before the new items are added.
+ *
+ * @param {OO.ui.OptionWidget[]} items Items to add
+ * @param {number} [index] Index to insert items after
+ * @fires add
+ * @chainable
  */
-OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
-       var highlightedItem, nextItem,
-               dir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );
+OO.ui.SelectWidget.prototype.addItems = function ( items, index ) {
+       var i, len, item, hash,
+               remove = [];
 
-       if ( dir ) {
-               highlightedItem = this.results.getHighlightedItem();
-               if ( !highlightedItem ) {
-                       highlightedItem = this.results.getSelectedItem();
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               hash = OO.getHash( item.getData() );
+               if ( hash in this.hashes ) {
+                       // Remove item with same value
+                       remove.push( this.hashes[hash] );
                }
-               nextItem = this.results.getRelativeSelectableItem( highlightedItem, dir );
-               this.results.highlightItem( nextItem );
-               nextItem.scrollElementIntoView();
+               this.hashes[hash] = item;
        }
+       if ( remove.length ) {
+               this.removeItems( remove );
+       }
+
+       // Mixin method
+       OO.ui.GroupWidget.prototype.addItems.call( this, items, index );
+
+       // Always provide an index, even if it was omitted
+       this.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );
+
+       return this;
 };
 
 /**
- * Handle select widget select events.
+ * Remove items.
  *
- * Clears existing results. Subclasses should repopulate items according to new query.
+ * Items will be detached, not removed, so they can be used later.
  *
- * @param {string} value New value
+ * @param {OO.ui.OptionWidget[]} items Items to remove
+ * @fires remove
+ * @chainable
  */
-OO.ui.SearchWidget.prototype.onQueryChange = function () {
-       // Reset
-       this.results.clearItems();
+OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
+       var i, len, item, hash;
+
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               hash = OO.getHash( item.getData() );
+               if ( hash in this.hashes ) {
+                       // Remove existing item
+                       delete this.hashes[hash];
+               }
+               if ( item.isSelected() ) {
+                       this.selectItem( null );
+               }
+       }
+
+       // Mixin method
+       OO.ui.GroupWidget.prototype.removeItems.call( this, items );
+
+       this.emit( 'remove', items );
+
+       return this;
 };
 
 /**
- * Handle select widget enter key events.
+ * Clear all items.
  *
- * Selects highlighted item.
+ * Items will be detached, not removed, so they can be used later.
  *
- * @param {string} value New value
+ * @fires remove
+ * @chainable
  */
-OO.ui.SearchWidget.prototype.onQueryEnter = function () {
-       // Reset
-       this.results.selectItem( this.results.getHighlightedItem() );
-};
+OO.ui.SelectWidget.prototype.clearItems = function () {
+       var items = this.items.slice();
 
-/**
- * Handle select widget highlight events.
- *
- * @param {OO.ui.OptionWidget} item Highlighted item
- * @fires highlight
- */
-OO.ui.SearchWidget.prototype.onResultsHighlight = function ( item ) {
-       this.emit( 'highlight', item ? item.getData() : null );
-};
+       // Clear all items
+       this.hashes = {};
+       // Mixin method
+       OO.ui.GroupWidget.prototype.clearItems.call( this );
+       this.selectItem( null );
 
-/**
- * Handle select widget select events.
- *
- * @param {OO.ui.OptionWidget} item Selected item
- * @fires select
- */
-OO.ui.SearchWidget.prototype.onResultsSelect = function ( item ) {
-       this.emit( 'select', item ? item.getData() : null );
-};
+       this.emit( 'remove', items );
 
-/**
- * Get the query input.
- *
- * @return {OO.ui.TextInputWidget} Query input
- */
-OO.ui.SearchWidget.prototype.getQuery = function () {
-       return this.query;
+       return this;
 };
 
 /**
- * Get the results list.
+ * Select widget containing button options.
  *
- * @return {OO.ui.SelectWidget} Select list
- */
-OO.ui.SearchWidget.prototype.getResults = function () {
-       return this.results;
-};
-
-/**
- * Text input widget.
+ * Use together with OO.ui.ButtonOptionWidget.
  *
  * @class
- * @extends OO.ui.InputWidget
+ * @extends OO.ui.SelectWidget
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {string} [placeholder] Placeholder text
- * @cfg {string} [icon] Symbolic name of icon
- * @cfg {boolean} [multiline=false] Allow multiple lines of text
- * @cfg {boolean} [autosize=false] Automatically resize to fit content
- * @cfg {boolean} [maxRows=10] Maximum number of rows to make visible when autosizing
  */
-OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
-       config = $.extend( { 'maxRows': 10 }, config );
-
+OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
        // Parent constructor
-       OO.ui.TextInputWidget.super.call( this, config );
-
-       // Properties
-       this.pending = 0;
-       this.multiline = !!config.multiline;
-       this.autosize = !!config.autosize;
-       this.maxRows = config.maxRows;
-
-       // Events
-       this.$input.on( 'keypress', OO.ui.bind( this.onKeyPress, this ) );
-       this.$element.on( 'DOMNodeInsertedIntoDocument', OO.ui.bind( this.onElementAttach, this ) );
+       OO.ui.ButtonSelectWidget.super.call( this, config );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-textInputWidget' );
-       if ( config.icon ) {
-               this.$element.addClass( 'oo-ui-textInputWidget-decorated' );
-               this.$element.append(
-                       this.$( '<span>' )
-                               .addClass( 'oo-ui-textInputWidget-icon oo-ui-icon-' + config.icon )
-                               .mousedown( OO.ui.bind( function () {
-                                       this.$input.focus();
-                                       return false;
-                               }, this ) )
-               );
-       }
-       if ( config.placeholder ) {
-               this.$input.attr( 'placeholder', config.placeholder );
-       }
+       this.$element.addClass( 'oo-ui-buttonSelectWidget' );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );
-
-/* Events */
+OO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );
 
 /**
- * User presses enter inside the text box.
+ * Overlaid menu of options.
  *
- * Not called if input is multiline.
+ * Menus are clipped to the visible viewport. They do not provide a control for opening or closing
+ * the menu.
  *
- * @event enter
+ * Use together with OO.ui.MenuItemWidget.
+ *
+ * @class
+ * @extends OO.ui.SelectWidget
+ * @mixins OO.ui.ClippableElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.InputWidget} [input] Input to bind keyboard handlers to
+ * @cfg {OO.ui.Widget} [widget] Widget to bind mouse handlers to
+ * @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu
  */
+OO.ui.MenuWidget = function OoUiMenuWidget( config ) {
+       // Config intialization
+       config = config || {};
 
-/* Methods */
+       // Parent constructor
+       OO.ui.MenuWidget.super.call( this, config );
 
-/**
- * Handle key press events.
- *
- * @param {jQuery.Event} e Key press event
- * @fires enter If enter key is pressed and input is not multiline
- */
-OO.ui.TextInputWidget.prototype.onKeyPress = function ( e ) {
-       if ( e.which === OO.ui.Keys.ENTER && !this.multiline ) {
-               this.emit( 'enter' );
-       }
-};
+       // Mixin constructors
+       OO.ui.ClippableElement.call( this, this.$group, config );
 
-/**
- * Handle element attach events.
- *
- * @param {jQuery.Event} e Element attach event
- */
-OO.ui.TextInputWidget.prototype.onElementAttach = function () {
-       this.adjustSize();
+       // Properties
+       this.flashing = false;
+       this.visible = false;
+       this.newItems = null;
+       this.autoHide = config.autoHide === undefined || !!config.autoHide;
+       this.$input = config.input ? config.input.$input : null;
+       this.$widget = config.widget ? config.widget.$element : null;
+       this.$previousFocus = null;
+       this.isolated = !config.input;
+       this.onKeyDownHandler = OO.ui.bind( this.onKeyDown, this );
+       this.onDocumentMouseDownHandler = OO.ui.bind( this.onDocumentMouseDown, this );
+
+       // Initialization
+       this.$element
+               .hide()
+               .attr( 'role', 'menu' )
+               .addClass( 'oo-ui-menuWidget' );
 };
 
-/**
- * @inheritdoc
- */
-OO.ui.TextInputWidget.prototype.onEdit = function () {
-       this.adjustSize();
+/* Setup */
 
-       // Parent method
-       return OO.ui.TextInputWidget.super.prototype.onEdit.call( this );
-};
+OO.inheritClass( OO.ui.MenuWidget, OO.ui.SelectWidget );
+OO.mixinClass( OO.ui.MenuWidget, OO.ui.ClippableElement );
+
+/* Methods */
 
 /**
- * Automatically adjust the size of the text input.
- *
- * This only affects multi-line inputs that are auto-sized.
+ * Handles document mouse down events.
  *
- * @chainable
+ * @param {jQuery.Event} e Key down event
  */
-OO.ui.TextInputWidget.prototype.adjustSize = function () {
-       var $clone, scrollHeight, innerHeight, outerHeight, maxInnerHeight, idealHeight;
-
-       if ( this.multiline && this.autosize ) {
-               $clone = this.$input.clone()
-                       .val( this.$input.val() )
-                       .css( { 'height': 0 } )
-                       .insertAfter( this.$input );
-               // Set inline height property to 0 to measure scroll height
-               scrollHeight = $clone[0].scrollHeight;
-               // Remove inline height property to measure natural heights
-               $clone.css( 'height', '' );
-               innerHeight = $clone.innerHeight();
-               outerHeight = $clone.outerHeight();
-               // Measure max rows height
-               $clone.attr( 'rows', this.maxRows ).css( 'height', 'auto' );
-               maxInnerHeight = $clone.innerHeight();
-               $clone.removeAttr( 'rows' ).css( 'height', '' );
-               $clone.remove();
-               idealHeight = Math.min( maxInnerHeight, scrollHeight );
-               // Only apply inline height when expansion beyond natural height is needed
-               this.$input.css(
-                       'height',
-                       // Use the difference between the inner and outer height as a buffer
-                       idealHeight > outerHeight ? idealHeight + ( outerHeight - innerHeight ) : ''
-               );
+OO.ui.MenuWidget.prototype.onDocumentMouseDown = function ( e ) {
+       if ( !$.contains( this.$element[0], e.target ) && ( !this.$widget || !$.contains( this.$widget[0], e.target ) ) ) {
+               this.toggle( false );
        }
-       return this;
 };
 
 /**
- * Get input element.
+ * Handles key down events.
  *
- * @param {Object} [config] Configuration options
- * @return {jQuery} Input element
+ * @param {jQuery.Event} e Key down event
  */
-OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
-       return config.multiline ? this.$( '<textarea>' ) : this.$( '<input type="text" />' );
-};
+OO.ui.MenuWidget.prototype.onKeyDown = function ( e ) {
+       var nextItem,
+               handled = false,
+               highlightItem = this.getHighlightedItem();
+
+       if ( !this.isDisabled() && this.isVisible() ) {
+               if ( !highlightItem ) {
+                       highlightItem = this.getSelectedItem();
+               }
+               switch ( e.keyCode ) {
+                       case OO.ui.Keys.ENTER:
+                               this.chooseItem( highlightItem );
+                               handled = true;
+                               break;
+                       case OO.ui.Keys.UP:
+                               nextItem = this.getRelativeSelectableItem( highlightItem, -1 );
+                               handled = true;
+                               break;
+                       case OO.ui.Keys.DOWN:
+                               nextItem = this.getRelativeSelectableItem( highlightItem, 1 );
+                               handled = true;
+                               break;
+                       case OO.ui.Keys.ESCAPE:
+                               if ( highlightItem ) {
+                                       highlightItem.setHighlighted( false );
+                               }
+                               this.toggle( false );
+                               handled = true;
+                               break;
+               }
 
-/* Methods */
+               if ( nextItem ) {
+                       this.highlightItem( nextItem );
+                       nextItem.scrollElementIntoView();
+               }
 
-/**
- * Check if input supports multiple lines.
- *
- * @return {boolean}
- */
-OO.ui.TextInputWidget.prototype.isMultiline = function () {
-       return !!this.multiline;
+               if ( handled ) {
+                       e.preventDefault();
+                       e.stopPropagation();
+                       return false;
+               }
+       }
 };
 
 /**
- * Check if input automatically adjusts its size.
- *
- * @return {boolean}
+ * Bind key down listener.
  */
-OO.ui.TextInputWidget.prototype.isAutosizing = function () {
-       return !!this.autosize;
+OO.ui.MenuWidget.prototype.bindKeyDownListener = function () {
+       if ( this.$input ) {
+               this.$input.on( 'keydown', this.onKeyDownHandler );
+       } else {
+               // Capture menu navigation keys
+               this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
+       }
 };
 
 /**
- * Check if input is pending.
- *
- * @return {boolean}
+ * Unbind key down listener.
  */
-OO.ui.TextInputWidget.prototype.isPending = function () {
-       return !!this.pending;
+OO.ui.MenuWidget.prototype.unbindKeyDownListener = function () {
+       if ( this.$input ) {
+               this.$input.off( 'keydown' );
+       } else {
+               this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
+       }
 };
 
 /**
- * Increase the pending stack.
+ * Choose an item.
+ *
+ * This will close the menu when done, unlike selectItem which only changes selection.
  *
+ * @param {OO.ui.OptionWidget} item Item to choose
  * @chainable
  */
-OO.ui.TextInputWidget.prototype.pushPending = function () {
-       if ( this.pending === 0 ) {
-               this.$element.addClass( 'oo-ui-textInputWidget-pending' );
-               this.$input.addClass( 'oo-ui-texture-pending' );
+OO.ui.MenuWidget.prototype.chooseItem = function ( item ) {
+       var widget = this;
+
+       // Parent method
+       OO.ui.MenuWidget.super.prototype.chooseItem.call( this, item );
+
+       if ( item && !this.flashing ) {
+               this.flashing = true;
+               item.flash().done( function () {
+                       widget.toggle( false );
+                       widget.flashing = false;
+               } );
+       } else {
+               this.toggle( false );
        }
-       this.pending++;
 
        return this;
 };
 
 /**
- * Reduce the pending stack.
+ * Add items.
  *
- * Clamped at zero.
+ * Adding an existing item (by value) will move it.
  *
+ * @param {OO.ui.MenuItemWidget[]} items Items to add
+ * @param {number} [index] Index to insert items after
  * @chainable
  */
-OO.ui.TextInputWidget.prototype.popPending = function () {
-       if ( this.pending === 1 ) {
-               this.$element.removeClass( 'oo-ui-textInputWidget-pending' );
-               this.$input.removeClass( 'oo-ui-texture-pending' );
+OO.ui.MenuWidget.prototype.addItems = function ( items, index ) {
+       var i, len, item;
+
+       // Parent method
+       OO.ui.MenuWidget.super.prototype.addItems.call( this, items, index );
+
+       // Auto-initialize
+       if ( !this.newItems ) {
+               this.newItems = [];
+       }
+
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               if ( this.isVisible() ) {
+                       // Defer fitting label until
+                       item.fitLabel();
+               } else {
+                       this.newItems.push( item );
+               }
        }
-       this.pending = Math.max( 0, this.pending - 1 );
 
        return this;
 };
 
 /**
- * Select the contents of the input.
- *
- * @chainable
+ * @inheritdoc
  */
-OO.ui.TextInputWidget.prototype.select = function () {
-       this.$input.select();
+OO.ui.MenuWidget.prototype.toggle = function ( visible ) {
+       visible = !!visible && !!this.items.length;
+
+       var i, len,
+               change = visible !== this.isVisible();
+
+       // Parent method
+       OO.ui.MenuWidget.super.prototype.toggle.call( this, visible );
+
+       if ( change ) {
+               if ( visible ) {
+                       this.bindKeyDownListener();
+
+                       // Change focus to enable keyboard navigation
+                       if ( this.isolated && this.$input && !this.$input.is( ':focus' ) ) {
+                               this.$previousFocus = this.$( ':focus' );
+                               this.$input[0].focus();
+                       }
+                       if ( this.newItems && this.newItems.length ) {
+                               for ( i = 0, len = this.newItems.length; i < len; i++ ) {
+                                       this.newItems[i].fitLabel();
+                               }
+                               this.newItems = null;
+                       }
+                       this.setClipping( true );
+
+                       // Auto-hide
+                       if ( this.autoHide ) {
+                               this.getElementDocument().addEventListener(
+                                       'mousedown', this.onDocumentMouseDownHandler, true
+                               );
+                       }
+               } else {
+                       this.unbindKeyDownListener();
+                       if ( this.isolated && this.$previousFocus ) {
+                               this.$previousFocus[0].focus();
+                               this.$previousFocus = null;
+                       }
+                       this.getElementDocument().removeEventListener(
+                               'mousedown', this.onDocumentMouseDownHandler, true
+                       );
+                       this.setClipping( false );
+               }
+       }
+
        return this;
 };
 
 /**
  * Menu for a text input widget.
  *
+ * This menu is specially designed to be positioned beneeth the text input widget. Even if the input
+ * is in a different frame, the menu's position is automatically calulated and maintained when the
+ * menu is toggled or the window is resized.
+ *
  * @class
  * @extends OO.ui.MenuWidget
  *
@@ -8431,29 +10422,24 @@ OO.ui.TextInputMenuWidget.prototype.onWindowResize = function () {
 };
 
 /**
- * Show the menu.
- *
- * @chainable
+ * @inheritdoc
  */
-OO.ui.TextInputMenuWidget.prototype.show = function () {
-       // Parent method
-       OO.ui.TextInputMenuWidget.super.prototype.show.call( this );
+OO.ui.TextInputMenuWidget.prototype.toggle = function ( visible ) {
+       visible = !!visible;
 
-       this.position();
-       this.$( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
-       return this;
-};
+       var change = visible !== this.isVisible();
 
-/**
- * Hide the menu.
- *
- * @chainable
- */
-OO.ui.TextInputMenuWidget.prototype.hide = function () {
        // Parent method
-       OO.ui.TextInputMenuWidget.super.prototype.hide.call( this );
+       OO.ui.TextInputMenuWidget.super.prototype.toggle.call( this, visible );
 
-       this.$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
+       if ( change ) {
+               if ( this.isVisible() ) {
+                       this.position();
+                       this.$( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
+               } else {
+                       this.$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
+               }
+       }
        return this;
 };
 
@@ -8486,130 +10472,37 @@ OO.ui.TextInputMenuWidget.prototype.position = function () {
                        delete dimensions.left;
                }
        }
-
        this.$element.css( dimensions );
        this.setIdealSize( $container.width() );
-       return this;
-};
-
-/**
- * Width with on and off states.
- *
- * Mixin for widgets with a boolean state.
- *
- * @abstract
- * @class
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
- */
-OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Properties
-       this.value = null;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-toggleWidget' );
-       this.setValue( !!config.value );
-};
-
-/* Events */
-
-/**
- * @event change
- * @param {boolean} value Changed value
- */
-
-/* Methods */
-
-/**
- * Get the value of the toggle.
- *
- * @return {boolean}
- */
-OO.ui.ToggleWidget.prototype.getValue = function () {
-       return this.value;
-};
 
-/**
- * Set the value of the toggle.
- *
- * @param {boolean} value New value
- * @fires change
- * @chainable
- */
-OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
-       value = !!value;
-       if ( this.value !== value ) {
-               this.value = value;
-               this.emit( 'change', value );
-               this.$element.toggleClass( 'oo-ui-toggleWidget-on', value );
-               this.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );
-       }
        return this;
 };
 
 /**
- * Button that toggles on and off.
+ * Structured list of items.
+ *
+ * Use with OO.ui.OutlineItemWidget.
  *
  * @class
- * @extends OO.ui.ButtonWidget
- * @mixins OO.ui.ToggleWidget
+ * @extends OO.ui.SelectWidget
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
  */
-OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
-       // Configuration initialization
+OO.ui.OutlineWidget = function OoUiOutlineWidget( config ) {
+       // Config intialization
        config = config || {};
 
        // Parent constructor
-       OO.ui.ToggleButtonWidget.super.call( this, config );
-
-       // Mixin constructors
-       OO.ui.ToggleWidget.call( this, config );
+       OO.ui.OutlineWidget.super.call( this, config );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-toggleButtonWidget' );
+       this.$element.addClass( 'oo-ui-outlineWidget' );
 };
 
 /* Setup */
 
-OO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ButtonWidget );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.ToggleButtonWidget.prototype.onClick = function () {
-       if ( !this.isDisabled() ) {
-               this.setValue( !this.value );
-       }
-
-       // Parent method
-       return OO.ui.ToggleButtonWidget.super.prototype.onClick.call( this );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {
-       value = !!value;
-       if ( value !== this.value ) {
-               this.setActive( value );
-       }
-
-       // Parent method (from mixin)
-       OO.ui.ToggleWidget.prototype.setValue.call( this, value );
-
-       return this;
-};
+OO.inheritClass( OO.ui.OutlineWidget, OO.ui.SelectWidget );
 
 /**
  * Switch that slides on and off.
diff --git a/resources/lib/oojs-ui/oojs-ui.rtl.css b/resources/lib/oojs-ui/oojs-ui.rtl.css
new file mode 100644 (file)
index 0000000..deca745
--- /dev/null
@@ -0,0 +1,1271 @@
+/*!
+ * OOjs UI v0.1.0
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2014 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2014-07-22T21:39:24Z
+ */
+/* Textures */
+
+.oo-ui-texture-pending {
+  background-image: /* @embed */ url(images/textures/pending.gif);
+}
+
+.oo-ui-texture-transparency {
+  background-image: /* @embed */ url(images/textures/transparency.png);
+}
+
+/* RTL Definitions */
+
+/* @noflip */
+
+.oo-ui-rtl {
+  direction: rtl;
+}
+
+/* @noflip */
+
+.oo-ui-ltr {
+  direction: ltr;
+}
+
+.oo-ui-frame {
+  padding: 0;
+  margin: 0;
+}
+
+.oo-ui-frame-body {
+  padding: 0;
+  margin: 0;
+  background: none;
+}
+
+.oo-ui-frame-content:focus {
+  outline: none;
+}
+
+.oo-ui-toolbar {
+  clear: both;
+}
+
+.oo-ui-toolbar-bar {
+  line-height: 1em;
+}
+
+.oo-ui-toolbar-bottom .oo-ui-toolbar-bar {
+  position: absolute;
+}
+
+.oo-ui-toolbar-actions {
+  float: left;
+}
+
+.oo-ui-toolbar-tools {
+  float: right;
+}
+
+.oo-ui-toolbar-tools,
+.oo-ui-toolbar-actions,
+.oo-ui-toolbar-shadow {
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-toolbar-actions .oo-ui-popupWidget {
+  -webkit-user-select: all;
+     -moz-user-select: all;
+      -ms-user-select: all;
+          user-select: all;
+  -webkit-touch-callout: default;
+}
+
+.oo-ui-toolbar-shadow {
+  position: absolute;
+  width: 100%;
+  pointer-events: none;
+  background-position: right top;
+  background-repeat: repeat-x;
+}
+
+.oo-ui-toolGroup {
+  display: inline-block;
+  margin: 0.3em;
+  vertical-align: middle;
+}
+
+.oo-ui-toolGroup-empty {
+  display: none;
+}
+
+.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-window {
+  line-height: 1em;
+}
+
+.oo-ui-window > .oo-ui-window-frame {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-window > .oo-ui-window-frame > .oo-ui-frame {
+  width: 100%;
+  height: 100%;
+}
+
+.oo-ui-window-head,
+.oo-ui-window-foot {
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-window-overlay {
+  position: absolute;
+  top: 0;
+  right: 0;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+  position: fixed;
+  width: 0;
+  height: 0;
+  overflow: hidden;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup {
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  width: auto;
+  height: auto;
+  padding: 1em;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
+  position: fixed;
+  left: 0;
+  right: 0;
+  max-width: 100%;
+  max-height: 100%;
+  margin: auto;
+  overflow: hidden;
+}
+
+.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
+  top: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.oo-ui-messageDialog-actions-horizontal {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+  display: table-cell;
+  width: 1%;
+}
+
+.oo-ui-messageDialog-actions-vertical {
+  display: block;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+  position: relative;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonedElement-button {
+  display: block;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  position: relative;
+  top: auto;
+  bottom: auto;
+  display: inline;
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-location {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-title {
+  display: inline;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-actions-safe,
+.oo-ui-processDialog-actions-primary {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+}
+
+.oo-ui-processDialog-actions-safe {
+  right: 0;
+}
+
+.oo-ui-processDialog-actions-primary {
+  left: 0;
+}
+
+.oo-ui-processDialog-errors {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  z-index: 2;
+  display: none;
+  padding: 3em 3em 1.5em 3em;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button {
+  display: inline-block;
+  vertical-align: middle;
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  display: none;
+  margin-right: 0;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator {
+  display: none;
+  margin-left: -0.75em;
+}
+
+.oo-ui-buttonedElement.oo-ui-widget-disabled > .oo-ui-buttonedElement-button {
+  cursor: default;
+}
+
+.oo-ui-buttonedElement.oo-ui-indicatedElement > .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement.oo-ui-iconedElement > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  display: inline-block;
+  vertical-align: middle;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-buttonedElement-frameless {
+  position: relative;
+  display: inline-block;
+}
+
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  display: inline-block;
+  margin-right: 0.25em;
+  vertical-align: middle;
+}
+
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button {
+  display: inline-block;
+  text-align: center;
+  vertical-align: top;
+}
+
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  display: inline-block;
+  line-height: 1.9em;
+  vertical-align: middle;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+  cursor: default;
+}
+
+.oo-ui-clippableElement-clippable {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
+  overflow-y: hidden;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
+  width: 100%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-scrollable {
+  overflow-y: auto;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-padded {
+  padding: 2em;
+}
+
+.oo-ui-bookletLayout-outlinePanel-editable .oo-ui-outlineWidget {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 3em;
+  right: 0;
+  overflow-y: auto;
+}
+
+.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.oo-ui-fieldLayout {
+  margin-bottom: 1em;
+}
+
+.oo-ui-fieldLayout:last-child {
+  margin-bottom: 0;
+}
+
+.oo-ui-fieldLayout:before,
+.oo-ui-fieldLayout:after {
+  display: table;
+  content: " ";
+}
+
+.oo-ui-fieldLayout:after {
+  clear: both;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labeledElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labeledElement-label {
+  display: block;
+  float: right;
+  width: 35%;
+  padding-top: 0.5em;
+  margin-left: 5%;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+  display: block;
+  float: right;
+  width: 60%;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labeledElement-label {
+  text-align: left;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labeledElement-label {
+  display: inline-block;
+  padding: 0.75em 0.5em 0.5em 0.5em;
+  vertical-align: middle;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
+  display: inline-block;
+  padding: 0.5em 0;
+  vertical-align: middle;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labeledElement-label {
+  display: inline-block;
+  padding: 0.5em 0;
+}
+
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  margin-top: 0.25em;
+}
+
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+  z-index: 1;
+}
+
+.oo-ui-fieldsetLayout {
+  position: relative;
+  padding: 0;
+  margin: 0;
+}
+
+.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
+  margin-top: 2em;
+}
+
+.oo-ui-fieldsetLayout-labeled {
+  margin-top: -0.75em;
+}
+
+.oo-ui-fieldsetLayout > .oo-ui-labeledElement-label {
+  padding: 0.25em 0;
+  margin-bottom: 0.5em;
+}
+
+.oo-ui-fieldsetLayout.oo-ui-iconedElement > .oo-ui-labeledElement-label {
+  padding-right: 1.75em;
+  line-height: 1.33em;
+}
+
+.oo-ui-fieldsetLayout.oo-ui-iconedElement > .oo-ui-iconedElement-icon {
+  position: absolute;
+  top: 0.25em;
+  right: 0;
+  display: block;
+  width: 2em;
+  height: 2em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-gridLayout {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.oo-ui-labelWidget {
+  display: inline-block;
+  padding: 0.5em 0;
+}
+
+.oo-ui-panelLayout {
+  position: relative;
+}
+
+.oo-ui-panelLayout-scrollable {
+  overflow-y: auto;
+}
+
+.oo-ui-panelLayout-expanded {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.oo-ui-stackLayout > .oo-ui-panelLayout {
+  display: none;
+}
+
+.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
+  position: relative;
+  display: block;
+}
+
+.oo-ui-barToolGroup > .oo-ui-iconedElement-icon,
+.oo-ui-barToolGroup > .oo-ui-labeledElement-label {
+  display: none;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool {
+  position: relative;
+  display: inline-block;
+  vertical-align: top;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link {
+  display: block;
+  height: 1.5em;
+  padding: 0.25em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  display: block;
+  width: 1.5em;
+  height: 1.5em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+  display: none;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+  cursor: default;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-title,
+.oo-ui-barToolGroup .oo-ui-tool-accel {
+  display: none;
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-link {
+  cursor: pointer;
+}
+
+.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
+  padding: 0.25em;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool {
+  display: inline-block;
+  width: 100%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool-link {
+  display: block;
+  padding-left: 0.5em;
+  white-space: nowrap;
+  cursor: pointer;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+  cursor: default;
+}
+
+.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
+  min-width: 8em;
+}
+
+.oo-ui-menuToolGroup .oo-ui-toolGroup-tools {
+  padding: 0.25em 0 0.25em 0;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool {
+  display: block;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-link {
+  display: block;
+  padding: 0 0.25em 0 1em;
+  white-space: nowrap;
+  cursor: pointer;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  background-image: none;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  background-image: /* @embed */ url(images/icons/check.svg);
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+  cursor: default;
+}
+
+.oo-ui-popupToolGroup {
+  position: relative;
+  height: 2em;
+  min-width: 2.5em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-indicatedElement.oo-ui-iconedElement {
+  min-width: 3.5em;
+}
+
+.oo-ui-popupToolGroup-handle {
+  display: block;
+  cursor: pointer;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator,
+.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
+  position: absolute;
+  top: 0;
+  width: 2em;
+  height: 2em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator {
+  left: 0;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
+  right: 0.25em;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+  margin: 0 1em;
+  font-size: 0.8em;
+  line-height: 2.6em;
+}
+
+.oo-ui-popupToolGroup-header {
+  margin: 0 0.6em;
+  font-size: 0.8em;
+  font-weight: bold;
+  line-height: 2.6em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
+  cursor: default;
+}
+
+.oo-ui-popupToolGroup.oo-ui-iconedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+  margin-right: 3em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-indicatedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+  margin-left: 2.25em;
+}
+
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+  position: absolute;
+  top: 2em;
+  right: -1px;
+  z-index: 4;
+  display: none;
+}
+
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconedElement-icon {
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
+  display: block;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  margin-left: 0.25em;
+  vertical-align: middle;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+  display: inline-block;
+  font-size: 0.8em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-accel {
+  display: none;
+}
+
+.oo-ui-popupTool .oo-ui-popupWidget {
+  margin-right: 1.25em;
+  font-size: 0.8em;
+}
+
+.oo-ui-popupTool .oo-ui-popupWidget-popup,
+.oo-ui-popupTool .oo-ui-popupWidget-anchor {
+  z-index: 4;
+}
+
+.oo-ui-iconWidget {
+  display: inline-block;
+  width: 1.9em;
+  height: 1.9em;
+  line-height: 2.5em;
+  vertical-align: middle;
+  background-position: center center;
+  background-repeat: no-repeat;
+  opacity: 0.8;
+}
+
+.oo-ui-iconWidget.oo-ui-widget-disabled {
+  opacity: 0.2;
+}
+
+.oo-ui-indicatorWidget {
+  display: inline-block;
+  width: 1.9em;
+  height: 1.9em;
+  line-height: 2.5em;
+  vertical-align: middle;
+  background-position: center center;
+  background-repeat: no-repeat;
+  opacity: 0.8;
+}
+
+.oo-ui-indicatorWidget.oo-ui-widget-disabled {
+  opacity: 0.2;
+}
+
+.oo-ui-selectWidget {
+  padding: 0;
+  margin: 0;
+  list-style: none;
+}
+
+.oo-ui-optionWidget {
+  position: relative;
+  display: block;
+  margin: 0;
+  list-style: none;
+  cursor: pointer;
+  border: none;
+}
+
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+  cursor: default;
+}
+
+.oo-ui-optionWidget .oo-ui-labeledElement-label {
+  display: block;
+  overflow: hidden;
+  line-height: 1.5em;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.oo-ui-decoratedOptionWidget .oo-ui-iconedElement-icon,
+.oo-ui-decoratedOptionWidget .oo-ui-indicatedElement-indicator {
+  position: absolute;
+  top: 50%;
+  width: 2em;
+  height: 2em;
+  margin-top: -1em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-decoratedOptionWidget .oo-ui-iconedElement-icon {
+  right: 0.5em;
+}
+
+.oo-ui-decoratedOptionWidget .oo-ui-indicatedElement-indicator {
+  left: 0.5em;
+}
+
+.oo-ui-menuWidget {
+  position: absolute;
+}
+
+.oo-ui-menuWidget input {
+  position: absolute;
+  width: 0;
+  height: 0;
+  overflow: hidden;
+  opacity: 0;
+}
+
+.oo-ui-popupWidget-popup {
+  position: absolute;
+  z-index: 1;
+  overflow: hidden;
+}
+
+.oo-ui-popupWidget-anchor {
+  z-index: 1;
+  display: none;
+}
+
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
+  margin-top: 7px;
+}
+
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
+  position: absolute;
+  display: block;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-popupWidget-head {
+  height: 2.5em;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-popupWidget-head .oo-ui-buttonWidget {
+  float: left;
+  margin: 0.25em;
+}
+
+.oo-ui-popupWidget-head .oo-ui-labeledElement-label {
+  float: right;
+  margin: 0.75em 1em;
+  cursor: default;
+}
+
+.oo-ui-popupWidget-body {
+  overflow: hidden;
+  clear: both;
+}
+
+.oo-ui-popupWidget-body-padded {
+  padding: 0 1em;
+}
+
+.oo-ui-buttonGroupWidget {
+  border-radius: 0.3em;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  margin-bottom: -1px;
+  margin-right: -1px;
+  border-radius: 0;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:first-child .oo-ui-buttonedElement-button {
+  margin-right: 0;
+  border-bottom-right-radius: 0.3em;
+  border-top-right-radius: 0.3em;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:last-child .oo-ui-buttonedElement-button {
+  border-top-left-radius: 0.3em;
+  border-bottom-left-radius: 0.3em;
+}
+
+.oo-ui-buttonOptionWidget {
+  display: inline-block;
+  background-color: transparent;
+}
+
+.oo-ui-buttonOptionWidget .oo-ui-buttonedElement-button {
+  position: relative;
+  height: 1.9em;
+}
+
+.oo-ui-buttonOptionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon,
+.oo-ui-buttonOptionWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator {
+  position: static;
+  display: inline-block;
+  height: 1.9em;
+  margin-top: 0;
+  vertical-align: middle;
+}
+
+.oo-ui-buttonSelectWidget {
+  display: inline-block;
+  white-space: nowrap;
+}
+
+.oo-ui-buttonWidget {
+  display: inline-block;
+  vertical-align: middle;
+}
+
+.oo-ui-inlineMenuWidget {
+  position: relative;
+  display: inline-block;
+  min-width: 20em;
+  margin: 0.25em 0;
+}
+
+.oo-ui-inlineMenuWidget-handle {
+  display: inline-block;
+  width: 100%;
+  height: 2.5em;
+  cursor: pointer;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-indicatedElement-indicator,
+.oo-ui-inlineMenuWidget-handle .oo-ui-iconedElement-icon {
+  position: absolute;
+  top: 0;
+  width: 2.5em;
+  height: 2.5em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-indicatedElement-indicator {
+  left: 0;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-iconedElement-icon {
+  right: 0.25em;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
+  margin: 0 0.5em;
+  line-height: 2.5em;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-iconedElement .oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
+  margin-right: 3em;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-indicatedElement .oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
+  margin-left: 2em;
+}
+
+.oo-ui-inlineMenuWidget .oo-ui-menuWidget {
+  z-index: 1;
+  width: 100%;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
+  cursor: default;
+}
+
+.oo-ui-menuItemWidget {
+  position: relative;
+}
+
+.oo-ui-menuItemWidget .oo-ui-iconedElement-icon {
+  display: none;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
+  background-color: transparent;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconedElement-icon {
+  display: block;
+}
+
+.oo-ui-menuSectionItemWidget {
+  cursor: default;
+}
+
+.oo-ui-outlineControlsWidget {
+  height: 3em;
+}
+
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+  float: right;
+  height: 2em;
+  padding: 0;
+  margin: 0.5em;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-outlineControlsWidget > .oo-ui-iconedElement-icon {
+  float: right;
+  width: 1.5em;
+  height: 2em;
+  margin: 0.5em 0.5em 0.5em 0;
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-outlineControlsWidget-items {
+  float: right;
+  margin-right: 0;
+}
+
+.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
+  float: right;
+}
+
+.oo-ui-outlineControlsWidget-movers {
+  float: left;
+}
+
+.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
+  float: left;
+}
+
+.oo-ui-outlineItemWidget {
+  position: relative;
+  padding: 0.75em;
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-popupButtonWidget {
+  position: relative;
+}
+
+.oo-ui-popupButtonWidget .oo-ui-popupWidget {
+  position: absolute;
+  right: 1em;
+  cursor: auto;
+}
+
+.oo-ui-searchWidget-query {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 4em;
+  padding: 0 1em;
+}
+
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+  width: 100%;
+  margin: 0.75em 0;
+}
+
+.oo-ui-searchWidget-results {
+  position: absolute;
+  top: 4em;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  padding: 1em;
+  overflow-x: hidden;
+  overflow-y: auto;
+  line-height: 0;
+}
+
+.oo-ui-textInputWidget {
+  position: relative;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+  display: inline-block;
+  width: 100%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  resize: none;
+}
+
+.oo-ui-textInputWidget-icon {
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 100%;
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-toggleSwitchWidget {
+  position: relative;
+  display: inline-block;
+  width: 4em;
+  height: 2em;
+  overflow: hidden;
+  vertical-align: middle;
+  cursor: pointer;
+  -webkit-transform: translateZ(0);
+     -moz-transform: translateZ(0);
+      -ms-transform: translateZ(0);
+       -o-transform: translateZ(0);
+          transform: translateZ(0);
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
+  cursor: default;
+}
+
+.oo-ui-toggleSwitchWidget-grip {
+  position: absolute;
+  top: 0.25em;
+  right: 0.25em;
+  display: block;
+  width: 1.5em;
+  height: 1.5em;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  -webkit-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+     -moz-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+      -ms-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+       -o-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+          transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+}
+
+.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  -webkit-transition: opacity 200ms ease-in-out;
+     -moz-transition: opacity 200ms ease-in-out;
+      -ms-transition: opacity 200ms ease-in-out;
+       -o-transition: opacity 200ms ease-in-out;
+          transition: opacity 200ms ease-in-out;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
+  right: 2.25em;
+  margin-right: -2px;
+}
+
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
+  right: 0.25em;
+  margin-right: 0;
+}
+
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+  display: none;
+}
+
+/* Icons */
+
+.oo-ui-icon-add-item {
+  background-image: /* @embed */ url(images/icons/add-item.png);
+}
+
+.oo-ui-icon-advanced {
+  background-image: /* @embed */ url(images/icons/advanced.png);
+}
+
+.oo-ui-icon-alert {
+  background-image: /* @embed */ url(images/icons/alert.png);
+}
+
+.oo-ui-icon-check {
+  background-image: /* @embed */ url(images/icons/check.png);
+}
+
+.oo-ui-icon-clear {
+  background-image: /* @embed */ url(images/icons/clear.png);
+}
+
+.oo-ui-icon-close {
+  background-image: /* @embed */ url(images/icons/close.png);
+}
+
+.oo-ui-icon-code {
+  background-image: /* @embed */ url(images/icons/code.png);
+}
+
+.oo-ui-icon-collapse {
+  background-image: /* @embed */ url(images/icons/collapse.png);
+}
+
+.oo-ui-icon-comment {
+  background-image: /* @embed */ url(images/icons/comment.png);
+}
+
+.oo-ui-icon-expand {
+  background-image: /* @embed */ url(images/icons/expand.png);
+}
+
+.oo-ui-icon-help {
+  background-image: /* @embed */ url(images/icons/help.png);
+}
+
+.oo-ui-icon-info {
+  background-image: /* @embed */ url(images/icons/info.png);
+}
+
+.oo-ui-icon-link {
+  background-image: /* @embed */ url(images/icons/link.png);
+}
+
+.oo-ui-icon-menu {
+  background-image: /* @embed */ url(images/icons/menu.png);
+}
+
+.oo-ui-icon-next {
+  background-image: /* @embed */ url(images/icons/move-rtl.png);
+}
+
+.oo-ui-icon-picture {
+  background-image: /* @embed */ url(images/icons/picture.png);
+}
+
+.oo-ui-icon-previous {
+  background-image: /* @embed */ url(images/icons/move-ltr.png);
+}
+
+.oo-ui-icon-redo {
+  background-image: /* @embed */ url(images/icons/arched-arrow-rtl.png);
+}
+
+.oo-ui-icon-remove {
+  background-image: /* @embed */ url(images/icons/remove.png);
+}
+
+.oo-ui-icon-search {
+  background-image: /* @embed */ url(images/icons/search.png);
+}
+
+.oo-ui-icon-settings {
+  background-image: /* @embed */ url(images/icons/settings.png);
+}
+
+.oo-ui-icon-tag {
+  background-image: /* @embed */ url(images/icons/tag.png);
+}
+
+.oo-ui-icon-undo {
+  background-image: /* @embed */ url(images/icons/arched-arrow-ltr.png);
+}
+
+.oo-ui-icon-window {
+  background-image: /* @embed */ url(images/icons/window.png);
+}
+
+/* Indicators */
+
+.oo-ui-indicator-alert {
+  background-image: /* @embed */ url(images/indicators/alert.png);
+}
+
+.oo-ui-indicator-down {
+  background-image: /* @embed */ url(images/indicators/arrow-down.png);
+}
+
+.oo-ui-indicator-next {
+  background-image: /* @embed */ url(images/indicators/arrow-rtl.png);
+}
+
+.oo-ui-indicator-previous {
+  background-image: /* @embed */ url(images/indicators/arrow-ltr.png);
+}
+
+.oo-ui-indicator-required {
+  background-image: /* @embed */ url(images/indicators/required.png);
+}
+
+.oo-ui-indicator-up {
+  background-image: /* @embed */ url(images/indicators/arrow-up.png);
+}
\ No newline at end of file
index a568a6d..c7b7d8d 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.1.0-pre (a63f03882e)
+ * OOjs UI v0.1.0-pre (9cd400e3d5)
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-06-27T23:51:18Z
+ * Date: 2014-07-22T21:59:46Z
  */
 /* Textures */
 
   direction: ltr;
 }
 
-.oo-ui-dialog {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  padding: 1em;
-  line-height: 1em;
-  /* Fix for strange opacity-related rendering issues.
-          CAUTION: -webkit-backface-visibility: hidden; is EXTREMELY DANGEROUS.
-          If applied to a VE surface directly, it will break selection of
-          FocusableNodes, and in the past it's caused transparent PNGs to
-          render as opaque black images. For some reason applying it to the dialog
-          wrapper in the main document fixes opacity-related behavior in the iframe
-          document, but doesn't break the surface inside the iframe. */
-
-  -webkit-backface-visibility: hidden;
-          backface-visibility: hidden;
-}
-
-.oo-ui-dialog > .oo-ui-window-frame {
-  position: fixed;
-  right: 0;
-  left: 0;
-  min-height: 12em;
-  margin: auto;
-  overflow: hidden;
-}
-
-.oo-ui-dialog > .oo-ui-window-frame .oo-ui-frame {
-  width: 100%;
-  height: 100%;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed {
-  float: left;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-flaggableElement-primary,
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-flaggableElement-constructive,
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-flaggableElement-destructive {
-  float: right;
-}
-
-.oo-ui-dialog-content-footless .oo-ui-window-foot {
-  display: none;
-}
-
 .oo-ui-frame {
   padding: 0;
   margin: 0;
   background-repeat: no-repeat;
 }
 
-.oo-ui-window-head {
+.oo-ui-window {
+  line-height: 1em;
+}
+
+.oo-ui-window > .oo-ui-window-frame {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-window > .oo-ui-window-frame > .oo-ui-frame {
+  width: 100%;
+  height: 100%;
+}
+
+.oo-ui-window-head,
+.oo-ui-window-foot {
   -webkit-user-select: none;
      -moz-user-select: none;
       -ms-user-select: none;
   -webkit-touch-callout: none;
 }
 
-.oo-ui-window-icon {
-  float: left;
-  background-position: center center;
-  background-repeat: no-repeat;
+.oo-ui-window-overlay {
+  position: absolute;
+  top: 0;
+  left: 0;
 }
 
-.oo-ui-window-title {
-  float: left;
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+  position: fixed;
+  width: 0;
+  height: 0;
+  overflow: hidden;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup {
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  width: auto;
+  height: auto;
+  padding: 1em;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
+  position: fixed;
+  right: 0;
+  left: 0;
+  max-width: 100%;
+  max-height: 100%;
+  margin: auto;
+  overflow: hidden;
+}
+
+.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
+  top: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.oo-ui-messageDialog-actions-horizontal {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+  display: table-cell;
+  width: 1%;
+}
+
+.oo-ui-messageDialog-actions-vertical {
+  display: block;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+  position: relative;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonedElement-button {
+  display: block;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  position: relative;
+  top: auto;
+  bottom: auto;
+  display: inline;
   white-space: nowrap;
-  cursor: default;
 }
 
-.oo-ui-window-overlay {
+.oo-ui-processDialog-location {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-title {
+  display: inline;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-actions-safe,
+.oo-ui-processDialog-actions-primary {
   position: absolute;
   top: 0;
+  bottom: 0;
+}
+
+.oo-ui-processDialog-actions-safe {
   left: 0;
 }
 
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button {
+.oo-ui-processDialog-actions-primary {
+  right: 0;
+}
+
+.oo-ui-processDialog-errors {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 2;
+  display: none;
+  padding: 3em 3em 1.5em 3em;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button {
   display: inline-block;
   vertical-align: middle;
   cursor: pointer;
   -webkit-touch-callout: none;
 }
 
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
   display: none;
   margin-left: 0;
 }
 
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator {
+.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator {
   display: none;
   margin-right: -0.75em;
 }
 
-.oo-ui-buttonedElement.oo-ui-widget-disabled .oo-ui-buttonedElement-button {
+.oo-ui-buttonedElement.oo-ui-widget-disabled .oo-ui-buttonedElement-button {
   cursor: default;
 }
 
-.oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
-.oo-ui-buttonedElement.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+.oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
   display: inline-block;
   vertical-align: middle;
   background-position: center center;
   display: inline-block;
 }
 
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
   display: inline-block;
   margin-left: 0.25em;
   vertical-align: middle;
 }
 
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
   display: inline-block;
   text-align: center;
   vertical-align: top;
 }
 
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
   display: inline-block;
   line-height: 1.9em;
   vertical-align: middle;
 }
 
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
   cursor: default;
 }
 
 }
 
 .oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labeledElement-label {
+  display: inline-block;
   padding: 0.5em 0;
 }
 
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  margin-top: 0.25em;
+}
+
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+  z-index: 1;
+}
+
 .oo-ui-fieldsetLayout {
   position: relative;
   padding: 0;
 }
 
 .oo-ui-labelWidget {
+  display: inline-block;
   padding: 0.5em 0;
 }
 
+.oo-ui-panelLayout {
+  position: relative;
+}
+
 .oo-ui-panelLayout-scrollable {
   overflow-y: auto;
 }
 
+.oo-ui-panelLayout-expanded {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+}
+
 .oo-ui-stackLayout > .oo-ui-panelLayout {
   display: none;
 }
 }
 
 .oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconedElement-icon {
-  background-image: /* @embed */ url(images/icons/check.png);
+  background-image: /* @embed */ url(images/icons/check.svg);
 }
 
 .oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
 }
 
 .oo-ui-popupTool .oo-ui-popupWidget-popup,
-.oo-ui-popupTool .oo-ui-popupWidget-tail {
+.oo-ui-popupTool .oo-ui-popupWidget-anchor {
   z-index: 4;
 }
 
   white-space: nowrap;
 }
 
-.oo-ui-optionWidget .oo-ui-iconedElement-icon,
-.oo-ui-optionWidget .oo-ui-indicatedElement-indicator {
+.oo-ui-decoratedOptionWidget .oo-ui-iconedElement-icon,
+.oo-ui-decoratedOptionWidget .oo-ui-indicatedElement-indicator {
   position: absolute;
   top: 50%;
   width: 2em;
   background-repeat: no-repeat;
 }
 
-.oo-ui-optionWidget .oo-ui-iconedElement-icon {
+.oo-ui-decoratedOptionWidget .oo-ui-iconedElement-icon {
   left: 0.5em;
 }
 
-.oo-ui-optionWidget .oo-ui-indicatedElement-indicator {
+.oo-ui-decoratedOptionWidget .oo-ui-indicatedElement-indicator {
   right: 0.5em;
 }
 
 
 .oo-ui-popupWidget-popup {
   position: absolute;
+  z-index: 1;
   overflow: hidden;
 }
 
-.oo-ui-popupWidget-tail {
+.oo-ui-popupWidget-anchor {
+  z-index: 1;
   display: none;
 }
 
-.oo-ui-popupWidget-tailed .oo-ui-popupWidget-popup {
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
   margin-top: 7px;
 }
 
-.oo-ui-popupWidget-tailed .oo-ui-popupWidget-tail {
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
   position: absolute;
   display: block;
   background-repeat: no-repeat;
 }
 
 .oo-ui-popupWidget-body {
+  overflow: hidden;
   clear: both;
 }
 
+.oo-ui-popupWidget-body-padded {
+  padding: 0 1em;
+}
+
 .oo-ui-buttonGroupWidget {
   border-radius: 0.3em;
 }
diff --git a/resources/lib/oojs-ui/oojs-ui.svg.rtl.css b/resources/lib/oojs-ui/oojs-ui.svg.rtl.css
new file mode 100644 (file)
index 0000000..9a7fe08
--- /dev/null
@@ -0,0 +1,1271 @@
+/*!
+ * OOjs UI v0.1.0
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2014 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2014-07-22T21:39:24Z
+ */
+/* Textures */
+
+.oo-ui-texture-pending {
+  background-image: /* @embed */ url(images/textures/pending.gif);
+}
+
+.oo-ui-texture-transparency {
+  background-image: /* @embed */ url(images/textures/transparency.png);
+}
+
+/* RTL Definitions */
+
+/* @noflip */
+
+.oo-ui-rtl {
+  direction: rtl;
+}
+
+/* @noflip */
+
+.oo-ui-ltr {
+  direction: ltr;
+}
+
+.oo-ui-frame {
+  padding: 0;
+  margin: 0;
+}
+
+.oo-ui-frame-body {
+  padding: 0;
+  margin: 0;
+  background: none;
+}
+
+.oo-ui-frame-content:focus {
+  outline: none;
+}
+
+.oo-ui-toolbar {
+  clear: both;
+}
+
+.oo-ui-toolbar-bar {
+  line-height: 1em;
+}
+
+.oo-ui-toolbar-bottom .oo-ui-toolbar-bar {
+  position: absolute;
+}
+
+.oo-ui-toolbar-actions {
+  float: left;
+}
+
+.oo-ui-toolbar-tools {
+  float: right;
+}
+
+.oo-ui-toolbar-tools,
+.oo-ui-toolbar-actions,
+.oo-ui-toolbar-shadow {
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-toolbar-actions .oo-ui-popupWidget {
+  -webkit-user-select: all;
+     -moz-user-select: all;
+      -ms-user-select: all;
+          user-select: all;
+  -webkit-touch-callout: default;
+}
+
+.oo-ui-toolbar-shadow {
+  position: absolute;
+  width: 100%;
+  pointer-events: none;
+  background-position: right top;
+  background-repeat: repeat-x;
+}
+
+.oo-ui-toolGroup {
+  display: inline-block;
+  margin: 0.3em;
+  vertical-align: middle;
+}
+
+.oo-ui-toolGroup-empty {
+  display: none;
+}
+
+.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-window {
+  line-height: 1em;
+}
+
+.oo-ui-window > .oo-ui-window-frame {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-window > .oo-ui-window-frame > .oo-ui-frame {
+  width: 100%;
+  height: 100%;
+}
+
+.oo-ui-window-head,
+.oo-ui-window-foot {
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-window-overlay {
+  position: absolute;
+  top: 0;
+  right: 0;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+  position: fixed;
+  width: 0;
+  height: 0;
+  overflow: hidden;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup {
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  width: auto;
+  height: auto;
+  padding: 1em;
+}
+
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
+  position: fixed;
+  left: 0;
+  right: 0;
+  max-width: 100%;
+  max-height: 100%;
+  margin: auto;
+  overflow: hidden;
+}
+
+.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
+  top: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.oo-ui-messageDialog-actions-horizontal {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+}
+
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+  display: table-cell;
+  width: 1%;
+}
+
+.oo-ui-messageDialog-actions-vertical {
+  display: block;
+}
+
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+  position: relative;
+  text-align: center;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonedElement-button {
+  display: block;
+}
+
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labeledElement-label {
+  position: relative;
+  top: auto;
+  bottom: auto;
+  display: inline;
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-location {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-title {
+  display: inline;
+}
+
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
+  white-space: nowrap;
+}
+
+.oo-ui-processDialog-actions-safe,
+.oo-ui-processDialog-actions-primary {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+}
+
+.oo-ui-processDialog-actions-safe {
+  right: 0;
+}
+
+.oo-ui-processDialog-actions-primary {
+  left: 0;
+}
+
+.oo-ui-processDialog-errors {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  z-index: 2;
+  display: none;
+  padding: 3em 3em 1.5em 3em;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button {
+  display: inline-block;
+  vertical-align: middle;
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  display: none;
+  margin-right: 0;
+}
+
+.oo-ui-buttonedElement > .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator {
+  display: none;
+  margin-left: -0.75em;
+}
+
+.oo-ui-buttonedElement.oo-ui-widget-disabled > .oo-ui-buttonedElement-button {
+  cursor: default;
+}
+
+.oo-ui-buttonedElement.oo-ui-indicatedElement > .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement.oo-ui-iconedElement > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  display: inline-block;
+  vertical-align: middle;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-buttonedElement-frameless {
+  position: relative;
+  display: inline-block;
+}
+
+.oo-ui-buttonedElement-frameless > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  display: inline-block;
+  margin-right: 0.25em;
+  vertical-align: middle;
+}
+
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button {
+  display: inline-block;
+  text-align: center;
+  vertical-align: top;
+}
+
+.oo-ui-buttonedElement-framed > .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+  display: inline-block;
+  line-height: 1.9em;
+  vertical-align: middle;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled > .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
+  cursor: default;
+}
+
+.oo-ui-clippableElement-clippable {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
+  overflow-y: hidden;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
+  width: 100%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-scrollable {
+  overflow-y: auto;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-padded {
+  padding: 2em;
+}
+
+.oo-ui-bookletLayout-outlinePanel-editable .oo-ui-outlineWidget {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 3em;
+  right: 0;
+  overflow-y: auto;
+}
+
+.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.oo-ui-fieldLayout {
+  margin-bottom: 1em;
+}
+
+.oo-ui-fieldLayout:last-child {
+  margin-bottom: 0;
+}
+
+.oo-ui-fieldLayout:before,
+.oo-ui-fieldLayout:after {
+  display: table;
+  content: " ";
+}
+
+.oo-ui-fieldLayout:after {
+  clear: both;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labeledElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labeledElement-label {
+  display: block;
+  float: right;
+  width: 35%;
+  padding-top: 0.5em;
+  margin-left: 5%;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+  display: block;
+  float: right;
+  width: 60%;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labeledElement-label {
+  text-align: left;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labeledElement-label {
+  display: inline-block;
+  padding: 0.75em 0.5em 0.5em 0.5em;
+  vertical-align: middle;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
+  display: inline-block;
+  padding: 0.5em 0;
+  vertical-align: middle;
+}
+
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labeledElement-label {
+  display: inline-block;
+  padding: 0.5em 0;
+}
+
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+  margin-top: 0.25em;
+}
+
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+  z-index: 1;
+}
+
+.oo-ui-fieldsetLayout {
+  position: relative;
+  padding: 0;
+  margin: 0;
+}
+
+.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
+  margin-top: 2em;
+}
+
+.oo-ui-fieldsetLayout-labeled {
+  margin-top: -0.75em;
+}
+
+.oo-ui-fieldsetLayout > .oo-ui-labeledElement-label {
+  padding: 0.25em 0;
+  margin-bottom: 0.5em;
+}
+
+.oo-ui-fieldsetLayout.oo-ui-iconedElement > .oo-ui-labeledElement-label {
+  padding-right: 1.75em;
+  line-height: 1.33em;
+}
+
+.oo-ui-fieldsetLayout.oo-ui-iconedElement > .oo-ui-iconedElement-icon {
+  position: absolute;
+  top: 0.25em;
+  right: 0;
+  display: block;
+  width: 2em;
+  height: 2em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-gridLayout {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.oo-ui-labelWidget {
+  display: inline-block;
+  padding: 0.5em 0;
+}
+
+.oo-ui-panelLayout {
+  position: relative;
+}
+
+.oo-ui-panelLayout-scrollable {
+  overflow-y: auto;
+}
+
+.oo-ui-panelLayout-expanded {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.oo-ui-stackLayout > .oo-ui-panelLayout {
+  display: none;
+}
+
+.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
+  position: relative;
+  display: block;
+}
+
+.oo-ui-barToolGroup > .oo-ui-iconedElement-icon,
+.oo-ui-barToolGroup > .oo-ui-labeledElement-label {
+  display: none;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool {
+  position: relative;
+  display: inline-block;
+  vertical-align: top;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link {
+  display: block;
+  height: 1.5em;
+  padding: 0.25em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  display: block;
+  width: 1.5em;
+  height: 1.5em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+  display: none;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+  cursor: default;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-title,
+.oo-ui-barToolGroup .oo-ui-tool-accel {
+  display: none;
+}
+
+.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-link {
+  cursor: pointer;
+}
+
+.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
+  padding: 0.25em;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool {
+  display: inline-block;
+  width: 100%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool-link {
+  display: block;
+  padding-left: 0.5em;
+  white-space: nowrap;
+  cursor: pointer;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+  cursor: default;
+}
+
+.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
+  min-width: 8em;
+}
+
+.oo-ui-menuToolGroup .oo-ui-toolGroup-tools {
+  padding: 0.25em 0 0.25em 0;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool {
+  display: block;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-link {
+  display: block;
+  padding: 0 0.25em 0 1em;
+  white-space: nowrap;
+  cursor: pointer;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  background-image: none;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  background-image: /* @embed */ url(images/icons/check.svg);
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+  cursor: default;
+}
+
+.oo-ui-popupToolGroup {
+  position: relative;
+  height: 2em;
+  min-width: 2.5em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-indicatedElement.oo-ui-iconedElement {
+  min-width: 3.5em;
+}
+
+.oo-ui-popupToolGroup-handle {
+  display: block;
+  cursor: pointer;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator,
+.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
+  position: absolute;
+  top: 0;
+  width: 2em;
+  height: 2em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator {
+  left: 0;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
+  right: 0.25em;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+  margin: 0 1em;
+  font-size: 0.8em;
+  line-height: 2.6em;
+}
+
+.oo-ui-popupToolGroup-header {
+  margin: 0 0.6em;
+  font-size: 0.8em;
+  font-weight: bold;
+  line-height: 2.6em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
+  cursor: default;
+}
+
+.oo-ui-popupToolGroup.oo-ui-iconedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+  margin-right: 3em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-indicatedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+  margin-left: 2.25em;
+}
+
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+  position: absolute;
+  top: 2em;
+  right: -1px;
+  z-index: 4;
+  display: none;
+}
+
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconedElement-icon {
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
+  display: block;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  margin-left: 0.25em;
+  vertical-align: middle;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+  display: inline-block;
+  font-size: 0.8em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-accel {
+  display: none;
+}
+
+.oo-ui-popupTool .oo-ui-popupWidget {
+  margin-right: 1.25em;
+  font-size: 0.8em;
+}
+
+.oo-ui-popupTool .oo-ui-popupWidget-popup,
+.oo-ui-popupTool .oo-ui-popupWidget-anchor {
+  z-index: 4;
+}
+
+.oo-ui-iconWidget {
+  display: inline-block;
+  width: 1.9em;
+  height: 1.9em;
+  line-height: 2.5em;
+  vertical-align: middle;
+  background-position: center center;
+  background-repeat: no-repeat;
+  opacity: 0.8;
+}
+
+.oo-ui-iconWidget.oo-ui-widget-disabled {
+  opacity: 0.2;
+}
+
+.oo-ui-indicatorWidget {
+  display: inline-block;
+  width: 1.9em;
+  height: 1.9em;
+  line-height: 2.5em;
+  vertical-align: middle;
+  background-position: center center;
+  background-repeat: no-repeat;
+  opacity: 0.8;
+}
+
+.oo-ui-indicatorWidget.oo-ui-widget-disabled {
+  opacity: 0.2;
+}
+
+.oo-ui-selectWidget {
+  padding: 0;
+  margin: 0;
+  list-style: none;
+}
+
+.oo-ui-optionWidget {
+  position: relative;
+  display: block;
+  margin: 0;
+  list-style: none;
+  cursor: pointer;
+  border: none;
+}
+
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+  cursor: default;
+}
+
+.oo-ui-optionWidget .oo-ui-labeledElement-label {
+  display: block;
+  overflow: hidden;
+  line-height: 1.5em;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.oo-ui-decoratedOptionWidget .oo-ui-iconedElement-icon,
+.oo-ui-decoratedOptionWidget .oo-ui-indicatedElement-indicator {
+  position: absolute;
+  top: 50%;
+  width: 2em;
+  height: 2em;
+  margin-top: -1em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-decoratedOptionWidget .oo-ui-iconedElement-icon {
+  right: 0.5em;
+}
+
+.oo-ui-decoratedOptionWidget .oo-ui-indicatedElement-indicator {
+  left: 0.5em;
+}
+
+.oo-ui-menuWidget {
+  position: absolute;
+}
+
+.oo-ui-menuWidget input {
+  position: absolute;
+  width: 0;
+  height: 0;
+  overflow: hidden;
+  opacity: 0;
+}
+
+.oo-ui-popupWidget-popup {
+  position: absolute;
+  z-index: 1;
+  overflow: hidden;
+}
+
+.oo-ui-popupWidget-anchor {
+  z-index: 1;
+  display: none;
+}
+
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
+  margin-top: 7px;
+}
+
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
+  position: absolute;
+  display: block;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-popupWidget-head {
+  height: 2.5em;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-popupWidget-head .oo-ui-buttonWidget {
+  float: left;
+  margin: 0.25em;
+}
+
+.oo-ui-popupWidget-head .oo-ui-labeledElement-label {
+  float: right;
+  margin: 0.75em 1em;
+  cursor: default;
+}
+
+.oo-ui-popupWidget-body {
+  overflow: hidden;
+  clear: both;
+}
+
+.oo-ui-popupWidget-body-padded {
+  padding: 0 1em;
+}
+
+.oo-ui-buttonGroupWidget {
+  border-radius: 0.3em;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+  margin-bottom: -1px;
+  margin-right: -1px;
+  border-radius: 0;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:first-child .oo-ui-buttonedElement-button {
+  margin-right: 0;
+  border-bottom-right-radius: 0.3em;
+  border-top-right-radius: 0.3em;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:last-child .oo-ui-buttonedElement-button {
+  border-top-left-radius: 0.3em;
+  border-bottom-left-radius: 0.3em;
+}
+
+.oo-ui-buttonOptionWidget {
+  display: inline-block;
+  background-color: transparent;
+}
+
+.oo-ui-buttonOptionWidget .oo-ui-buttonedElement-button {
+  position: relative;
+  height: 1.9em;
+}
+
+.oo-ui-buttonOptionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon,
+.oo-ui-buttonOptionWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator {
+  position: static;
+  display: inline-block;
+  height: 1.9em;
+  margin-top: 0;
+  vertical-align: middle;
+}
+
+.oo-ui-buttonSelectWidget {
+  display: inline-block;
+  white-space: nowrap;
+}
+
+.oo-ui-buttonWidget {
+  display: inline-block;
+  vertical-align: middle;
+}
+
+.oo-ui-inlineMenuWidget {
+  position: relative;
+  display: inline-block;
+  min-width: 20em;
+  margin: 0.25em 0;
+}
+
+.oo-ui-inlineMenuWidget-handle {
+  display: inline-block;
+  width: 100%;
+  height: 2.5em;
+  cursor: pointer;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-indicatedElement-indicator,
+.oo-ui-inlineMenuWidget-handle .oo-ui-iconedElement-icon {
+  position: absolute;
+  top: 0;
+  width: 2.5em;
+  height: 2.5em;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-indicatedElement-indicator {
+  left: 0;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-iconedElement-icon {
+  right: 0.25em;
+}
+
+.oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
+  margin: 0 0.5em;
+  line-height: 2.5em;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-iconedElement .oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
+  margin-right: 3em;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-indicatedElement .oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
+  margin-left: 2em;
+}
+
+.oo-ui-inlineMenuWidget .oo-ui-menuWidget {
+  z-index: 1;
+  width: 100%;
+}
+
+.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
+  cursor: default;
+}
+
+.oo-ui-menuItemWidget {
+  position: relative;
+}
+
+.oo-ui-menuItemWidget .oo-ui-iconedElement-icon {
+  display: none;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
+  background-color: transparent;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconedElement-icon {
+  display: block;
+}
+
+.oo-ui-menuSectionItemWidget {
+  cursor: default;
+}
+
+.oo-ui-outlineControlsWidget {
+  height: 3em;
+}
+
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+  float: right;
+  height: 2em;
+  padding: 0;
+  margin: 0.5em;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-outlineControlsWidget > .oo-ui-iconedElement-icon {
+  float: right;
+  width: 1.5em;
+  height: 2em;
+  margin: 0.5em 0.5em 0.5em 0;
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-outlineControlsWidget-items {
+  float: right;
+  margin-right: 0;
+}
+
+.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
+  float: right;
+}
+
+.oo-ui-outlineControlsWidget-movers {
+  float: left;
+}
+
+.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
+  float: left;
+}
+
+.oo-ui-outlineItemWidget {
+  position: relative;
+  padding: 0.75em;
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-popupButtonWidget {
+  position: relative;
+}
+
+.oo-ui-popupButtonWidget .oo-ui-popupWidget {
+  position: absolute;
+  right: 1em;
+  cursor: auto;
+}
+
+.oo-ui-searchWidget-query {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 4em;
+  padding: 0 1em;
+}
+
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+  width: 100%;
+  margin: 0.75em 0;
+}
+
+.oo-ui-searchWidget-results {
+  position: absolute;
+  top: 4em;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  padding: 1em;
+  overflow-x: hidden;
+  overflow-y: auto;
+  line-height: 0;
+}
+
+.oo-ui-textInputWidget {
+  position: relative;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+  display: inline-block;
+  width: 100%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  resize: none;
+}
+
+.oo-ui-textInputWidget-icon {
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 100%;
+  background-position: left center;
+  background-repeat: no-repeat;
+}
+
+.oo-ui-toggleSwitchWidget {
+  position: relative;
+  display: inline-block;
+  width: 4em;
+  height: 2em;
+  overflow: hidden;
+  vertical-align: middle;
+  cursor: pointer;
+  -webkit-transform: translateZ(0);
+     -moz-transform: translateZ(0);
+      -ms-transform: translateZ(0);
+       -o-transform: translateZ(0);
+          transform: translateZ(0);
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
+  cursor: default;
+}
+
+.oo-ui-toggleSwitchWidget-grip {
+  position: absolute;
+  top: 0.25em;
+  right: 0.25em;
+  display: block;
+  width: 1.5em;
+  height: 1.5em;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  -webkit-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+     -moz-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+      -ms-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+       -o-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+          transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
+}
+
+.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  -webkit-transition: opacity 200ms ease-in-out;
+     -moz-transition: opacity 200ms ease-in-out;
+      -ms-transition: opacity 200ms ease-in-out;
+       -o-transition: opacity 200ms ease-in-out;
+          transition: opacity 200ms ease-in-out;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  -webkit-touch-callout: none;
+}
+
+.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
+  right: 2.25em;
+  margin-right: -2px;
+}
+
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
+  right: 0.25em;
+  margin-right: 0;
+}
+
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+  display: none;
+}
+
+/* Icons */
+
+.oo-ui-icon-add-item {
+  background-image: /* @embed */ url(images/icons/add-item.svg);
+}
+
+.oo-ui-icon-advanced {
+  background-image: /* @embed */ url(images/icons/advanced.svg);
+}
+
+.oo-ui-icon-alert {
+  background-image: /* @embed */ url(images/icons/alert.svg);
+}
+
+.oo-ui-icon-check {
+  background-image: /* @embed */ url(images/icons/check.svg);
+}
+
+.oo-ui-icon-clear {
+  background-image: /* @embed */ url(images/icons/clear.svg);
+}
+
+.oo-ui-icon-close {
+  background-image: /* @embed */ url(images/icons/close.svg);
+}
+
+.oo-ui-icon-code {
+  background-image: /* @embed */ url(images/icons/code.svg);
+}
+
+.oo-ui-icon-collapse {
+  background-image: /* @embed */ url(images/icons/collapse.svg);
+}
+
+.oo-ui-icon-comment {
+  background-image: /* @embed */ url(images/icons/comment.svg);
+}
+
+.oo-ui-icon-expand {
+  background-image: /* @embed */ url(images/icons/expand.svg);
+}
+
+.oo-ui-icon-help {
+  background-image: /* @embed */ url(images/icons/help.svg);
+}
+
+.oo-ui-icon-info {
+  background-image: /* @embed */ url(images/icons/info.svg);
+}
+
+.oo-ui-icon-link {
+  background-image: /* @embed */ url(images/icons/link.svg);
+}
+
+.oo-ui-icon-menu {
+  background-image: /* @embed */ url(images/icons/menu.svg);
+}
+
+.oo-ui-icon-next {
+  background-image: /* @embed */ url(images/icons/move-rtl.svg);
+}
+
+.oo-ui-icon-picture {
+  background-image: /* @embed */ url(images/icons/picture.svg);
+}
+
+.oo-ui-icon-previous {
+  background-image: /* @embed */ url(images/icons/move-ltr.svg);
+}
+
+.oo-ui-icon-redo {
+  background-image: /* @embed */ url(images/icons/arched-arrow-rtl.svg);
+}
+
+.oo-ui-icon-remove {
+  background-image: /* @embed */ url(images/icons/remove.svg);
+}
+
+.oo-ui-icon-search {
+  background-image: /* @embed */ url(images/icons/search.svg);
+}
+
+.oo-ui-icon-settings {
+  background-image: /* @embed */ url(images/icons/settings.svg);
+}
+
+.oo-ui-icon-tag {
+  background-image: /* @embed */ url(images/icons/tag.svg);
+}
+
+.oo-ui-icon-undo {
+  background-image: /* @embed */ url(images/icons/arched-arrow-ltr.svg);
+}
+
+.oo-ui-icon-window {
+  background-image: /* @embed */ url(images/icons/window.svg);
+}
+
+/* Indicators */
+
+.oo-ui-indicator-alert {
+  background-image: /* @embed */ url(images/indicators/alert.svg);
+}
+
+.oo-ui-indicator-down {
+  background-image: /* @embed */ url(images/indicators/arrow-down.svg);
+}
+
+.oo-ui-indicator-next {
+  background-image: /* @embed */ url(images/indicators/arrow-rtl.svg);
+}
+
+.oo-ui-indicator-previous {
+  background-image: /* @embed */ url(images/indicators/arrow-ltr.svg);
+}
+
+.oo-ui-indicator-required {
+  background-image: /* @embed */ url(images/indicators/required.svg);
+}
+
+.oo-ui-indicator-up {
+  background-image: /* @embed */ url(images/indicators/arrow-up.svg);
+}
\ No newline at end of file
diff --git a/resources/lib/sinonjs/sinon-1.10.3.js b/resources/lib/sinonjs/sinon-1.10.3.js
new file mode 100644 (file)
index 0000000..703414d
--- /dev/null
@@ -0,0 +1,5073 @@
+/**
+ * Sinon.JS 1.10.3, 2014/07/11
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
+ *
+ * (The BSD License)
+ * 
+ * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ *     * Neither the name of Christian Johansen nor the names of his contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+this.sinon = (function () {
+var samsam, formatio;
+function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else if (typeof fn === "function") { formatio = fn(samsam); } }
+define.amd = {};
+((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
+ (typeof module === "object" &&
+      function (m) { module.exports = m(); }) || // Node
+ function (m) { this.samsam = m(); } // Browser globals
+)(function () {
+    var o = Object.prototype;
+    var div = typeof document !== "undefined" && document.createElement("div");
+
+    function isNaN(value) {
+        // Unlike global isNaN, this avoids type coercion
+        // typeof check avoids IE host object issues, hat tip to
+        // lodash
+        var val = value; // JsLint thinks value !== value is "weird"
+        return typeof value === "number" && value !== val;
+    }
+
+    function getClass(value) {
+        // Returns the internal [[Class]] by calling Object.prototype.toString
+        // with the provided value as this. Return value is a string, naming the
+        // internal class, e.g. "Array"
+        return o.toString.call(value).split(/[ \]]/)[1];
+    }
+
+    /**
+     * @name samsam.isArguments
+     * @param Object object
+     *
+     * Returns ``true`` if ``object`` is an ``arguments`` object,
+     * ``false`` otherwise.
+     */
+    function isArguments(object) {
+        if (typeof object !== "object" || typeof object.length !== "number" ||
+                getClass(object) === "Array") {
+            return false;
+        }
+        if (typeof object.callee == "function") { return true; }
+        try {
+            object[object.length] = 6;
+            delete object[object.length];
+        } catch (e) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @name samsam.isElement
+     * @param Object object
+     *
+     * Returns ``true`` if ``object`` is a DOM element node. Unlike
+     * Underscore.js/lodash, this function will return ``false`` if ``object``
+     * is an *element-like* object, i.e. a regular object with a ``nodeType``
+     * property that holds the value ``1``.
+     */
+    function isElement(object) {
+        if (!object || object.nodeType !== 1 || !div) { return false; }
+        try {
+            object.appendChild(div);
+            object.removeChild(div);
+        } catch (e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @name samsam.keys
+     * @param Object object
+     *
+     * Return an array of own property names.
+     */
+    function keys(object) {
+        var ks = [], prop;
+        for (prop in object) {
+            if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
+        }
+        return ks;
+    }
+
+    /**
+     * @name samsam.isDate
+     * @param Object value
+     *
+     * Returns true if the object is a ``Date``, or *date-like*. Duck typing
+     * of date objects work by checking that the object has a ``getTime``
+     * function whose return value equals the return value from the object's
+     * ``valueOf``.
+     */
+    function isDate(value) {
+        return typeof value.getTime == "function" &&
+            value.getTime() == value.valueOf();
+    }
+
+    /**
+     * @name samsam.isNegZero
+     * @param Object value
+     *
+     * Returns ``true`` if ``value`` is ``-0``.
+     */
+    function isNegZero(value) {
+        return value === 0 && 1 / value === -Infinity;
+    }
+
+    /**
+     * @name samsam.equal
+     * @param Object obj1
+     * @param Object obj2
+     *
+     * Returns ``true`` if two objects are strictly equal. Compared to
+     * ``===`` there are two exceptions:
+     *
+     *   - NaN is considered equal to NaN
+     *   - -0 and +0 are not considered equal
+     */
+    function identical(obj1, obj2) {
+        if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
+            return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
+        }
+    }
+
+
+    /**
+     * @name samsam.deepEqual
+     * @param Object obj1
+     * @param Object obj2
+     *
+     * Deep equal comparison. Two values are "deep equal" if:
+     *
+     *   - They are equal, according to samsam.identical
+     *   - They are both date objects representing the same time
+     *   - They are both arrays containing elements that are all deepEqual
+     *   - They are objects with the same set of properties, and each property
+     *     in ``obj1`` is deepEqual to the corresponding property in ``obj2``
+     *
+     * Supports cyclic objects.
+     */
+    function deepEqualCyclic(obj1, obj2) {
+
+        // used for cyclic comparison
+        // contain already visited objects
+        var objects1 = [],
+            objects2 = [],
+        // contain pathes (position in the object structure)
+        // of the already visited objects
+        // indexes same as in objects arrays
+            paths1 = [],
+            paths2 = [],
+        // contains combinations of already compared objects
+        // in the manner: { "$1['ref']$2['ref']": true }
+            compared = {};
+
+        /**
+         * used to check, if the value of a property is an object
+         * (cyclic logic is only needed for objects)
+         * only needed for cyclic logic
+         */
+        function isObject(value) {
+
+            if (typeof value === 'object' && value !== null &&
+                    !(value instanceof Boolean) &&
+                    !(value instanceof Date)    &&
+                    !(value instanceof Number)  &&
+                    !(value instanceof RegExp)  &&
+                    !(value instanceof String)) {
+
+                return true;
+            }
+
+            return false;
+        }
+
+        /**
+         * returns the index of the given object in the
+         * given objects array, -1 if not contained
+         * only needed for cyclic logic
+         */
+        function getIndex(objects, obj) {
+
+            var i;
+            for (i = 0; i < objects.length; i++) {
+                if (objects[i] === obj) {
+                    return i;
+                }
+            }
+
+            return -1;
+        }
+
+        // does the recursion for the deep equal check
+        return (function deepEqual(obj1, obj2, path1, path2) {
+            var type1 = typeof obj1;
+            var type2 = typeof obj2;
+
+            // == null also matches undefined
+            if (obj1 === obj2 ||
+                    isNaN(obj1) || isNaN(obj2) ||
+                    obj1 == null || obj2 == null ||
+                    type1 !== "object" || type2 !== "object") {
+
+                return identical(obj1, obj2);
+            }
+
+            // Elements are only equal if identical(expected, actual)
+            if (isElement(obj1) || isElement(obj2)) { return false; }
+
+            var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
+            if (isDate1 || isDate2) {
+                if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
+                    return false;
+                }
+            }
+
+            if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
+                if (obj1.toString() !== obj2.toString()) { return false; }
+            }
+
+            var class1 = getClass(obj1);
+            var class2 = getClass(obj2);
+            var keys1 = keys(obj1);
+            var keys2 = keys(obj2);
+
+            if (isArguments(obj1) || isArguments(obj2)) {
+                if (obj1.length !== obj2.length) { return false; }
+            } else {
+                if (type1 !== type2 || class1 !== class2 ||
+                        keys1.length !== keys2.length) {
+                    return false;
+                }
+            }
+
+            var key, i, l,
+                // following vars are used for the cyclic logic
+                value1, value2,
+                isObject1, isObject2,
+                index1, index2,
+                newPath1, newPath2;
+
+            for (i = 0, l = keys1.length; i < l; i++) {
+                key = keys1[i];
+                if (!o.hasOwnProperty.call(obj2, key)) {
+                    return false;
+                }
+
+                // Start of the cyclic logic
+
+                value1 = obj1[key];
+                value2 = obj2[key];
+
+                isObject1 = isObject(value1);
+                isObject2 = isObject(value2);
+
+                // determine, if the objects were already visited
+                // (it's faster to check for isObject first, than to
+                // get -1 from getIndex for non objects)
+                index1 = isObject1 ? getIndex(objects1, value1) : -1;
+                index2 = isObject2 ? getIndex(objects2, value2) : -1;
+
+                // determine the new pathes of the objects
+                // - for non cyclic objects the current path will be extended
+                //   by current property name
+                // - for cyclic objects the stored path is taken
+                newPath1 = index1 !== -1
+                    ? paths1[index1]
+                    : path1 + '[' + JSON.stringify(key) + ']';
+                newPath2 = index2 !== -1
+                    ? paths2[index2]
+                    : path2 + '[' + JSON.stringify(key) + ']';
+
+                // stop recursion if current objects are already compared
+                if (compared[newPath1 + newPath2]) {
+                    return true;
+                }
+
+                // remember the current objects and their pathes
+                if (index1 === -1 && isObject1) {
+                    objects1.push(value1);
+                    paths1.push(newPath1);
+                }
+                if (index2 === -1 && isObject2) {
+                    objects2.push(value2);
+                    paths2.push(newPath2);
+                }
+
+                // remember that the current objects are already compared
+                if (isObject1 && isObject2) {
+                    compared[newPath1 + newPath2] = true;
+                }
+
+                // End of cyclic logic
+
+                // neither value1 nor value2 is a cycle
+                // continue with next level
+                if (!deepEqual(value1, value2, newPath1, newPath2)) {
+                    return false;
+                }
+            }
+
+            return true;
+
+        }(obj1, obj2, '$1', '$2'));
+    }
+
+    var match;
+
+    function arrayContains(array, subset) {
+        if (subset.length === 0) { return true; }
+        var i, l, j, k;
+        for (i = 0, l = array.length; i < l; ++i) {
+            if (match(array[i], subset[0])) {
+                for (j = 0, k = subset.length; j < k; ++j) {
+                    if (!match(array[i + j], subset[j])) { return false; }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @name samsam.match
+     * @param Object object
+     * @param Object matcher
+     *
+     * Compare arbitrary value ``object`` with matcher.
+     */
+    match = function match(object, matcher) {
+        if (matcher && typeof matcher.test === "function") {
+            return matcher.test(object);
+        }
+
+        if (typeof matcher === "function") {
+            return matcher(object) === true;
+        }
+
+        if (typeof matcher === "string") {
+            matcher = matcher.toLowerCase();
+            var notNull = typeof object === "string" || !!object;
+            return notNull &&
+                (String(object)).toLowerCase().indexOf(matcher) >= 0;
+        }
+
+        if (typeof matcher === "number") {
+            return matcher === object;
+        }
+
+        if (typeof matcher === "boolean") {
+            return matcher === object;
+        }
+
+        if (getClass(object) === "Array" && getClass(matcher) === "Array") {
+            return arrayContains(object, matcher);
+        }
+
+        if (matcher && typeof matcher === "object") {
+            var prop;
+            for (prop in matcher) {
+                if (!match(object[prop], matcher[prop])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        throw new Error("Matcher was not a string, a number, a " +
+                        "function, a boolean or an object");
+    };
+
+    return {
+        isArguments: isArguments,
+        isElement: isElement,
+        isDate: isDate,
+        isNegZero: isNegZero,
+        identical: identical,
+        deepEqual: deepEqualCyclic,
+        match: match,
+        keys: keys
+    };
+});
+((typeof define === "function" && define.amd && function (m) {
+    define("formatio", ["samsam"], m);
+}) || (typeof module === "object" && function (m) {
+    module.exports = m(require("samsam"));
+}) || function (m) { this.formatio = m(this.samsam); }
+)(function (samsam) {
+    
+    var formatio = {
+        excludeConstructors: ["Object", /^.$/],
+        quoteStrings: true
+    };
+
+    var hasOwn = Object.prototype.hasOwnProperty;
+
+    var specialObjects = [];
+    if (typeof global !== "undefined") {
+        specialObjects.push({ object: global, value: "[object global]" });
+    }
+    if (typeof document !== "undefined") {
+        specialObjects.push({
+            object: document,
+            value: "[object HTMLDocument]"
+        });
+    }
+    if (typeof window !== "undefined") {
+        specialObjects.push({ object: window, value: "[object Window]" });
+    }
+
+    function functionName(func) {
+        if (!func) { return ""; }
+        if (func.displayName) { return func.displayName; }
+        if (func.name) { return func.name; }
+        var matches = func.toString().match(/function\s+([^\(]+)/m);
+        return (matches && matches[1]) || "";
+    }
+
+    function constructorName(f, object) {
+        var name = functionName(object && object.constructor);
+        var excludes = f.excludeConstructors ||
+                formatio.excludeConstructors || [];
+
+        var i, l;
+        for (i = 0, l = excludes.length; i < l; ++i) {
+            if (typeof excludes[i] === "string" && excludes[i] === name) {
+                return "";
+            } else if (excludes[i].test && excludes[i].test(name)) {
+                return "";
+            }
+        }
+
+        return name;
+    }
+
+    function isCircular(object, objects) {
+        if (typeof object !== "object") { return false; }
+        var i, l;
+        for (i = 0, l = objects.length; i < l; ++i) {
+            if (objects[i] === object) { return true; }
+        }
+        return false;
+    }
+
+    function ascii(f, object, processed, indent) {
+        if (typeof object === "string") {
+            var qs = f.quoteStrings;
+            var quote = typeof qs !== "boolean" || qs;
+            return processed || quote ? '"' + object + '"' : object;
+        }
+
+        if (typeof object === "function" && !(object instanceof RegExp)) {
+            return ascii.func(object);
+        }
+
+        processed = processed || [];
+
+        if (isCircular(object, processed)) { return "[Circular]"; }
+
+        if (Object.prototype.toString.call(object) === "[object Array]") {
+            return ascii.array.call(f, object, processed);
+        }
+
+        if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
+        if (samsam.isElement(object)) { return ascii.element(object); }
+
+        if (typeof object.toString === "function" &&
+                object.toString !== Object.prototype.toString) {
+            return object.toString();
+        }
+
+        var i, l;
+        for (i = 0, l = specialObjects.length; i < l; i++) {
+            if (object === specialObjects[i].object) {
+                return specialObjects[i].value;
+            }
+        }
+
+        return ascii.object.call(f, object, processed, indent);
+    }
+
+    ascii.func = function (func) {
+        return "function " + functionName(func) + "() {}";
+    };
+
+    ascii.array = function (array, processed) {
+        processed = processed || [];
+        processed.push(array);
+        var i, l, pieces = [];
+        for (i = 0, l = array.length; i < l; ++i) {
+            pieces.push(ascii(this, array[i], processed));
+        }
+        return "[" + pieces.join(", ") + "]";
+    };
+
+    ascii.object = function (object, processed, indent) {
+        processed = processed || [];
+        processed.push(object);
+        indent = indent || 0;
+        var pieces = [], properties = samsam.keys(object).sort();
+        var length = 3;
+        var prop, str, obj, i, l;
+
+        for (i = 0, l = properties.length; i < l; ++i) {
+            prop = properties[i];
+            obj = object[prop];
+
+            if (isCircular(obj, processed)) {
+                str = "[Circular]";
+            } else {
+                str = ascii(this, obj, processed, indent + 2);
+            }
+
+            str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
+            length += str.length;
+            pieces.push(str);
+        }
+
+        var cons = constructorName(this, object);
+        var prefix = cons ? "[" + cons + "] " : "";
+        var is = "";
+        for (i = 0, l = indent; i < l; ++i) { is += " "; }
+
+        if (length + indent > 80) {
+            return prefix + "{\n  " + is + pieces.join(",\n  " + is) + "\n" +
+                is + "}";
+        }
+        return prefix + "{ " + pieces.join(", ") + " }";
+    };
+
+    ascii.element = function (element) {
+        var tagName = element.tagName.toLowerCase();
+        var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
+
+        for (i = 0, l = attrs.length; i < l; ++i) {
+            attr = attrs.item(i);
+            attrName = attr.nodeName.toLowerCase().replace("html:", "");
+            val = attr.nodeValue;
+            if (attrName !== "contenteditable" || val !== "inherit") {
+                if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
+            }
+        }
+
+        var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
+        var content = element.innerHTML;
+
+        if (content.length > 20) {
+            content = content.substr(0, 20) + "[...]";
+        }
+
+        var res = formatted + pairs.join(" ") + ">" + content +
+                "</" + tagName + ">";
+
+        return res.replace(/ contentEditable="inherit"/, "");
+    };
+
+    function Formatio(options) {
+        for (var opt in options) {
+            this[opt] = options[opt];
+        }
+    }
+
+    Formatio.prototype = {
+        functionName: functionName,
+
+        configure: function (options) {
+            return new Formatio(options);
+        },
+
+        constructorName: function (object) {
+            return constructorName(this, object);
+        },
+
+        ascii: function (object, processed, indent) {
+            return ascii(this, object, processed, indent);
+        }
+    };
+
+    return Formatio.prototype;
+});
+/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
+/*global module, require, __dirname, document*/
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+var sinon = (function (formatio) {
+    var div = typeof document != "undefined" && document.createElement("div");
+    var hasOwn = Object.prototype.hasOwnProperty;
+
+    function isDOMNode(obj) {
+        var success = false;
+
+        try {
+            obj.appendChild(div);
+            success = div.parentNode == obj;
+        } catch (e) {
+            return false;
+        } finally {
+            try {
+                obj.removeChild(div);
+            } catch (e) {
+                // Remove failed, not much we can do about that
+            }
+        }
+
+        return success;
+    }
+
+    function isElement(obj) {
+        return div && obj && obj.nodeType === 1 && isDOMNode(obj);
+    }
+
+    function isFunction(obj) {
+        return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
+    }
+
+    function isReallyNaN(val) {
+        return typeof val === 'number' && isNaN(val);
+    }
+
+    function mirrorProperties(target, source) {
+        for (var prop in source) {
+            if (!hasOwn.call(target, prop)) {
+                target[prop] = source[prop];
+            }
+        }
+    }
+
+    function isRestorable (obj) {
+        return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
+    }
+
+    var sinon = {
+        wrapMethod: function wrapMethod(object, property, method) {
+            if (!object) {
+                throw new TypeError("Should wrap property of object");
+            }
+
+            if (typeof method != "function") {
+                throw new TypeError("Method wrapper should be function");
+            }
+
+            var wrappedMethod = object[property],
+                error;
+
+            if (!isFunction(wrappedMethod)) {
+                error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+                                    property + " as function");
+            } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
+                error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
+            } else if (wrappedMethod.calledBefore) {
+                var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
+                error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
+            }
+
+            if (error) {
+                if (wrappedMethod && wrappedMethod._stack) {
+                    error.stack += '\n--------------\n' + wrappedMethod._stack;
+                }
+                throw error;
+            }
+
+            // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
+            // when using hasOwn.call on objects from other frames.
+            var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
+            object[property] = method;
+            method.displayName = property;
+            // Set up a stack trace which can be used later to find what line of
+            // code the original method was created on.
+            method._stack = (new Error('Stack Trace for original')).stack;
+
+            method.restore = function () {
+                // For prototype properties try to reset by delete first.
+                // If this fails (ex: localStorage on mobile safari) then force a reset
+                // via direct assignment.
+                if (!owned) {
+                    delete object[property];
+                }
+                if (object[property] === method) {
+                    object[property] = wrappedMethod;
+                }
+            };
+
+            method.restore.sinon = true;
+            mirrorProperties(method, wrappedMethod);
+
+            return method;
+        },
+
+        extend: function extend(target) {
+            for (var i = 1, l = arguments.length; i < l; i += 1) {
+                for (var prop in arguments[i]) {
+                    if (arguments[i].hasOwnProperty(prop)) {
+                        target[prop] = arguments[i][prop];
+                    }
+
+                    // DONT ENUM bug, only care about toString
+                    if (arguments[i].hasOwnProperty("toString") &&
+                        arguments[i].toString != target.toString) {
+                        target.toString = arguments[i].toString;
+                    }
+                }
+            }
+
+            return target;
+        },
+
+        create: function create(proto) {
+            var F = function () {};
+            F.prototype = proto;
+            return new F();
+        },
+
+        deepEqual: function deepEqual(a, b) {
+            if (sinon.match && sinon.match.isMatcher(a)) {
+                return a.test(b);
+            }
+
+            if (typeof a != 'object' || typeof b != 'object') {
+                if (isReallyNaN(a) && isReallyNaN(b)) {
+                    return true;
+                } else {
+                    return a === b;
+                }
+            }
+
+            if (isElement(a) || isElement(b)) {
+                return a === b;
+            }
+
+            if (a === b) {
+                return true;
+            }
+
+            if ((a === null && b !== null) || (a !== null && b === null)) {
+                return false;
+            }
+
+            if (a instanceof RegExp && b instanceof RegExp) {
+              return (a.source === b.source) && (a.global === b.global) &&
+                (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
+            }
+
+            var aString = Object.prototype.toString.call(a);
+            if (aString != Object.prototype.toString.call(b)) {
+                return false;
+            }
+
+            if (aString == "[object Date]") {
+                return a.valueOf() === b.valueOf();
+            }
+
+            var prop, aLength = 0, bLength = 0;
+
+            if (aString == "[object Array]" && a.length !== b.length) {
+                return false;
+            }
+
+            for (prop in a) {
+                aLength += 1;
+
+                if (!(prop in b)) {
+                    return false;
+                }
+
+                if (!deepEqual(a[prop], b[prop])) {
+                    return false;
+                }
+            }
+
+            for (prop in b) {
+                bLength += 1;
+            }
+
+            return aLength == bLength;
+        },
+
+        functionName: function functionName(func) {
+            var name = func.displayName || func.name;
+
+            // Use function decomposition as a last resort to get function
+            // name. Does not rely on function decomposition to work - if it
+            // doesn't debugging will be slightly less informative
+            // (i.e. toString will say 'spy' rather than 'myFunc').
+            if (!name) {
+                var matches = func.toString().match(/function ([^\s\(]+)/);
+                name = matches && matches[1];
+            }
+
+            return name;
+        },
+
+        functionToString: function toString() {
+            if (this.getCall && this.callCount) {
+                var thisValue, prop, i = this.callCount;
+
+                while (i--) {
+                    thisValue = this.getCall(i).thisValue;
+
+                    for (prop in thisValue) {
+                        if (thisValue[prop] === this) {
+                            return prop;
+                        }
+                    }
+                }
+            }
+
+            return this.displayName || "sinon fake";
+        },
+
+        getConfig: function (custom) {
+            var config = {};
+            custom = custom || {};
+            var defaults = sinon.defaultConfig;
+
+            for (var prop in defaults) {
+                if (defaults.hasOwnProperty(prop)) {
+                    config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
+                }
+            }
+
+            return config;
+        },
+
+        format: function (val) {
+            return "" + val;
+        },
+
+        defaultConfig: {
+            injectIntoThis: true,
+            injectInto: null,
+            properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+            useFakeTimers: true,
+            useFakeServer: true
+        },
+
+        timesInWords: function timesInWords(count) {
+            return count == 1 && "once" ||
+                count == 2 && "twice" ||
+                count == 3 && "thrice" ||
+                (count || 0) + " times";
+        },
+
+        calledInOrder: function (spies) {
+            for (var i = 1, l = spies.length; i < l; i++) {
+                if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
+                    return false;
+                }
+            }
+
+            return true;
+        },
+
+        orderByFirstCall: function (spies) {
+            return spies.sort(function (a, b) {
+                // uuid, won't ever be equal
+                var aCall = a.getCall(0);
+                var bCall = b.getCall(0);
+                var aId = aCall && aCall.callId || -1;
+                var bId = bCall && bCall.callId || -1;
+
+                return aId < bId ? -1 : 1;
+            });
+        },
+
+        log: function () {},
+
+        logError: function (label, err) {
+            var msg = label + " threw exception: ";
+            sinon.log(msg + "[" + err.name + "] " + err.message);
+            if (err.stack) { sinon.log(err.stack); }
+
+            setTimeout(function () {
+                err.message = msg + err.message;
+                throw err;
+            }, 0);
+        },
+
+        typeOf: function (value) {
+            if (value === null) {
+                return "null";
+            }
+            else if (value === undefined) {
+                return "undefined";
+            }
+            var string = Object.prototype.toString.call(value);
+            return string.substring(8, string.length - 1).toLowerCase();
+        },
+
+        createStubInstance: function (constructor) {
+            if (typeof constructor !== "function") {
+                throw new TypeError("The constructor should be a function.");
+            }
+            return sinon.stub(sinon.create(constructor.prototype));
+        },
+
+        restore: function (object) {
+            if (object !== null && typeof object === "object") {
+                for (var prop in object) {
+                    if (isRestorable(object[prop])) {
+                        object[prop].restore();
+                    }
+                }
+            }
+            else if (isRestorable(object)) {
+                object.restore();
+            }
+        }
+    };
+
+    var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+    var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
+
+    function makePublicAPI(require, exports, module) {
+        module.exports = sinon;
+        sinon.spy = require("./sinon/spy");
+        sinon.spyCall = require("./sinon/call");
+        sinon.behavior = require("./sinon/behavior");
+        sinon.stub = require("./sinon/stub");
+        sinon.mock = require("./sinon/mock");
+        sinon.collection = require("./sinon/collection");
+        sinon.assert = require("./sinon/assert");
+        sinon.sandbox = require("./sinon/sandbox");
+        sinon.test = require("./sinon/test");
+        sinon.testCase = require("./sinon/test_case");
+        sinon.match = require("./sinon/match");
+    }
+
+    if (isAMD) {
+        define(makePublicAPI);
+    } else if (isNode) {
+        try {
+            formatio = require("formatio");
+        } catch (e) {}
+        makePublicAPI(require, exports, module);
+    }
+
+    if (formatio) {
+        var formatter = formatio.configure({ quoteStrings: false });
+        sinon.format = function () {
+            return formatter.ascii.apply(formatter, arguments);
+        };
+    } else if (isNode) {
+        try {
+            var util = require("util");
+            sinon.format = function (value) {
+                return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
+            };
+        } catch (e) {
+            /* Node, but no util module - would be very old, but better safe than
+             sorry */
+        }
+    }
+
+    return sinon;
+}(typeof formatio == "object" && formatio));
+
+/* @depend ../sinon.js */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Match functions
+ *
+ * @author Maximilian Antoni (mail@maxantoni.de)
+ * @license BSD
+ *
+ * Copyright (c) 2012 Maximilian Antoni
+ */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    function assertType(value, type, name) {
+        var actual = sinon.typeOf(value);
+        if (actual !== type) {
+            throw new TypeError("Expected type of " + name + " to be " +
+                type + ", but was " + actual);
+        }
+    }
+
+    var matcher = {
+        toString: function () {
+            return this.message;
+        }
+    };
+
+    function isMatcher(object) {
+        return matcher.isPrototypeOf(object);
+    }
+
+    function matchObject(expectation, actual) {
+        if (actual === null || actual === undefined) {
+            return false;
+        }
+        for (var key in expectation) {
+            if (expectation.hasOwnProperty(key)) {
+                var exp = expectation[key];
+                var act = actual[key];
+                if (match.isMatcher(exp)) {
+                    if (!exp.test(act)) {
+                        return false;
+                    }
+                } else if (sinon.typeOf(exp) === "object") {
+                    if (!matchObject(exp, act)) {
+                        return false;
+                    }
+                } else if (!sinon.deepEqual(exp, act)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    matcher.or = function (m2) {
+        if (!arguments.length) {
+            throw new TypeError("Matcher expected");
+        } else if (!isMatcher(m2)) {
+            m2 = match(m2);
+        }
+        var m1 = this;
+        var or = sinon.create(matcher);
+        or.test = function (actual) {
+            return m1.test(actual) || m2.test(actual);
+        };
+        or.message = m1.message + ".or(" + m2.message + ")";
+        return or;
+    };
+
+    matcher.and = function (m2) {
+        if (!arguments.length) {
+            throw new TypeError("Matcher expected");
+        } else if (!isMatcher(m2)) {
+            m2 = match(m2);
+        }
+        var m1 = this;
+        var and = sinon.create(matcher);
+        and.test = function (actual) {
+            return m1.test(actual) && m2.test(actual);
+        };
+        and.message = m1.message + ".and(" + m2.message + ")";
+        return and;
+    };
+
+    var match = function (expectation, message) {
+        var m = sinon.create(matcher);
+        var type = sinon.typeOf(expectation);
+        switch (type) {
+        case "object":
+            if (typeof expectation.test === "function") {
+                m.test = function (actual) {
+                    return expectation.test(actual) === true;
+                };
+                m.message = "match(" + sinon.functionName(expectation.test) + ")";
+                return m;
+            }
+            var str = [];
+            for (var key in expectation) {
+                if (expectation.hasOwnProperty(key)) {
+                    str.push(key + ": " + expectation[key]);
+                }
+            }
+            m.test = function (actual) {
+                return matchObject(expectation, actual);
+            };
+            m.message = "match(" + str.join(", ") + ")";
+            break;
+        case "number":
+            m.test = function (actual) {
+                return expectation == actual;
+            };
+            break;
+        case "string":
+            m.test = function (actual) {
+                if (typeof actual !== "string") {
+                    return false;
+                }
+                return actual.indexOf(expectation) !== -1;
+            };
+            m.message = "match(\"" + expectation + "\")";
+            break;
+        case "regexp":
+            m.test = function (actual) {
+                if (typeof actual !== "string") {
+                    return false;
+                }
+                return expectation.test(actual);
+            };
+            break;
+        case "function":
+            m.test = expectation;
+            if (message) {
+                m.message = message;
+            } else {
+                m.message = "match(" + sinon.functionName(expectation) + ")";
+            }
+            break;
+        default:
+            m.test = function (actual) {
+              return sinon.deepEqual(expectation, actual);
+            };
+        }
+        if (!m.message) {
+            m.message = "match(" + expectation + ")";
+        }
+        return m;
+    };
+
+    match.isMatcher = isMatcher;
+
+    match.any = match(function () {
+        return true;
+    }, "any");
+
+    match.defined = match(function (actual) {
+        return actual !== null && actual !== undefined;
+    }, "defined");
+
+    match.truthy = match(function (actual) {
+        return !!actual;
+    }, "truthy");
+
+    match.falsy = match(function (actual) {
+        return !actual;
+    }, "falsy");
+
+    match.same = function (expectation) {
+        return match(function (actual) {
+            return expectation === actual;
+        }, "same(" + expectation + ")");
+    };
+
+    match.typeOf = function (type) {
+        assertType(type, "string", "type");
+        return match(function (actual) {
+            return sinon.typeOf(actual) === type;
+        }, "typeOf(\"" + type + "\")");
+    };
+
+    match.instanceOf = function (type) {
+        assertType(type, "function", "type");
+        return match(function (actual) {
+            return actual instanceof type;
+        }, "instanceOf(" + sinon.functionName(type) + ")");
+    };
+
+    function createPropertyMatcher(propertyTest, messagePrefix) {
+        return function (property, value) {
+            assertType(property, "string", "property");
+            var onlyProperty = arguments.length === 1;
+            var message = messagePrefix + "(\"" + property + "\"";
+            if (!onlyProperty) {
+                message += ", " + value;
+            }
+            message += ")";
+            return match(function (actual) {
+                if (actual === undefined || actual === null ||
+                        !propertyTest(actual, property)) {
+                    return false;
+                }
+                return onlyProperty || sinon.deepEqual(value, actual[property]);
+            }, message);
+        };
+    }
+
+    match.has = createPropertyMatcher(function (actual, property) {
+        if (typeof actual === "object") {
+            return property in actual;
+        }
+        return actual[property] !== undefined;
+    }, "has");
+
+    match.hasOwn = createPropertyMatcher(function (actual, property) {
+        return actual.hasOwnProperty(property);
+    }, "hasOwn");
+
+    match.bool = match.typeOf("boolean");
+    match.number = match.typeOf("number");
+    match.string = match.typeOf("string");
+    match.object = match.typeOf("object");
+    match.func = match.typeOf("function");
+    match.array = match.typeOf("array");
+    match.regexp = match.typeOf("regexp");
+    match.date = match.typeOf("date");
+
+    sinon.match = match;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = match; });
+    } else if (commonJSModule) {
+        module.exports = match;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+  * @depend ../sinon.js
+  * @depend match.js
+  */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+  * Spy calls
+  *
+  * @author Christian Johansen (christian@cjohansen.no)
+  * @author Maximilian Antoni (mail@maxantoni.de)
+  * @license BSD
+  *
+  * Copyright (c) 2010-2013 Christian Johansen
+  * Copyright (c) 2013 Maximilian Antoni
+  */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    function throwYieldError(proxy, text, args) {
+        var msg = sinon.functionName(proxy) + text;
+        if (args.length) {
+            msg += " Received [" + slice.call(args).join(", ") + "]";
+        }
+        throw new Error(msg);
+    }
+
+    var slice = Array.prototype.slice;
+
+    var callProto = {
+        calledOn: function calledOn(thisValue) {
+            if (sinon.match && sinon.match.isMatcher(thisValue)) {
+                return thisValue.test(this.thisValue);
+            }
+            return this.thisValue === thisValue;
+        },
+
+        calledWith: function calledWith() {
+            for (var i = 0, l = arguments.length; i < l; i += 1) {
+                if (!sinon.deepEqual(arguments[i], this.args[i])) {
+                    return false;
+                }
+            }
+
+            return true;
+        },
+
+        calledWithMatch: function calledWithMatch() {
+            for (var i = 0, l = arguments.length; i < l; i += 1) {
+                var actual = this.args[i];
+                var expectation = arguments[i];
+                if (!sinon.match || !sinon.match(expectation).test(actual)) {
+                    return false;
+                }
+            }
+            return true;
+        },
+
+        calledWithExactly: function calledWithExactly() {
+            return arguments.length == this.args.length &&
+                this.calledWith.apply(this, arguments);
+        },
+
+        notCalledWith: function notCalledWith() {
+            return !this.calledWith.apply(this, arguments);
+        },
+
+        notCalledWithMatch: function notCalledWithMatch() {
+            return !this.calledWithMatch.apply(this, arguments);
+        },
+
+        returned: function returned(value) {
+            return sinon.deepEqual(value, this.returnValue);
+        },
+
+        threw: function threw(error) {
+            if (typeof error === "undefined" || !this.exception) {
+                return !!this.exception;
+            }
+
+            return this.exception === error || this.exception.name === error;
+        },
+
+        calledWithNew: function calledWithNew() {
+            return this.proxy.prototype && this.thisValue instanceof this.proxy;
+        },
+
+        calledBefore: function (other) {
+            return this.callId < other.callId;
+        },
+
+        calledAfter: function (other) {
+            return this.callId > other.callId;
+        },
+
+        callArg: function (pos) {
+            this.args[pos]();
+        },
+
+        callArgOn: function (pos, thisValue) {
+            this.args[pos].apply(thisValue);
+        },
+
+        callArgWith: function (pos) {
+            this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
+        },
+
+        callArgOnWith: function (pos, thisValue) {
+            var args = slice.call(arguments, 2);
+            this.args[pos].apply(thisValue, args);
+        },
+
+        "yield": function () {
+            this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
+        },
+
+        yieldOn: function (thisValue) {
+            var args = this.args;
+            for (var i = 0, l = args.length; i < l; ++i) {
+                if (typeof args[i] === "function") {
+                    args[i].apply(thisValue, slice.call(arguments, 1));
+                    return;
+                }
+            }
+            throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
+        },
+
+        yieldTo: function (prop) {
+            this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
+        },
+
+        yieldToOn: function (prop, thisValue) {
+            var args = this.args;
+            for (var i = 0, l = args.length; i < l; ++i) {
+                if (args[i] && typeof args[i][prop] === "function") {
+                    args[i][prop].apply(thisValue, slice.call(arguments, 2));
+                    return;
+                }
+            }
+            throwYieldError(this.proxy, " cannot yield to '" + prop +
+                "' since no callback was passed.", args);
+        },
+
+        toString: function () {
+            var callStr = this.proxy.toString() + "(";
+            var args = [];
+
+            for (var i = 0, l = this.args.length; i < l; ++i) {
+                args.push(sinon.format(this.args[i]));
+            }
+
+            callStr = callStr + args.join(", ") + ")";
+
+            if (typeof this.returnValue != "undefined") {
+                callStr += " => " + sinon.format(this.returnValue);
+            }
+
+            if (this.exception) {
+                callStr += " !" + this.exception.name;
+
+                if (this.exception.message) {
+                    callStr += "(" + this.exception.message + ")";
+                }
+            }
+
+            return callStr;
+        }
+    };
+
+    callProto.invokeCallback = callProto.yield;
+
+    function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
+        if (typeof id !== "number") {
+            throw new TypeError("Call id is not a number");
+        }
+        var proxyCall = sinon.create(callProto);
+        proxyCall.proxy = spy;
+        proxyCall.thisValue = thisValue;
+        proxyCall.args = args;
+        proxyCall.returnValue = returnValue;
+        proxyCall.exception = exception;
+        proxyCall.callId = id;
+
+        return proxyCall;
+    }
+    createSpyCall.toString = callProto.toString; // used by mocks
+
+    sinon.spyCall = createSpyCall;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = createSpyCall; });
+    } else if (commonJSModule) {
+        module.exports = createSpyCall;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+
+/**
+  * @depend ../sinon.js
+  * @depend call.js
+  */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+  * Spy functions
+  *
+  * @author Christian Johansen (christian@cjohansen.no)
+  * @license BSD
+  *
+  * Copyright (c) 2010-2013 Christian Johansen
+  */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+    var push = Array.prototype.push;
+    var slice = Array.prototype.slice;
+    var callId = 0;
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    function spy(object, property) {
+        if (!property && typeof object == "function") {
+            return spy.create(object);
+        }
+
+        if (!object && !property) {
+            return spy.create(function () { });
+        }
+
+        var method = object[property];
+        return sinon.wrapMethod(object, property, spy.create(method));
+    }
+
+    function matchingFake(fakes, args, strict) {
+        if (!fakes) {
+            return;
+        }
+
+        for (var i = 0, l = fakes.length; i < l; i++) {
+            if (fakes[i].matches(args, strict)) {
+                return fakes[i];
+            }
+        }
+    }
+
+    function incrementCallCount() {
+        this.called = true;
+        this.callCount += 1;
+        this.notCalled = false;
+        this.calledOnce = this.callCount == 1;
+        this.calledTwice = this.callCount == 2;
+        this.calledThrice = this.callCount == 3;
+    }
+
+    function createCallProperties() {
+        this.firstCall = this.getCall(0);
+        this.secondCall = this.getCall(1);
+        this.thirdCall = this.getCall(2);
+        this.lastCall = this.getCall(this.callCount - 1);
+    }
+
+    var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
+    function createProxy(func) {
+        // Retain the function length:
+        var p;
+        if (func.length) {
+            eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
+                ") { return p.invoke(func, this, slice.call(arguments)); });");
+        }
+        else {
+            p = function proxy() {
+                return p.invoke(func, this, slice.call(arguments));
+            };
+        }
+        return p;
+    }
+
+    var uuid = 0;
+
+    // Public API
+    var spyApi = {
+        reset: function () {
+            this.called = false;
+            this.notCalled = true;
+            this.calledOnce = false;
+            this.calledTwice = false;
+            this.calledThrice = false;
+            this.callCount = 0;
+            this.firstCall = null;
+            this.secondCall = null;
+            this.thirdCall = null;
+            this.lastCall = null;
+            this.args = [];
+            this.returnValues = [];
+            this.thisValues = [];
+            this.exceptions = [];
+            this.callIds = [];
+            if (this.fakes) {
+                for (var i = 0; i < this.fakes.length; i++) {
+                    this.fakes[i].reset();
+                }
+            }
+        },
+
+        create: function create(func) {
+            var name;
+
+            if (typeof func != "function") {
+                func = function () { };
+            } else {
+                name = sinon.functionName(func);
+            }
+
+            var proxy = createProxy(func);
+
+            sinon.extend(proxy, spy);
+            delete proxy.create;
+            sinon.extend(proxy, func);
+
+            proxy.reset();
+            proxy.prototype = func.prototype;
+            proxy.displayName = name || "spy";
+            proxy.toString = sinon.functionToString;
+            proxy._create = sinon.spy.create;
+            proxy.id = "spy#" + uuid++;
+
+            return proxy;
+        },
+
+        invoke: function invoke(func, thisValue, args) {
+            var matching = matchingFake(this.fakes, args);
+            var exception, returnValue;
+
+            incrementCallCount.call(this);
+            push.call(this.thisValues, thisValue);
+            push.call(this.args, args);
+            push.call(this.callIds, callId++);
+
+            // Make call properties available from within the spied function:
+            createCallProperties.call(this);
+
+            try {
+                if (matching) {
+                    returnValue = matching.invoke(func, thisValue, args);
+                } else {
+                    returnValue = (this.func || func).apply(thisValue, args);
+                }
+
+                var thisCall = this.getCall(this.callCount - 1);
+                if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
+                    returnValue = thisValue;
+                }
+            } catch (e) {
+                exception = e;
+            }
+
+            push.call(this.exceptions, exception);
+            push.call(this.returnValues, returnValue);
+
+            // Make return value and exception available in the calls:
+            createCallProperties.call(this);
+
+            if (exception !== undefined) {
+                throw exception;
+            }
+
+            return returnValue;
+        },
+
+        named: function named(name) {
+            this.displayName = name;
+            return this;
+        },
+
+        getCall: function getCall(i) {
+            if (i < 0 || i >= this.callCount) {
+                return null;
+            }
+
+            return sinon.spyCall(this, this.thisValues[i], this.args[i],
+                                    this.returnValues[i], this.exceptions[i],
+                                    this.callIds[i]);
+        },
+
+        getCalls: function () {
+            var calls = [];
+            var i;
+
+            for (i = 0; i < this.callCount; i++) {
+                calls.push(this.getCall(i));
+            }
+
+            return calls;
+        },
+
+        calledBefore: function calledBefore(spyFn) {
+            if (!this.called) {
+                return false;
+            }
+
+            if (!spyFn.called) {
+                return true;
+            }
+
+            return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
+        },
+
+        calledAfter: function calledAfter(spyFn) {
+            if (!this.called || !spyFn.called) {
+                return false;
+            }
+
+            return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
+        },
+
+        withArgs: function () {
+            var args = slice.call(arguments);
+
+            if (this.fakes) {
+                var match = matchingFake(this.fakes, args, true);
+
+                if (match) {
+                    return match;
+                }
+            } else {
+                this.fakes = [];
+            }
+
+            var original = this;
+            var fake = this._create();
+            fake.matchingAguments = args;
+            fake.parent = this;
+            push.call(this.fakes, fake);
+
+            fake.withArgs = function () {
+                return original.withArgs.apply(original, arguments);
+            };
+
+            for (var i = 0; i < this.args.length; i++) {
+                if (fake.matches(this.args[i])) {
+                    incrementCallCount.call(fake);
+                    push.call(fake.thisValues, this.thisValues[i]);
+                    push.call(fake.args, this.args[i]);
+                    push.call(fake.returnValues, this.returnValues[i]);
+                    push.call(fake.exceptions, this.exceptions[i]);
+                    push.call(fake.callIds, this.callIds[i]);
+                }
+            }
+            createCallProperties.call(fake);
+
+            return fake;
+        },
+
+        matches: function (args, strict) {
+            var margs = this.matchingAguments;
+
+            if (margs.length <= args.length &&
+                sinon.deepEqual(margs, args.slice(0, margs.length))) {
+                return !strict || margs.length == args.length;
+            }
+        },
+
+        printf: function (format) {
+            var spy = this;
+            var args = slice.call(arguments, 1);
+            var formatter;
+
+            return (format || "").replace(/%(.)/g, function (match, specifyer) {
+                formatter = spyApi.formatters[specifyer];
+
+                if (typeof formatter == "function") {
+                    return formatter.call(null, spy, args);
+                } else if (!isNaN(parseInt(specifyer, 10))) {
+                    return sinon.format(args[specifyer - 1]);
+                }
+
+                return "%" + specifyer;
+            });
+        }
+    };
+
+    function delegateToCalls(method, matchAny, actual, notCalled) {
+        spyApi[method] = function () {
+            if (!this.called) {
+                if (notCalled) {
+                    return notCalled.apply(this, arguments);
+                }
+                return false;
+            }
+
+            var currentCall;
+            var matches = 0;
+
+            for (var i = 0, l = this.callCount; i < l; i += 1) {
+                currentCall = this.getCall(i);
+
+                if (currentCall[actual || method].apply(currentCall, arguments)) {
+                    matches += 1;
+
+                    if (matchAny) {
+                        return true;
+                    }
+                }
+            }
+
+            return matches === this.callCount;
+        };
+    }
+
+    delegateToCalls("calledOn", true);
+    delegateToCalls("alwaysCalledOn", false, "calledOn");
+    delegateToCalls("calledWith", true);
+    delegateToCalls("calledWithMatch", true);
+    delegateToCalls("alwaysCalledWith", false, "calledWith");
+    delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
+    delegateToCalls("calledWithExactly", true);
+    delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
+    delegateToCalls("neverCalledWith", false, "notCalledWith",
+        function () { return true; });
+    delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
+        function () { return true; });
+    delegateToCalls("threw", true);
+    delegateToCalls("alwaysThrew", false, "threw");
+    delegateToCalls("returned", true);
+    delegateToCalls("alwaysReturned", false, "returned");
+    delegateToCalls("calledWithNew", true);
+    delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
+    delegateToCalls("callArg", false, "callArgWith", function () {
+        throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+    });
+    spyApi.callArgWith = spyApi.callArg;
+    delegateToCalls("callArgOn", false, "callArgOnWith", function () {
+        throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+    });
+    spyApi.callArgOnWith = spyApi.callArgOn;
+    delegateToCalls("yield", false, "yield", function () {
+        throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+    });
+    // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
+    spyApi.invokeCallback = spyApi.yield;
+    delegateToCalls("yieldOn", false, "yieldOn", function () {
+        throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+    });
+    delegateToCalls("yieldTo", false, "yieldTo", function (property) {
+        throw new Error(this.toString() + " cannot yield to '" + property +
+            "' since it was not yet invoked.");
+    });
+    delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
+        throw new Error(this.toString() + " cannot yield to '" + property +
+            "' since it was not yet invoked.");
+    });
+
+    spyApi.formatters = {
+        "c": function (spy) {
+            return sinon.timesInWords(spy.callCount);
+        },
+
+        "n": function (spy) {
+            return spy.toString();
+        },
+
+        "C": function (spy) {
+            var calls = [];
+
+            for (var i = 0, l = spy.callCount; i < l; ++i) {
+                var stringifiedCall = "    " + spy.getCall(i).toString();
+                if (/\n/.test(calls[i - 1])) {
+                    stringifiedCall = "\n" + stringifiedCall;
+                }
+                push.call(calls, stringifiedCall);
+            }
+
+            return calls.length > 0 ? "\n" + calls.join("\n") : "";
+        },
+
+        "t": function (spy) {
+            var objects = [];
+
+            for (var i = 0, l = spy.callCount; i < l; ++i) {
+                push.call(objects, sinon.format(spy.thisValues[i]));
+            }
+
+            return objects.join(", ");
+        },
+
+        "*": function (spy, args) {
+            var formatted = [];
+
+            for (var i = 0, l = args.length; i < l; ++i) {
+                push.call(formatted, sinon.format(args[i]));
+            }
+
+            return formatted.join(", ");
+        }
+    };
+
+    sinon.extend(spy, spyApi);
+
+    spy.spyCall = sinon.spyCall;
+    sinon.spy = spy;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = spy; });
+    } else if (commonJSModule) {
+        module.exports = spy;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global module, require, sinon, process, setImmediate, setTimeout*/
+/**
+ * Stub behavior
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Tim Fischbach (mail@timfischbach.de)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    var slice = Array.prototype.slice;
+    var join = Array.prototype.join;
+    var proto;
+
+    var nextTick = (function () {
+        if (typeof process === "object" && typeof process.nextTick === "function") {
+            return process.nextTick;
+        } else if (typeof setImmediate === "function") {
+            return setImmediate;
+        } else {
+            return function (callback) {
+                setTimeout(callback, 0);
+            };
+        }
+    })();
+
+    function throwsException(error, message) {
+        if (typeof error == "string") {
+            this.exception = new Error(message || "");
+            this.exception.name = error;
+        } else if (!error) {
+            this.exception = new Error("Error");
+        } else {
+            this.exception = error;
+        }
+
+        return this;
+    }
+
+    function getCallback(behavior, args) {
+        var callArgAt = behavior.callArgAt;
+
+        if (callArgAt < 0) {
+            var callArgProp = behavior.callArgProp;
+
+            for (var i = 0, l = args.length; i < l; ++i) {
+                if (!callArgProp && typeof args[i] == "function") {
+                    return args[i];
+                }
+
+                if (callArgProp && args[i] &&
+                    typeof args[i][callArgProp] == "function") {
+                    return args[i][callArgProp];
+                }
+            }
+
+            return null;
+        }
+
+        return args[callArgAt];
+    }
+
+    function getCallbackError(behavior, func, args) {
+        if (behavior.callArgAt < 0) {
+            var msg;
+
+            if (behavior.callArgProp) {
+                msg = sinon.functionName(behavior.stub) +
+                    " expected to yield to '" + behavior.callArgProp +
+                    "', but no object with such a property was passed.";
+            } else {
+                msg = sinon.functionName(behavior.stub) +
+                    " expected to yield, but no callback was passed.";
+            }
+
+            if (args.length > 0) {
+                msg += " Received [" + join.call(args, ", ") + "]";
+            }
+
+            return msg;
+        }
+
+        return "argument at index " + behavior.callArgAt + " is not a function: " + func;
+    }
+
+    function callCallback(behavior, args) {
+        if (typeof behavior.callArgAt == "number") {
+            var func = getCallback(behavior, args);
+
+            if (typeof func != "function") {
+                throw new TypeError(getCallbackError(behavior, func, args));
+            }
+
+            if (behavior.callbackAsync) {
+                nextTick(function() {
+                    func.apply(behavior.callbackContext, behavior.callbackArguments);
+                });
+            } else {
+                func.apply(behavior.callbackContext, behavior.callbackArguments);
+            }
+        }
+    }
+
+    proto = {
+        create: function(stub) {
+            var behavior = sinon.extend({}, sinon.behavior);
+            delete behavior.create;
+            behavior.stub = stub;
+
+            return behavior;
+        },
+
+        isPresent: function() {
+            return (typeof this.callArgAt == 'number' ||
+                    this.exception ||
+                    typeof this.returnArgAt == 'number' ||
+                    this.returnThis ||
+                    this.returnValueDefined);
+        },
+
+        invoke: function(context, args) {
+            callCallback(this, args);
+
+            if (this.exception) {
+                throw this.exception;
+            } else if (typeof this.returnArgAt == 'number') {
+                return args[this.returnArgAt];
+            } else if (this.returnThis) {
+                return context;
+            }
+
+            return this.returnValue;
+        },
+
+        onCall: function(index) {
+            return this.stub.onCall(index);
+        },
+
+        onFirstCall: function() {
+            return this.stub.onFirstCall();
+        },
+
+        onSecondCall: function() {
+            return this.stub.onSecondCall();
+        },
+
+        onThirdCall: function() {
+            return this.stub.onThirdCall();
+        },
+
+        withArgs: function(/* arguments */) {
+            throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
+                            'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
+        },
+
+        callsArg: function callsArg(pos) {
+            if (typeof pos != "number") {
+                throw new TypeError("argument index is not number");
+            }
+
+            this.callArgAt = pos;
+            this.callbackArguments = [];
+            this.callbackContext = undefined;
+            this.callArgProp = undefined;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+        callsArgOn: function callsArgOn(pos, context) {
+            if (typeof pos != "number") {
+                throw new TypeError("argument index is not number");
+            }
+            if (typeof context != "object") {
+                throw new TypeError("argument context is not an object");
+            }
+
+            this.callArgAt = pos;
+            this.callbackArguments = [];
+            this.callbackContext = context;
+            this.callArgProp = undefined;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+        callsArgWith: function callsArgWith(pos) {
+            if (typeof pos != "number") {
+                throw new TypeError("argument index is not number");
+            }
+
+            this.callArgAt = pos;
+            this.callbackArguments = slice.call(arguments, 1);
+            this.callbackContext = undefined;
+            this.callArgProp = undefined;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+        callsArgOnWith: function callsArgWith(pos, context) {
+            if (typeof pos != "number") {
+                throw new TypeError("argument index is not number");
+            }
+            if (typeof context != "object") {
+                throw new TypeError("argument context is not an object");
+            }
+
+            this.callArgAt = pos;
+            this.callbackArguments = slice.call(arguments, 2);
+            this.callbackContext = context;
+            this.callArgProp = undefined;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+        yields: function () {
+            this.callArgAt = -1;
+            this.callbackArguments = slice.call(arguments, 0);
+            this.callbackContext = undefined;
+            this.callArgProp = undefined;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+        yieldsOn: function (context) {
+            if (typeof context != "object") {
+                throw new TypeError("argument context is not an object");
+            }
+
+            this.callArgAt = -1;
+            this.callbackArguments = slice.call(arguments, 1);
+            this.callbackContext = context;
+            this.callArgProp = undefined;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+        yieldsTo: function (prop) {
+            this.callArgAt = -1;
+            this.callbackArguments = slice.call(arguments, 1);
+            this.callbackContext = undefined;
+            this.callArgProp = prop;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+        yieldsToOn: function (prop, context) {
+            if (typeof context != "object") {
+                throw new TypeError("argument context is not an object");
+            }
+
+            this.callArgAt = -1;
+            this.callbackArguments = slice.call(arguments, 2);
+            this.callbackContext = context;
+            this.callArgProp = prop;
+            this.callbackAsync = false;
+
+            return this;
+        },
+
+
+        "throws": throwsException,
+        throwsException: throwsException,
+
+        returns: function returns(value) {
+            this.returnValue = value;
+            this.returnValueDefined = true;
+
+            return this;
+        },
+
+        returnsArg: function returnsArg(pos) {
+            if (typeof pos != "number") {
+                throw new TypeError("argument index is not number");
+            }
+
+            this.returnArgAt = pos;
+
+            return this;
+        },
+
+        returnsThis: function returnsThis() {
+            this.returnThis = true;
+
+            return this;
+        }
+    };
+
+    // create asynchronous versions of callsArg* and yields* methods
+    for (var method in proto) {
+        // need to avoid creating anotherasync versions of the newly added async methods
+        if (proto.hasOwnProperty(method) &&
+            method.match(/^(callsArg|yields)/) &&
+            !method.match(/Async/)) {
+            proto[method + 'Async'] = (function (syncFnName) {
+                return function () {
+                    var result = this[syncFnName].apply(this, arguments);
+                    this.callbackAsync = true;
+                    return result;
+                };
+            })(method);
+        }
+    }
+
+    sinon.behavior = proto;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = proto; });
+    } else if (commonJSModule) {
+        module.exports = proto;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend spy.js
+ * @depend behavior.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global module, require, sinon*/
+/**
+ * Stub functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    function stub(object, property, func) {
+        if (!!func && typeof func != "function") {
+            throw new TypeError("Custom stub should be function");
+        }
+
+        var wrapper;
+
+        if (func) {
+            wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
+        } else {
+            wrapper = stub.create();
+        }
+
+        if (!object && typeof property === "undefined") {
+            return sinon.stub.create();
+        }
+
+        if (typeof property === "undefined" && typeof object == "object") {
+            for (var prop in object) {
+                if (typeof object[prop] === "function") {
+                    stub(object, prop);
+                }
+            }
+
+            return object;
+        }
+
+        return sinon.wrapMethod(object, property, wrapper);
+    }
+
+    function getDefaultBehavior(stub) {
+        return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
+    }
+
+    function getParentBehaviour(stub) {
+        return (stub.parent && getCurrentBehavior(stub.parent));
+    }
+
+    function getCurrentBehavior(stub) {
+        var behavior = stub.behaviors[stub.callCount - 1];
+        return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
+    }
+
+    var uuid = 0;
+
+    sinon.extend(stub, (function () {
+        var proto = {
+            create: function create() {
+                var functionStub = function () {
+                    return getCurrentBehavior(functionStub).invoke(this, arguments);
+                };
+
+                functionStub.id = "stub#" + uuid++;
+                var orig = functionStub;
+                functionStub = sinon.spy.create(functionStub);
+                functionStub.func = orig;
+
+                sinon.extend(functionStub, stub);
+                functionStub._create = sinon.stub.create;
+                functionStub.displayName = "stub";
+                functionStub.toString = sinon.functionToString;
+
+                functionStub.defaultBehavior = null;
+                functionStub.behaviors = [];
+
+                return functionStub;
+            },
+
+            resetBehavior: function () {
+                var i;
+
+                this.defaultBehavior = null;
+                this.behaviors = [];
+
+                delete this.returnValue;
+                delete this.returnArgAt;
+                this.returnThis = false;
+
+                if (this.fakes) {
+                    for (i = 0; i < this.fakes.length; i++) {
+                        this.fakes[i].resetBehavior();
+                    }
+                }
+            },
+
+            onCall: function(index) {
+                if (!this.behaviors[index]) {
+                    this.behaviors[index] = sinon.behavior.create(this);
+                }
+
+                return this.behaviors[index];
+            },
+
+            onFirstCall: function() {
+                return this.onCall(0);
+            },
+
+            onSecondCall: function() {
+                return this.onCall(1);
+            },
+
+            onThirdCall: function() {
+                return this.onCall(2);
+            }
+        };
+
+        for (var method in sinon.behavior) {
+            if (sinon.behavior.hasOwnProperty(method) &&
+                !proto.hasOwnProperty(method) &&
+                method != 'create' &&
+                method != 'withArgs' &&
+                method != 'invoke') {
+                proto[method] = (function(behaviorMethod) {
+                    return function() {
+                        this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
+                        this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
+                        return this;
+                    };
+                }(method));
+            }
+        }
+
+        return proto;
+    }()));
+
+    sinon.stub = stub;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = stub; });
+    } else if (commonJSModule) {
+        module.exports = stub;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false*/
+/*global module, require, sinon*/
+/**
+ * Mock functions.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+    var push = [].push;
+    var match;
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    match = sinon.match;
+
+    if (!match && commonJSModule) {
+        match = require("./match");
+    }
+
+    function mock(object) {
+        if (!object) {
+            return sinon.expectation.create("Anonymous mock");
+        }
+
+        return mock.create(object);
+    }
+
+    sinon.mock = mock;
+
+    sinon.extend(mock, (function () {
+        function each(collection, callback) {
+            if (!collection) {
+                return;
+            }
+
+            for (var i = 0, l = collection.length; i < l; i += 1) {
+                callback(collection[i]);
+            }
+        }
+
+        return {
+            create: function create(object) {
+                if (!object) {
+                    throw new TypeError("object is null");
+                }
+
+                var mockObject = sinon.extend({}, mock);
+                mockObject.object = object;
+                delete mockObject.create;
+
+                return mockObject;
+            },
+
+            expects: function expects(method) {
+                if (!method) {
+                    throw new TypeError("method is falsy");
+                }
+
+                if (!this.expectations) {
+                    this.expectations = {};
+                    this.proxies = [];
+                }
+
+                if (!this.expectations[method]) {
+                    this.expectations[method] = [];
+                    var mockObject = this;
+
+                    sinon.wrapMethod(this.object, method, function () {
+                        return mockObject.invokeMethod(method, this, arguments);
+                    });
+
+                    push.call(this.proxies, method);
+                }
+
+                var expectation = sinon.expectation.create(method);
+                push.call(this.expectations[method], expectation);
+
+                return expectation;
+            },
+
+            restore: function restore() {
+                var object = this.object;
+
+                each(this.proxies, function (proxy) {
+                    if (typeof object[proxy].restore == "function") {
+                        object[proxy].restore();
+                    }
+                });
+            },
+
+            verify: function verify() {
+                var expectations = this.expectations || {};
+                var messages = [], met = [];
+
+                each(this.proxies, function (proxy) {
+                    each(expectations[proxy], function (expectation) {
+                        if (!expectation.met()) {
+                            push.call(messages, expectation.toString());
+                        } else {
+                            push.call(met, expectation.toString());
+                        }
+                    });
+                });
+
+                this.restore();
+
+                if (messages.length > 0) {
+                    sinon.expectation.fail(messages.concat(met).join("\n"));
+                } else {
+                    sinon.expectation.pass(messages.concat(met).join("\n"));
+                }
+
+                return true;
+            },
+
+            invokeMethod: function invokeMethod(method, thisValue, args) {
+                var expectations = this.expectations && this.expectations[method];
+                var length = expectations && expectations.length || 0, i;
+
+                for (i = 0; i < length; i += 1) {
+                    if (!expectations[i].met() &&
+                        expectations[i].allowsCall(thisValue, args)) {
+                        return expectations[i].apply(thisValue, args);
+                    }
+                }
+
+                var messages = [], available, exhausted = 0;
+
+                for (i = 0; i < length; i += 1) {
+                    if (expectations[i].allowsCall(thisValue, args)) {
+                        available = available || expectations[i];
+                    } else {
+                        exhausted += 1;
+                    }
+                    push.call(messages, "    " + expectations[i].toString());
+                }
+
+                if (exhausted === 0) {
+                    return available.apply(thisValue, args);
+                }
+
+                messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
+                    proxy: method,
+                    args: args
+                }));
+
+                sinon.expectation.fail(messages.join("\n"));
+            }
+        };
+    }()));
+
+    var times = sinon.timesInWords;
+
+    sinon.expectation = (function () {
+        var slice = Array.prototype.slice;
+        var _invoke = sinon.spy.invoke;
+
+        function callCountInWords(callCount) {
+            if (callCount == 0) {
+                return "never called";
+            } else {
+                return "called " + times(callCount);
+            }
+        }
+
+        function expectedCallCountInWords(expectation) {
+            var min = expectation.minCalls;
+            var max = expectation.maxCalls;
+
+            if (typeof min == "number" && typeof max == "number") {
+                var str = times(min);
+
+                if (min != max) {
+                    str = "at least " + str + " and at most " + times(max);
+                }
+
+                return str;
+            }
+
+            if (typeof min == "number") {
+                return "at least " + times(min);
+            }
+
+            return "at most " + times(max);
+        }
+
+        function receivedMinCalls(expectation) {
+            var hasMinLimit = typeof expectation.minCalls == "number";
+            return !hasMinLimit || expectation.callCount >= expectation.minCalls;
+        }
+
+        function receivedMaxCalls(expectation) {
+            if (typeof expectation.maxCalls != "number") {
+                return false;
+            }
+
+            return expectation.callCount == expectation.maxCalls;
+        }
+
+        function verifyMatcher(possibleMatcher, arg){
+            if (match && match.isMatcher(possibleMatcher)) {
+                return possibleMatcher.test(arg);
+            } else {
+                return true;
+            }
+        }
+
+        return {
+            minCalls: 1,
+            maxCalls: 1,
+
+            create: function create(methodName) {
+                var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
+                delete expectation.create;
+                expectation.method = methodName;
+
+                return expectation;
+            },
+
+            invoke: function invoke(func, thisValue, args) {
+                this.verifyCallAllowed(thisValue, args);
+
+                return _invoke.apply(this, arguments);
+            },
+
+            atLeast: function atLeast(num) {
+                if (typeof num != "number") {
+                    throw new TypeError("'" + num + "' is not number");
+                }
+
+                if (!this.limitsSet) {
+                    this.maxCalls = null;
+                    this.limitsSet = true;
+                }
+
+                this.minCalls = num;
+
+                return this;
+            },
+
+            atMost: function atMost(num) {
+                if (typeof num != "number") {
+                    throw new TypeError("'" + num + "' is not number");
+                }
+
+                if (!this.limitsSet) {
+                    this.minCalls = null;
+                    this.limitsSet = true;
+                }
+
+                this.maxCalls = num;
+
+                return this;
+            },
+
+            never: function never() {
+                return this.exactly(0);
+            },
+
+            once: function once() {
+                return this.exactly(1);
+            },
+
+            twice: function twice() {
+                return this.exactly(2);
+            },
+
+            thrice: function thrice() {
+                return this.exactly(3);
+            },
+
+            exactly: function exactly(num) {
+                if (typeof num != "number") {
+                    throw new TypeError("'" + num + "' is not a number");
+                }
+
+                this.atLeast(num);
+                return this.atMost(num);
+            },
+
+            met: function met() {
+                return !this.failed && receivedMinCalls(this);
+            },
+
+            verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
+                if (receivedMaxCalls(this)) {
+                    this.failed = true;
+                    sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
+                }
+
+                if ("expectedThis" in this && this.expectedThis !== thisValue) {
+                    sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
+                        this.expectedThis);
+                }
+
+                if (!("expectedArguments" in this)) {
+                    return;
+                }
+
+                if (!args) {
+                    sinon.expectation.fail(this.method + " received no arguments, expected " +
+                        sinon.format(this.expectedArguments));
+                }
+
+                if (args.length < this.expectedArguments.length) {
+                    sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
+                        "), expected " + sinon.format(this.expectedArguments));
+                }
+
+                if (this.expectsExactArgCount &&
+                    args.length != this.expectedArguments.length) {
+                    sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
+                        "), expected " + sinon.format(this.expectedArguments));
+                }
+
+                for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+
+                    if (!verifyMatcher(this.expectedArguments[i],args[i])) {
+                        sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+                            ", didn't match " + this.expectedArguments.toString());
+                    }
+
+                    if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+                        sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+                            ", expected " + sinon.format(this.expectedArguments));
+                    }
+                }
+            },
+
+            allowsCall: function allowsCall(thisValue, args) {
+                if (this.met() && receivedMaxCalls(this)) {
+                    return false;
+                }
+
+                if ("expectedThis" in this && this.expectedThis !== thisValue) {
+                    return false;
+                }
+
+                if (!("expectedArguments" in this)) {
+                    return true;
+                }
+
+                args = args || [];
+
+                if (args.length < this.expectedArguments.length) {
+                    return false;
+                }
+
+                if (this.expectsExactArgCount &&
+                    args.length != this.expectedArguments.length) {
+                    return false;
+                }
+
+                for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+                    if (!verifyMatcher(this.expectedArguments[i],args[i])) {
+                        return false;
+                    }
+
+                    if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+                        return false;
+                    }
+                }
+
+                return true;
+            },
+
+            withArgs: function withArgs() {
+                this.expectedArguments = slice.call(arguments);
+                return this;
+            },
+
+            withExactArgs: function withExactArgs() {
+                this.withArgs.apply(this, arguments);
+                this.expectsExactArgCount = true;
+                return this;
+            },
+
+            on: function on(thisValue) {
+                this.expectedThis = thisValue;
+                return this;
+            },
+
+            toString: function () {
+                var args = (this.expectedArguments || []).slice();
+
+                if (!this.expectsExactArgCount) {
+                    push.call(args, "[...]");
+                }
+
+                var callStr = sinon.spyCall.toString.call({
+                    proxy: this.method || "anonymous mock expectation",
+                    args: args
+                });
+
+                var message = callStr.replace(", [...", "[, ...") + " " +
+                    expectedCallCountInWords(this);
+
+                if (this.met()) {
+                    return "Expectation met: " + message;
+                }
+
+                return "Expected " + message + " (" +
+                    callCountInWords(this.callCount) + ")";
+            },
+
+            verify: function verify() {
+                if (!this.met()) {
+                    sinon.expectation.fail(this.toString());
+                } else {
+                    sinon.expectation.pass(this.toString());
+                }
+
+                return true;
+            },
+
+            pass: function(message) {
+              sinon.assert.pass(message);
+            },
+            fail: function (message) {
+                var exception = new Error(message);
+                exception.name = "ExpectationError";
+
+                throw exception;
+            }
+        };
+    }());
+
+    sinon.mock = mock;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = mock; });
+    } else if (commonJSModule) {
+        module.exports = mock;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true*/
+/*global module, require, sinon*/
+/**
+ * Collections of stubs, spies and mocks.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+    var push = [].push;
+    var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    function getFakes(fakeCollection) {
+        if (!fakeCollection.fakes) {
+            fakeCollection.fakes = [];
+        }
+
+        return fakeCollection.fakes;
+    }
+
+    function each(fakeCollection, method) {
+        var fakes = getFakes(fakeCollection);
+
+        for (var i = 0, l = fakes.length; i < l; i += 1) {
+            if (typeof fakes[i][method] == "function") {
+                fakes[i][method]();
+            }
+        }
+    }
+
+    function compact(fakeCollection) {
+        var fakes = getFakes(fakeCollection);
+        var i = 0;
+        while (i < fakes.length) {
+          fakes.splice(i, 1);
+        }
+    }
+
+    var collection = {
+        verify: function resolve() {
+            each(this, "verify");
+        },
+
+        restore: function restore() {
+            each(this, "restore");
+            compact(this);
+        },
+
+        verifyAndRestore: function verifyAndRestore() {
+            var exception;
+
+            try {
+                this.verify();
+            } catch (e) {
+                exception = e;
+            }
+
+            this.restore();
+
+            if (exception) {
+                throw exception;
+            }
+        },
+
+        add: function add(fake) {
+            push.call(getFakes(this), fake);
+            return fake;
+        },
+
+        spy: function spy() {
+            return this.add(sinon.spy.apply(sinon, arguments));
+        },
+
+        stub: function stub(object, property, value) {
+            if (property) {
+                var original = object[property];
+
+                if (typeof original != "function") {
+                    if (!hasOwnProperty.call(object, property)) {
+                        throw new TypeError("Cannot stub non-existent own property " + property);
+                    }
+
+                    object[property] = value;
+
+                    return this.add({
+                        restore: function () {
+                            object[property] = original;
+                        }
+                    });
+                }
+            }
+            if (!property && !!object && typeof object == "object") {
+                var stubbedObj = sinon.stub.apply(sinon, arguments);
+
+                for (var prop in stubbedObj) {
+                    if (typeof stubbedObj[prop] === "function") {
+                        this.add(stubbedObj[prop]);
+                    }
+                }
+
+                return stubbedObj;
+            }
+
+            return this.add(sinon.stub.apply(sinon, arguments));
+        },
+
+        mock: function mock() {
+            return this.add(sinon.mock.apply(sinon, arguments));
+        },
+
+        inject: function inject(obj) {
+            var col = this;
+
+            obj.spy = function () {
+                return col.spy.apply(col, arguments);
+            };
+
+            obj.stub = function () {
+                return col.stub.apply(col, arguments);
+            };
+
+            obj.mock = function () {
+                return col.mock.apply(col, arguments);
+            };
+
+            return obj;
+        }
+    };
+
+    sinon.collection = collection;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = collection; });
+    } else if (commonJSModule) {
+        module.exports = collection;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
+/*global module, require, window*/
+/**
+ * Fake timer API
+ * setTimeout
+ * setInterval
+ * clearTimeout
+ * clearInterval
+ * tick
+ * reset
+ * Date
+ *
+ * Inspired by jsUnitMockTimeOut from JsUnit
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+    var sinon = {};
+}
+
+(function (global) {
+    // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
+    // browsers, a number.
+    // see https://github.com/cjohansen/Sinon.JS/pull/436
+    var timeoutResult = setTimeout(function() {}, 0);
+    var addTimerReturnsObject = typeof timeoutResult === 'object';
+    clearTimeout(timeoutResult);
+
+    var id = 1;
+
+    function addTimer(args, recurring) {
+        if (args.length === 0) {
+            throw new Error("Function requires at least 1 parameter");
+        }
+
+        if (typeof args[0] === "undefined") {
+            throw new Error("Callback must be provided to timer calls");
+        }
+
+        var toId = id++;
+        var delay = args[1] || 0;
+
+        if (!this.timeouts) {
+            this.timeouts = {};
+        }
+
+        this.timeouts[toId] = {
+            id: toId,
+            func: args[0],
+            callAt: this.now + delay,
+            invokeArgs: Array.prototype.slice.call(args, 2)
+        };
+
+        if (recurring === true) {
+            this.timeouts[toId].interval = delay;
+        }
+
+        if (addTimerReturnsObject) {
+            return {
+                id: toId,
+                ref: function() {},
+                unref: function() {}
+            };
+        }
+        else {
+            return toId;
+        }
+    }
+
+    function parseTime(str) {
+        if (!str) {
+            return 0;
+        }
+
+        var strings = str.split(":");
+        var l = strings.length, i = l;
+        var ms = 0, parsed;
+
+        if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
+            throw new Error("tick only understands numbers and 'h:m:s'");
+        }
+
+        while (i--) {
+            parsed = parseInt(strings[i], 10);
+
+            if (parsed >= 60) {
+                throw new Error("Invalid time " + str);
+            }
+
+            ms += parsed * Math.pow(60, (l - i - 1));
+        }
+
+        return ms * 1000;
+    }
+
+    function createObject(object) {
+        var newObject;
+
+        if (Object.create) {
+            newObject = Object.create(object);
+        } else {
+            var F = function () {};
+            F.prototype = object;
+            newObject = new F();
+        }
+
+        newObject.Date.clock = newObject;
+        return newObject;
+    }
+
+    sinon.clock = {
+        now: 0,
+
+        create: function create(now) {
+            var clock = createObject(this);
+
+            if (typeof now == "number") {
+                clock.now = now;
+            }
+
+            if (!!now && typeof now == "object") {
+                throw new TypeError("now should be milliseconds since UNIX epoch");
+            }
+
+            return clock;
+        },
+
+        setTimeout: function setTimeout(callback, timeout) {
+            return addTimer.call(this, arguments, false);
+        },
+
+        clearTimeout: function clearTimeout(timerId) {
+            if (!timerId) {
+                // null appears to be allowed in most browsers, and appears to be relied upon by some libraries, like Bootstrap carousel
+                return;
+            }
+            if (!this.timeouts) {
+                this.timeouts = [];
+            }
+            // in Node, timerId is an object with .ref()/.unref(), and
+            // its .id field is the actual timer id.
+            if (typeof timerId === 'object') {
+              timerId = timerId.id
+            }
+            if (timerId in this.timeouts) {
+                delete this.timeouts[timerId];
+            }
+        },
+
+        setInterval: function setInterval(callback, timeout) {
+            return addTimer.call(this, arguments, true);
+        },
+
+        clearInterval: function clearInterval(timerId) {
+            this.clearTimeout(timerId);
+        },
+
+        setImmediate: function setImmediate(callback) {
+            var passThruArgs = Array.prototype.slice.call(arguments, 1);
+
+            return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
+        },
+
+        clearImmediate: function clearImmediate(timerId) {
+            this.clearTimeout(timerId);
+        },
+
+        tick: function tick(ms) {
+            ms = typeof ms == "number" ? ms : parseTime(ms);
+            var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
+            var timer = this.firstTimerInRange(tickFrom, tickTo);
+
+            var firstException;
+            while (timer && tickFrom <= tickTo) {
+                if (this.timeouts[timer.id]) {
+                    tickFrom = this.now = timer.callAt;
+                    try {
+                      this.callTimer(timer);
+                    } catch (e) {
+                      firstException = firstException || e;
+                    }
+                }
+
+                timer = this.firstTimerInRange(previous, tickTo);
+                previous = tickFrom;
+            }
+
+            this.now = tickTo;
+
+            if (firstException) {
+              throw firstException;
+            }
+
+            return this.now;
+        },
+
+        firstTimerInRange: function (from, to) {
+            var timer, smallest = null, originalTimer;
+
+            for (var id in this.timeouts) {
+                if (this.timeouts.hasOwnProperty(id)) {
+                    if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
+                        continue;
+                    }
+
+                    if (smallest === null || this.timeouts[id].callAt < smallest) {
+                        originalTimer = this.timeouts[id];
+                        smallest = this.timeouts[id].callAt;
+
+                        timer = {
+                            func: this.timeouts[id].func,
+                            callAt: this.timeouts[id].callAt,
+                            interval: this.timeouts[id].interval,
+                            id: this.timeouts[id].id,
+                            invokeArgs: this.timeouts[id].invokeArgs
+                        };
+                    }
+                }
+            }
+
+            return timer || null;
+        },
+
+        callTimer: function (timer) {
+            if (typeof timer.interval == "number") {
+                this.timeouts[timer.id].callAt += timer.interval;
+            } else {
+                delete this.timeouts[timer.id];
+            }
+
+            try {
+                if (typeof timer.func == "function") {
+                    timer.func.apply(null, timer.invokeArgs);
+                } else {
+                    eval(timer.func);
+                }
+            } catch (e) {
+              var exception = e;
+            }
+
+            if (!this.timeouts[timer.id]) {
+                if (exception) {
+                  throw exception;
+                }
+                return;
+            }
+
+            if (exception) {
+              throw exception;
+            }
+        },
+
+        reset: function reset() {
+            this.timeouts = {};
+        },
+
+        Date: (function () {
+            var NativeDate = Date;
+
+            function ClockDate(year, month, date, hour, minute, second, ms) {
+                // Defensive and verbose to avoid potential harm in passing
+                // explicit undefined when user does not pass argument
+                switch (arguments.length) {
+                case 0:
+                    return new NativeDate(ClockDate.clock.now);
+                case 1:
+                    return new NativeDate(year);
+                case 2:
+                    return new NativeDate(year, month);
+                case 3:
+                    return new NativeDate(year, month, date);
+                case 4:
+                    return new NativeDate(year, month, date, hour);
+                case 5:
+                    return new NativeDate(year, month, date, hour, minute);
+                case 6:
+                    return new NativeDate(year, month, date, hour, minute, second);
+                default:
+                    return new NativeDate(year, month, date, hour, minute, second, ms);
+                }
+            }
+
+            return mirrorDateProperties(ClockDate, NativeDate);
+        }())
+    };
+
+    function mirrorDateProperties(target, source) {
+        if (source.now) {
+            target.now = function now() {
+                return target.clock.now;
+            };
+        } else {
+            delete target.now;
+        }
+
+        if (source.toSource) {
+            target.toSource = function toSource() {
+                return source.toSource();
+            };
+        } else {
+            delete target.toSource;
+        }
+
+        target.toString = function toString() {
+            return source.toString();
+        };
+
+        target.prototype = source.prototype;
+        target.parse = source.parse;
+        target.UTC = source.UTC;
+        target.prototype.toUTCString = source.prototype.toUTCString;
+
+        for (var prop in source) {
+            if (source.hasOwnProperty(prop)) {
+                target[prop] = source[prop];
+            }
+        }
+
+        return target;
+    }
+
+    var methods = ["Date", "setTimeout", "setInterval",
+                   "clearTimeout", "clearInterval"];
+
+    if (typeof global.setImmediate !== "undefined") {
+        methods.push("setImmediate");
+    }
+
+    if (typeof global.clearImmediate !== "undefined") {
+        methods.push("clearImmediate");
+    }
+
+    function restore() {
+        var method;
+
+        for (var i = 0, l = this.methods.length; i < l; i++) {
+            method = this.methods[i];
+
+            if (global[method].hadOwnProperty) {
+                global[method] = this["_" + method];
+            } else {
+                try {
+                    delete global[method];
+                } catch (e) {}
+            }
+        }
+
+        // Prevent multiple executions which will completely remove these props
+        this.methods = [];
+    }
+
+    function stubGlobal(method, clock) {
+        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
+        clock["_" + method] = global[method];
+
+        if (method == "Date") {
+            var date = mirrorDateProperties(clock[method], global[method]);
+            global[method] = date;
+        } else {
+            global[method] = function () {
+                return clock[method].apply(clock, arguments);
+            };
+
+            for (var prop in clock[method]) {
+                if (clock[method].hasOwnProperty(prop)) {
+                    global[method][prop] = clock[method][prop];
+                }
+            }
+        }
+
+        global[method].clock = clock;
+    }
+
+    sinon.useFakeTimers = function useFakeTimers(now) {
+        var clock = sinon.clock.create(now);
+        clock.restore = restore;
+        clock.methods = Array.prototype.slice.call(arguments,
+                                                   typeof now == "number" ? 1 : 0);
+
+        if (clock.methods.length === 0) {
+            clock.methods = methods;
+        }
+
+        for (var i = 0, l = clock.methods.length; i < l; i++) {
+            stubGlobal(clock.methods[i], clock);
+        }
+
+        return clock;
+    };
+}(typeof global != "undefined" && typeof global !== "function" ? global : this));
+
+sinon.timers = {
+    setTimeout: setTimeout,
+    clearTimeout: clearTimeout,
+    setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
+    clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
+    setInterval: setInterval,
+    clearInterval: clearInterval,
+    Date: Date
+};
+
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = sinon;
+}
+
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Minimal Event interface implementation
+ *
+ * Original implementation by Sven Fuchs: https://gist.github.com/995028
+ * Modifications and tests by Christian Johansen.
+ *
+ * @author Sven Fuchs (svenfuchs@artweb-design.de)
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2011 Sven Fuchs, Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+    this.sinon = {};
+}
+
+(function () {
+    var push = [].push;
+
+    sinon.Event = function Event(type, bubbles, cancelable, target) {
+        this.initEvent(type, bubbles, cancelable, target);
+    };
+
+    sinon.Event.prototype = {
+        initEvent: function(type, bubbles, cancelable, target) {
+            this.type = type;
+            this.bubbles = bubbles;
+            this.cancelable = cancelable;
+            this.target = target;
+        },
+
+        stopPropagation: function () {},
+
+        preventDefault: function () {
+            this.defaultPrevented = true;
+        }
+    };
+
+    sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
+        this.initEvent(type, false, false, target);
+        this.loaded = progressEventRaw.loaded || null;
+        this.total = progressEventRaw.total || null;
+    };
+
+    sinon.ProgressEvent.prototype = new sinon.Event();
+
+    sinon.ProgressEvent.prototype.constructor =  sinon.ProgressEvent;
+
+    sinon.CustomEvent = function CustomEvent(type, customData, target) {
+        this.initEvent(type, false, false, target);
+        this.detail = customData.detail || null;
+    };
+
+    sinon.CustomEvent.prototype = new sinon.Event();
+
+    sinon.CustomEvent.prototype.constructor =  sinon.CustomEvent;
+
+    sinon.EventTarget = {
+        addEventListener: function addEventListener(event, listener) {
+            this.eventListeners = this.eventListeners || {};
+            this.eventListeners[event] = this.eventListeners[event] || [];
+            push.call(this.eventListeners[event], listener);
+        },
+
+        removeEventListener: function removeEventListener(event, listener) {
+            var listeners = this.eventListeners && this.eventListeners[event] || [];
+
+            for (var i = 0, l = listeners.length; i < l; ++i) {
+                if (listeners[i] == listener) {
+                    return listeners.splice(i, 1);
+                }
+            }
+        },
+
+        dispatchEvent: function dispatchEvent(event) {
+            var type = event.type;
+            var listeners = this.eventListeners && this.eventListeners[type] || [];
+
+            for (var i = 0; i < listeners.length; i++) {
+                if (typeof listeners[i] == "function") {
+                    listeners[i].call(this, event);
+                } else {
+                    listeners[i].handleEvent(event);
+                }
+            }
+
+            return !!event.defaultPrevented;
+        }
+    };
+}());
+
+/**
+ * @depend ../../sinon.js
+ * @depend event.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Fake XMLHttpRequest object
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+// wrapper for global
+(function(global) {
+    if (typeof sinon === "undefined") {
+        global.sinon = {};
+    }
+
+    var supportsProgress = typeof ProgressEvent !== "undefined";
+    var supportsCustomEvent = typeof CustomEvent !== "undefined";
+    sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
+    var xhr = sinon.xhr;
+    xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
+    xhr.GlobalActiveXObject = global.ActiveXObject;
+    xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
+    xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
+    xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
+                                     ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
+    xhr.supportsCORS = xhr.supportsXHR && 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
+
+    /*jsl:ignore*/
+    var unsafeHeaders = {
+        "Accept-Charset": true,
+        "Accept-Encoding": true,
+        "Connection": true,
+        "Content-Length": true,
+        "Cookie": true,
+        "Cookie2": true,
+        "Content-Transfer-Encoding": true,
+        "Date": true,
+        "Expect": true,
+        "Host": true,
+        "Keep-Alive": true,
+        "Referer": true,
+        "TE": true,
+        "Trailer": true,
+        "Transfer-Encoding": true,
+        "Upgrade": true,
+        "User-Agent": true,
+        "Via": true
+    };
+    /*jsl:end*/
+
+    function FakeXMLHttpRequest() {
+        this.readyState = FakeXMLHttpRequest.UNSENT;
+        this.requestHeaders = {};
+        this.requestBody = null;
+        this.status = 0;
+        this.statusText = "";
+        this.upload = new UploadProgress();
+        if (sinon.xhr.supportsCORS) {
+            this.withCredentials = false;
+        }
+
+
+        var xhr = this;
+        var events = ["loadstart", "load", "abort", "loadend"];
+
+        function addEventListener(eventName) {
+            xhr.addEventListener(eventName, function (event) {
+                var listener = xhr["on" + eventName];
+
+                if (listener && typeof listener == "function") {
+                    listener.call(this, event);
+                }
+            });
+        }
+
+        for (var i = events.length - 1; i >= 0; i--) {
+            addEventListener(events[i]);
+        }
+
+        if (typeof FakeXMLHttpRequest.onCreate == "function") {
+            FakeXMLHttpRequest.onCreate(this);
+        }
+    }
+
+    // An upload object is created for each
+    // FakeXMLHttpRequest and allows upload
+    // events to be simulated using uploadProgress
+    // and uploadError.
+    function UploadProgress() {
+        this.eventListeners = {
+            "progress": [],
+            "load": [],
+            "abort": [],
+            "error": []
+        }
+    }
+
+    UploadProgress.prototype.addEventListener = function(event, listener) {
+        this.eventListeners[event].push(listener);
+    };
+
+    UploadProgress.prototype.removeEventListener = function(event, listener) {
+        var listeners = this.eventListeners[event] || [];
+
+        for (var i = 0, l = listeners.length; i < l; ++i) {
+            if (listeners[i] == listener) {
+                return listeners.splice(i, 1);
+            }
+        }
+    };
+
+    UploadProgress.prototype.dispatchEvent = function(event) {
+        var listeners = this.eventListeners[event.type] || [];
+
+        for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
+            listener(event);
+        }
+    };
+
+    function verifyState(xhr) {
+        if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+            throw new Error("INVALID_STATE_ERR");
+        }
+
+        if (xhr.sendFlag) {
+            throw new Error("INVALID_STATE_ERR");
+        }
+    }
+
+    // filtering to enable a white-list version of Sinon FakeXhr,
+    // where whitelisted requests are passed through to real XHR
+    function each(collection, callback) {
+        if (!collection) return;
+        for (var i = 0, l = collection.length; i < l; i += 1) {
+            callback(collection[i]);
+        }
+    }
+    function some(collection, callback) {
+        for (var index = 0; index < collection.length; index++) {
+            if(callback(collection[index]) === true) return true;
+        }
+        return false;
+    }
+    // largest arity in XHR is 5 - XHR#open
+    var apply = function(obj,method,args) {
+        switch(args.length) {
+        case 0: return obj[method]();
+        case 1: return obj[method](args[0]);
+        case 2: return obj[method](args[0],args[1]);
+        case 3: return obj[method](args[0],args[1],args[2]);
+        case 4: return obj[method](args[0],args[1],args[2],args[3]);
+        case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
+        }
+    };
+
+    FakeXMLHttpRequest.filters = [];
+    FakeXMLHttpRequest.addFilter = function(fn) {
+        this.filters.push(fn)
+    };
+    var IE6Re = /MSIE 6/;
+    FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
+        var xhr = new sinon.xhr.workingXHR();
+        each(["open","setRequestHeader","send","abort","getResponseHeader",
+              "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
+             function(method) {
+                 fakeXhr[method] = function() {
+                   return apply(xhr,method,arguments);
+                 };
+             });
+
+        var copyAttrs = function(args) {
+            each(args, function(attr) {
+              try {
+                fakeXhr[attr] = xhr[attr]
+              } catch(e) {
+                if(!IE6Re.test(navigator.userAgent)) throw e;
+              }
+            });
+        };
+
+        var stateChange = function() {
+            fakeXhr.readyState = xhr.readyState;
+            if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
+                copyAttrs(["status","statusText"]);
+            }
+            if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
+                copyAttrs(["responseText"]);
+            }
+            if(xhr.readyState === FakeXMLHttpRequest.DONE) {
+                copyAttrs(["responseXML"]);
+            }
+            if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
+        };
+        if(xhr.addEventListener) {
+          for(var event in fakeXhr.eventListeners) {
+              if(fakeXhr.eventListeners.hasOwnProperty(event)) {
+                  each(fakeXhr.eventListeners[event],function(handler) {
+                      xhr.addEventListener(event, handler);
+                  });
+              }
+          }
+          xhr.addEventListener("readystatechange",stateChange);
+        } else {
+          xhr.onreadystatechange = stateChange;
+        }
+        apply(xhr,"open",xhrArgs);
+    };
+    FakeXMLHttpRequest.useFilters = false;
+
+    function verifyRequestOpened(xhr) {
+        if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
+            throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
+        }
+    }
+
+    function verifyRequestSent(xhr) {
+        if (xhr.readyState == FakeXMLHttpRequest.DONE) {
+            throw new Error("Request done");
+        }
+    }
+
+    function verifyHeadersReceived(xhr) {
+        if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
+            throw new Error("No headers received");
+        }
+    }
+
+    function verifyResponseBodyType(body) {
+        if (typeof body != "string") {
+            var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
+                                 body + ", which is not a string.");
+            error.name = "InvalidBodyException";
+            throw error;
+        }
+    }
+
+    sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
+        async: true,
+
+        open: function open(method, url, async, username, password) {
+            this.method = method;
+            this.url = url;
+            this.async = typeof async == "boolean" ? async : true;
+            this.username = username;
+            this.password = password;
+            this.responseText = null;
+            this.responseXML = null;
+            this.requestHeaders = {};
+            this.sendFlag = false;
+            if(sinon.FakeXMLHttpRequest.useFilters === true) {
+                var xhrArgs = arguments;
+                var defake = some(FakeXMLHttpRequest.filters,function(filter) {
+                    return filter.apply(this,xhrArgs)
+                });
+                if (defake) {
+                  return sinon.FakeXMLHttpRequest.defake(this,arguments);
+                }
+            }
+            this.readyStateChange(FakeXMLHttpRequest.OPENED);
+        },
+
+        readyStateChange: function readyStateChange(state) {
+            this.readyState = state;
+
+            if (typeof this.onreadystatechange == "function") {
+                try {
+                    this.onreadystatechange();
+                } catch (e) {
+                    sinon.logError("Fake XHR onreadystatechange handler", e);
+                }
+            }
+
+            this.dispatchEvent(new sinon.Event("readystatechange"));
+
+            switch (this.readyState) {
+                case FakeXMLHttpRequest.DONE:
+                    this.dispatchEvent(new sinon.Event("load", false, false, this));
+                    this.dispatchEvent(new sinon.Event("loadend", false, false, this));
+                    this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
+                    if (supportsProgress) {
+                        this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
+                    }
+                    break;
+            }
+        },
+
+        setRequestHeader: function setRequestHeader(header, value) {
+            verifyState(this);
+
+            if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
+                throw new Error("Refused to set unsafe header \"" + header + "\"");
+            }
+
+            if (this.requestHeaders[header]) {
+                this.requestHeaders[header] += "," + value;
+            } else {
+                this.requestHeaders[header] = value;
+            }
+        },
+
+        // Helps testing
+        setResponseHeaders: function setResponseHeaders(headers) {
+            verifyRequestOpened(this);
+            this.responseHeaders = {};
+
+            for (var header in headers) {
+                if (headers.hasOwnProperty(header)) {
+                    this.responseHeaders[header] = headers[header];
+                }
+            }
+
+            if (this.async) {
+                this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
+            } else {
+                this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
+            }
+        },
+
+        // Currently treats ALL data as a DOMString (i.e. no Document)
+        send: function send(data) {
+            verifyState(this);
+
+            if (!/^(get|head)$/i.test(this.method)) {
+                if (this.requestHeaders["Content-Type"]) {
+                    var value = this.requestHeaders["Content-Type"].split(";");
+                    this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
+                } else {
+                    this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+                }
+
+                this.requestBody = data;
+            }
+
+            this.errorFlag = false;
+            this.sendFlag = this.async;
+            this.readyStateChange(FakeXMLHttpRequest.OPENED);
+
+            if (typeof this.onSend == "function") {
+                this.onSend(this);
+            }
+
+            this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
+        },
+
+        abort: function abort() {
+            this.aborted = true;
+            this.responseText = null;
+            this.errorFlag = true;
+            this.requestHeaders = {};
+
+            if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
+                this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
+                this.sendFlag = false;
+            }
+
+            this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
+
+            this.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+            this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+            if (typeof this.onerror === "function") {
+                this.onerror();
+            }
+        },
+
+        getResponseHeader: function getResponseHeader(header) {
+            if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+                return null;
+            }
+
+            if (/^Set-Cookie2?$/i.test(header)) {
+                return null;
+            }
+
+            header = header.toLowerCase();
+
+            for (var h in this.responseHeaders) {
+                if (h.toLowerCase() == header) {
+                    return this.responseHeaders[h];
+                }
+            }
+
+            return null;
+        },
+
+        getAllResponseHeaders: function getAllResponseHeaders() {
+            if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+                return "";
+            }
+
+            var headers = "";
+
+            for (var header in this.responseHeaders) {
+                if (this.responseHeaders.hasOwnProperty(header) &&
+                    !/^Set-Cookie2?$/i.test(header)) {
+                    headers += header + ": " + this.responseHeaders[header] + "\r\n";
+                }
+            }
+
+            return headers;
+        },
+
+        setResponseBody: function setResponseBody(body) {
+            verifyRequestSent(this);
+            verifyHeadersReceived(this);
+            verifyResponseBodyType(body);
+
+            var chunkSize = this.chunkSize || 10;
+            var index = 0;
+            this.responseText = "";
+
+            do {
+                if (this.async) {
+                    this.readyStateChange(FakeXMLHttpRequest.LOADING);
+                }
+
+                this.responseText += body.substring(index, index + chunkSize);
+                index += chunkSize;
+            } while (index < body.length);
+
+            var type = this.getResponseHeader("Content-Type");
+
+            if (this.responseText &&
+                (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
+                try {
+                    this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
+                } catch (e) {
+                    // Unable to parse XML - no biggie
+                }
+            }
+
+            if (this.async) {
+                this.readyStateChange(FakeXMLHttpRequest.DONE);
+            } else {
+                this.readyState = FakeXMLHttpRequest.DONE;
+            }
+        },
+
+        respond: function respond(status, headers, body) {
+            this.status = typeof status == "number" ? status : 200;
+            this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
+            this.setResponseHeaders(headers || {});
+            this.setResponseBody(body || "");
+        },
+
+        uploadProgress: function uploadProgress(progressEventRaw) {
+            if (supportsProgress) {
+                this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
+            }
+        },
+
+        uploadError: function uploadError(error) {
+            if (supportsCustomEvent) {
+                this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
+            }
+        }
+    });
+
+    sinon.extend(FakeXMLHttpRequest, {
+        UNSENT: 0,
+        OPENED: 1,
+        HEADERS_RECEIVED: 2,
+        LOADING: 3,
+        DONE: 4
+    });
+
+    // Borrowed from JSpec
+    FakeXMLHttpRequest.parseXML = function parseXML(text) {
+        var xmlDoc;
+
+        if (typeof DOMParser != "undefined") {
+            var parser = new DOMParser();
+            xmlDoc = parser.parseFromString(text, "text/xml");
+        } else {
+            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+            xmlDoc.async = "false";
+            xmlDoc.loadXML(text);
+        }
+
+        return xmlDoc;
+    };
+
+    FakeXMLHttpRequest.statusCodes = {
+        100: "Continue",
+        101: "Switching Protocols",
+        200: "OK",
+        201: "Created",
+        202: "Accepted",
+        203: "Non-Authoritative Information",
+        204: "No Content",
+        205: "Reset Content",
+        206: "Partial Content",
+        300: "Multiple Choice",
+        301: "Moved Permanently",
+        302: "Found",
+        303: "See Other",
+        304: "Not Modified",
+        305: "Use Proxy",
+        307: "Temporary Redirect",
+        400: "Bad Request",
+        401: "Unauthorized",
+        402: "Payment Required",
+        403: "Forbidden",
+        404: "Not Found",
+        405: "Method Not Allowed",
+        406: "Not Acceptable",
+        407: "Proxy Authentication Required",
+        408: "Request Timeout",
+        409: "Conflict",
+        410: "Gone",
+        411: "Length Required",
+        412: "Precondition Failed",
+        413: "Request Entity Too Large",
+        414: "Request-URI Too Long",
+        415: "Unsupported Media Type",
+        416: "Requested Range Not Satisfiable",
+        417: "Expectation Failed",
+        422: "Unprocessable Entity",
+        500: "Internal Server Error",
+        501: "Not Implemented",
+        502: "Bad Gateway",
+        503: "Service Unavailable",
+        504: "Gateway Timeout",
+        505: "HTTP Version Not Supported"
+    };
+
+    sinon.useFakeXMLHttpRequest = function () {
+        sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
+            if (xhr.supportsXHR) {
+                global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
+            }
+
+            if (xhr.supportsActiveX) {
+                global.ActiveXObject = xhr.GlobalActiveXObject;
+            }
+
+            delete sinon.FakeXMLHttpRequest.restore;
+
+            if (keepOnCreate !== true) {
+                delete sinon.FakeXMLHttpRequest.onCreate;
+            }
+        };
+        if (xhr.supportsXHR) {
+            global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
+        }
+
+        if (xhr.supportsActiveX) {
+            global.ActiveXObject = function ActiveXObject(objId) {
+                if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
+
+                    return new sinon.FakeXMLHttpRequest();
+                }
+
+                return new xhr.GlobalActiveXObject(objId);
+            };
+        }
+
+        return sinon.FakeXMLHttpRequest;
+    };
+
+    sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
+
+})((function(){ return typeof global === "object" ? global : this; })());
+
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = sinon;
+}
+
+/**
+ * @depend fake_xml_http_request.js
+ */
+/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
+/*global module, require, window*/
+/**
+ * The Sinon "server" mimics a web server that receives requests from
+ * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
+ * both synchronously and asynchronously. To respond synchronuously, canned
+ * answers have to be provided upfront.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+    var sinon = {};
+}
+
+sinon.fakeServer = (function () {
+    var push = [].push;
+    function F() {}
+
+    function create(proto) {
+        F.prototype = proto;
+        return new F();
+    }
+
+    function responseArray(handler) {
+        var response = handler;
+
+        if (Object.prototype.toString.call(handler) != "[object Array]") {
+            response = [200, {}, handler];
+        }
+
+        if (typeof response[2] != "string") {
+            throw new TypeError("Fake server response body should be string, but was " +
+                                typeof response[2]);
+        }
+
+        return response;
+    }
+
+    var wloc = typeof window !== "undefined" ? window.location : {};
+    var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
+
+    function matchOne(response, reqMethod, reqUrl) {
+        var rmeth = response.method;
+        var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
+        var url = response.url;
+        var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
+
+        return matchMethod && matchUrl;
+    }
+
+    function match(response, request) {
+        var requestUrl = request.url;
+
+        if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
+            requestUrl = requestUrl.replace(rCurrLoc, "");
+        }
+
+        if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
+            if (typeof response.response == "function") {
+                var ru = response.url;
+                var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
+                return response.response.apply(response, args);
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    return {
+        create: function () {
+            var server = create(this);
+            this.xhr = sinon.useFakeXMLHttpRequest();
+            server.requests = [];
+
+            this.xhr.onCreate = function (xhrObj) {
+                server.addRequest(xhrObj);
+            };
+
+            return server;
+        },
+
+        addRequest: function addRequest(xhrObj) {
+            var server = this;
+            push.call(this.requests, xhrObj);
+
+            xhrObj.onSend = function () {
+                server.handleRequest(this);
+
+                if (server.autoRespond && !server.responding) {
+                    setTimeout(function () {
+                        server.responding = false;
+                        server.respond();
+                    }, server.autoRespondAfter || 10);
+
+                    server.responding = true;
+                }
+            };
+        },
+
+        getHTTPMethod: function getHTTPMethod(request) {
+            if (this.fakeHTTPMethods && /post/i.test(request.method)) {
+                var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
+                return !!matches ? matches[1] : request.method;
+            }
+
+            return request.method;
+        },
+
+        handleRequest: function handleRequest(xhr) {
+            if (xhr.async) {
+                if (!this.queue) {
+                    this.queue = [];
+                }
+
+                push.call(this.queue, xhr);
+            } else {
+                this.processRequest(xhr);
+            }
+        },
+
+        log: function(response, request) {
+            var str;
+
+            str =  "Request:\n"  + sinon.format(request)  + "\n\n";
+            str += "Response:\n" + sinon.format(response) + "\n\n";
+
+            sinon.log(str);
+        },
+
+        respondWith: function respondWith(method, url, body) {
+            if (arguments.length == 1 && typeof method != "function") {
+                this.response = responseArray(method);
+                return;
+            }
+
+            if (!this.responses) { this.responses = []; }
+
+            if (arguments.length == 1) {
+                body = method;
+                url = method = null;
+            }
+
+            if (arguments.length == 2) {
+                body = url;
+                url = method;
+                method = null;
+            }
+
+            push.call(this.responses, {
+                method: method,
+                url: url,
+                response: typeof body == "function" ? body : responseArray(body)
+            });
+        },
+
+        respond: function respond() {
+            if (arguments.length > 0) this.respondWith.apply(this, arguments);
+            var queue = this.queue || [];
+            var requests = queue.splice(0, queue.length);
+            var request;
+
+            while(request = requests.shift()) {
+                this.processRequest(request);
+            }
+        },
+
+        processRequest: function processRequest(request) {
+            try {
+                if (request.aborted) {
+                    return;
+                }
+
+                var response = this.response || [404, {}, ""];
+
+                if (this.responses) {
+                    for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
+                        if (match.call(this, this.responses[i], request)) {
+                            response = this.responses[i].response;
+                            break;
+                        }
+                    }
+                }
+
+                if (request.readyState != 4) {
+                    sinon.fakeServer.log(response, request);
+
+                    request.respond(response[0], response[1], response[2]);
+                }
+            } catch (e) {
+                sinon.logError("Fake server request processing", e);
+            }
+        },
+
+        restore: function restore() {
+            return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
+        }
+    };
+}());
+
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = sinon;
+}
+
+/**
+ * @depend fake_server.js
+ * @depend fake_timers.js
+ */
+/*jslint browser: true, eqeqeq: false, onevar: false*/
+/*global sinon*/
+/**
+ * Add-on for sinon.fakeServer that automatically handles a fake timer along with
+ * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
+ * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
+ * it polls the object for completion with setInterval. Dispite the direct
+ * motivation, there is nothing jQuery-specific in this file, so it can be used
+ * in any environment where the ajax implementation depends on setInterval or
+ * setTimeout.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function () {
+    function Server() {}
+    Server.prototype = sinon.fakeServer;
+
+    sinon.fakeServerWithClock = new Server();
+
+    sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
+        if (xhr.async) {
+            if (typeof setTimeout.clock == "object") {
+                this.clock = setTimeout.clock;
+            } else {
+                this.clock = sinon.useFakeTimers();
+                this.resetClock = true;
+            }
+
+            if (!this.longestTimeout) {
+                var clockSetTimeout = this.clock.setTimeout;
+                var clockSetInterval = this.clock.setInterval;
+                var server = this;
+
+                this.clock.setTimeout = function (fn, timeout) {
+                    server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+                    return clockSetTimeout.apply(this, arguments);
+                };
+
+                this.clock.setInterval = function (fn, timeout) {
+                    server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+                    return clockSetInterval.apply(this, arguments);
+                };
+            }
+        }
+
+        return sinon.fakeServer.addRequest.call(this, xhr);
+    };
+
+    sinon.fakeServerWithClock.respond = function respond() {
+        var returnVal = sinon.fakeServer.respond.apply(this, arguments);
+
+        if (this.clock) {
+            this.clock.tick(this.longestTimeout || 0);
+            this.longestTimeout = 0;
+
+            if (this.resetClock) {
+                this.clock.restore();
+                this.resetClock = false;
+            }
+        }
+
+        return returnVal;
+    };
+
+    sinon.fakeServerWithClock.restore = function restore() {
+        if (this.clock) {
+            this.clock.restore();
+        }
+
+        return sinon.fakeServer.restore.apply(this, arguments);
+    };
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend collection.js
+ * @depend util/fake_timers.js
+ * @depend util/fake_server_with_clock.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global require, module*/
+/**
+ * Manages fake collections as well as fake utilities such as Sinon's
+ * timers and fake XHR implementation in one convenient object.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof module !== "undefined" && module.exports && typeof require == "function") {
+    var sinon = require("../sinon");
+    sinon.extend(sinon, require("./util/fake_timers"));
+}
+
+(function () {
+    var push = [].push;
+
+    function exposeValue(sandbox, config, key, value) {
+        if (!value) {
+            return;
+        }
+
+        if (config.injectInto && !(key in config.injectInto)) {
+            config.injectInto[key] = value;
+            sandbox.injectedKeys.push(key);
+        } else {
+            push.call(sandbox.args, value);
+        }
+    }
+
+    function prepareSandboxFromConfig(config) {
+        var sandbox = sinon.create(sinon.sandbox);
+
+        if (config.useFakeServer) {
+            if (typeof config.useFakeServer == "object") {
+                sandbox.serverPrototype = config.useFakeServer;
+            }
+
+            sandbox.useFakeServer();
+        }
+
+        if (config.useFakeTimers) {
+            if (typeof config.useFakeTimers == "object") {
+                sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
+            } else {
+                sandbox.useFakeTimers();
+            }
+        }
+
+        return sandbox;
+    }
+
+    sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
+        useFakeTimers: function useFakeTimers() {
+            this.clock = sinon.useFakeTimers.apply(sinon, arguments);
+
+            return this.add(this.clock);
+        },
+
+        serverPrototype: sinon.fakeServer,
+
+        useFakeServer: function useFakeServer() {
+            var proto = this.serverPrototype || sinon.fakeServer;
+
+            if (!proto || !proto.create) {
+                return null;
+            }
+
+            this.server = proto.create();
+            return this.add(this.server);
+        },
+
+        inject: function (obj) {
+            sinon.collection.inject.call(this, obj);
+
+            if (this.clock) {
+                obj.clock = this.clock;
+            }
+
+            if (this.server) {
+                obj.server = this.server;
+                obj.requests = this.server.requests;
+            }
+
+            return obj;
+        },
+
+        restore: function () {
+            sinon.collection.restore.apply(this, arguments);
+            this.restoreContext();
+        },
+
+        restoreContext: function () {
+            if (this.injectedKeys) {
+                for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
+                    delete this.injectInto[this.injectedKeys[i]];
+                }
+                this.injectedKeys = [];
+            }
+        },
+
+        create: function (config) {
+            if (!config) {
+                return sinon.create(sinon.sandbox);
+            }
+
+            var sandbox = prepareSandboxFromConfig(config);
+            sandbox.args = sandbox.args || [];
+            sandbox.injectedKeys = [];
+            sandbox.injectInto = config.injectInto;
+            var prop, value, exposed = sandbox.inject({});
+
+            if (config.properties) {
+                for (var i = 0, l = config.properties.length; i < l; i++) {
+                    prop = config.properties[i];
+                    value = exposed[prop] || prop == "sandbox" && sandbox;
+                    exposeValue(sandbox, config, prop, value);
+                }
+            } else {
+                exposeValue(sandbox, config, "sandbox", value);
+            }
+
+            return sandbox;
+        }
+    });
+
+    sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = sinon.sandbox; });
+    } else if (typeof module !== 'undefined' && module.exports) {
+        module.exports = sinon.sandbox;
+    }
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ * @depend sandbox.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Test function, sandboxes fakes
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    function test(callback) {
+        var type = typeof callback;
+
+        if (type != "function") {
+            throw new TypeError("sinon.test needs to wrap a test function, got " + type);
+        }
+
+        function sinonSandboxedTest() {
+            var config = sinon.getConfig(sinon.config);
+            config.injectInto = config.injectIntoThis && this || config.injectInto;
+            var sandbox = sinon.sandbox.create(config);
+            var exception, result;
+            var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
+
+            try {
+                result = callback.apply(this, args);
+            } catch (e) {
+                exception = e;
+            }
+
+            if (typeof exception !== "undefined") {
+                sandbox.restore();
+                throw exception;
+            }
+            else {
+                sandbox.verifyAndRestore();
+            }
+
+            return result;
+        };
+
+        if (callback.length) {
+            return function sinonAsyncSandboxedTest(callback) {
+                return sinonSandboxedTest.apply(this, arguments);
+            };
+        }
+
+        return sinonSandboxedTest;
+    }
+
+    test.config = {
+        injectIntoThis: true,
+        injectInto: null,
+        properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+        useFakeTimers: true,
+        useFakeServer: true
+    };
+
+    sinon.test = test;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = test; });
+    } else if (commonJSModule) {
+        module.exports = test;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend test.js
+ */
+/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
+/*global module, require, sinon*/
+/**
+ * Test case, sandboxes all test functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon || !Object.prototype.hasOwnProperty) {
+        return;
+    }
+
+    function createTest(property, setUp, tearDown) {
+        return function () {
+            if (setUp) {
+                setUp.apply(this, arguments);
+            }
+
+            var exception, result;
+
+            try {
+                result = property.apply(this, arguments);
+            } catch (e) {
+                exception = e;
+            }
+
+            if (tearDown) {
+                tearDown.apply(this, arguments);
+            }
+
+            if (exception) {
+                throw exception;
+            }
+
+            return result;
+        };
+    }
+
+    function testCase(tests, prefix) {
+        /*jsl:ignore*/
+        if (!tests || typeof tests != "object") {
+            throw new TypeError("sinon.testCase needs an object with test functions");
+        }
+        /*jsl:end*/
+
+        prefix = prefix || "test";
+        var rPrefix = new RegExp("^" + prefix);
+        var methods = {}, testName, property, method;
+        var setUp = tests.setUp;
+        var tearDown = tests.tearDown;
+
+        for (testName in tests) {
+            if (tests.hasOwnProperty(testName)) {
+                property = tests[testName];
+
+                if (/^(setUp|tearDown)$/.test(testName)) {
+                    continue;
+                }
+
+                if (typeof property == "function" && rPrefix.test(testName)) {
+                    method = property;
+
+                    if (setUp || tearDown) {
+                        method = createTest(property, setUp, tearDown);
+                    }
+
+                    methods[testName] = sinon.test(method);
+                } else {
+                    methods[testName] = tests[testName];
+                }
+            }
+        }
+
+        return methods;
+    }
+
+    sinon.testCase = testCase;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = testCase; });
+    } else if (commonJSModule) {
+        module.exports = testCase;
+    }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Assertions matching the test spy retrieval interface.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon, global) {
+    var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
+    var slice = Array.prototype.slice;
+    var assert;
+
+    if (!sinon && commonJSModule) {
+        sinon = require("../sinon");
+    }
+
+    if (!sinon) {
+        return;
+    }
+
+    function verifyIsStub() {
+        var method;
+
+        for (var i = 0, l = arguments.length; i < l; ++i) {
+            method = arguments[i];
+
+            if (!method) {
+                assert.fail("fake is not a spy");
+            }
+
+            if (typeof method != "function") {
+                assert.fail(method + " is not a function");
+            }
+
+            if (typeof method.getCall != "function") {
+                assert.fail(method + " is not stubbed");
+            }
+        }
+    }
+
+    function failAssertion(object, msg) {
+        object = object || global;
+        var failMethod = object.fail || assert.fail;
+        failMethod.call(object, msg);
+    }
+
+    function mirrorPropAsAssertion(name, method, message) {
+        if (arguments.length == 2) {
+            message = method;
+            method = name;
+        }
+
+        assert[name] = function (fake) {
+            verifyIsStub(fake);
+
+            var args = slice.call(arguments, 1);
+            var failed = false;
+
+            if (typeof method == "function") {
+                failed = !method(fake);
+            } else {
+                failed = typeof fake[method] == "function" ?
+                    !fake[method].apply(fake, args) : !fake[method];
+            }
+
+            if (failed) {
+                failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
+            } else {
+                assert.pass(name);
+            }
+        };
+    }
+
+    function exposedName(prefix, prop) {
+        return !prefix || /^fail/.test(prop) ? prop :
+            prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
+    }
+
+    assert = {
+        failException: "AssertError",
+
+        fail: function fail(message) {
+            var error = new Error(message);
+            error.name = this.failException || assert.failException;
+
+            throw error;
+        },
+
+        pass: function pass(assertion) {},
+
+        callOrder: function assertCallOrder() {
+            verifyIsStub.apply(null, arguments);
+            var expected = "", actual = "";
+
+            if (!sinon.calledInOrder(arguments)) {
+                try {
+                    expected = [].join.call(arguments, ", ");
+                    var calls = slice.call(arguments);
+                    var i = calls.length;
+                    while (i) {
+                        if (!calls[--i].called) {
+                            calls.splice(i, 1);
+                        }
+                    }
+                    actual = sinon.orderByFirstCall(calls).join(", ");
+                } catch (e) {
+                    // If this fails, we'll just fall back to the blank string
+                }
+
+                failAssertion(this, "expected " + expected + " to be " +
+                              "called in order but were called as " + actual);
+            } else {
+                assert.pass("callOrder");
+            }
+        },
+
+        callCount: function assertCallCount(method, count) {
+            verifyIsStub(method);
+
+            if (method.callCount != count) {
+                var msg = "expected %n to be called " + sinon.timesInWords(count) +
+                    " but was called %c%C";
+                failAssertion(this, method.printf(msg));
+            } else {
+                assert.pass("callCount");
+            }
+        },
+
+        expose: function expose(target, options) {
+            if (!target) {
+                throw new TypeError("target is null or undefined");
+            }
+
+            var o = options || {};
+            var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
+            var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
+
+            for (var method in this) {
+                if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
+                    target[exposedName(prefix, method)] = this[method];
+                }
+            }
+
+            return target;
+        },
+
+        match: function match(actual, expectation) {
+            var matcher = sinon.match(expectation);
+            if (matcher.test(actual)) {
+                assert.pass("match");
+            } else {
+                var formatted = [
+                    "expected value to match",
+                    "    expected = " + sinon.format(expectation),
+                    "    actual = " + sinon.format(actual)
+                ]
+                failAssertion(this, formatted.join("\n"));
+            }
+        }
+    };
+
+    mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
+    mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
+                          "expected %n to not have been called but was called %c%C");
+    mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
+    mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
+    mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
+    mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
+    mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
+    mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
+    mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
+    mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
+    mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
+    mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
+    mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
+    mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
+    mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
+    mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
+    mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
+    mirrorPropAsAssertion("threw", "%n did not throw exception%C");
+    mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
+
+    sinon.assert = assert;
+
+    if (typeof define === "function" && define.amd) {
+        define(["module"], function(module) { module.exports = assert; });
+    } else if (commonJSModule) {
+        module.exports = assert;
+    }
+}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
+
+/**
+ * @depend ../../sinon.js
+ * @depend event.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, XDomainRequest*/
+/**
+ * Fake XDomainRequest object
+ */
+
+if (typeof sinon == "undefined") {
+    this.sinon = {};
+}
+sinon.xdr = { XDomainRequest: this.XDomainRequest };
+
+// wrapper for global
+(function (global) {
+    var xdr = sinon.xdr;
+    xdr.GlobalXDomainRequest = global.XDomainRequest;
+    xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
+    xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest :  false;
+
+    function FakeXDomainRequest() {
+        this.readyState = FakeXDomainRequest.UNSENT;
+        this.requestBody = null;
+        this.requestHeaders = {};
+        this.status = 0;
+        this.timeout = null;
+
+        if (typeof FakeXDomainRequest.onCreate == "function") {
+            FakeXDomainRequest.onCreate(this);
+        }
+    }
+
+    function verifyState(xdr) {
+        if (xdr.readyState !== FakeXDomainRequest.OPENED) {
+            throw new Error("INVALID_STATE_ERR");
+        }
+
+        if (xdr.sendFlag) {
+            throw new Error("INVALID_STATE_ERR");
+        }
+    }
+
+    function verifyRequestSent(xdr) {
+        if (xdr.readyState == FakeXDomainRequest.UNSENT) {
+            throw new Error("Request not sent");
+        }
+        if (xdr.readyState == FakeXDomainRequest.DONE) {
+            throw new Error("Request done");
+        }
+    }
+
+    function verifyResponseBodyType(body) {
+        if (typeof body != "string") {
+            var error = new Error("Attempted to respond to fake XDomainRequest with " +
+                                  body + ", which is not a string.");
+            error.name = "InvalidBodyException";
+            throw error;
+        }
+    }
+
+    sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
+        open: function open(method, url) {
+            this.method = method;
+            this.url = url;
+
+            this.responseText = null;
+            this.sendFlag = false;
+
+            this.readyStateChange(FakeXDomainRequest.OPENED);
+        },
+
+        readyStateChange: function readyStateChange(state) {
+            this.readyState = state;
+            var eventName = '';
+            switch (this.readyState) {
+            case FakeXDomainRequest.UNSENT:
+                break;
+            case FakeXDomainRequest.OPENED:
+                break;
+            case FakeXDomainRequest.LOADING:
+                if (this.sendFlag){
+                    //raise the progress event
+                    eventName = 'onprogress';
+                }
+                break;
+            case FakeXDomainRequest.DONE:
+                if (this.isTimeout){
+                    eventName = 'ontimeout'
+                }
+                else if (this.errorFlag || (this.status < 200 || this.status > 299)) {
+                    eventName = 'onerror';
+                }
+                else {
+                    eventName = 'onload'
+                }
+                break;
+            }
+
+            // raising event (if defined)
+            if (eventName) {
+                if (typeof this[eventName] == "function") {
+                    try {
+                        this[eventName]();
+                    } catch (e) {
+                        sinon.logError("Fake XHR " + eventName + " handler", e);
+                    }
+                }
+            }
+        },
+
+        send: function send(data) {
+            verifyState(this);
+
+            if (!/^(get|head)$/i.test(this.method)) {
+                this.requestBody = data;
+            }
+            this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+
+            this.errorFlag = false;
+            this.sendFlag = true;
+            this.readyStateChange(FakeXDomainRequest.OPENED);
+
+            if (typeof this.onSend == "function") {
+                this.onSend(this);
+            }
+        },
+
+        abort: function abort() {
+            this.aborted = true;
+            this.responseText = null;
+            this.errorFlag = true;
+
+            if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
+                this.readyStateChange(sinon.FakeXDomainRequest.DONE);
+                this.sendFlag = false;
+            }
+        },
+
+        setResponseBody: function setResponseBody(body) {
+            verifyRequestSent(this);
+            verifyResponseBodyType(body);
+
+            var chunkSize = this.chunkSize || 10;
+            var index = 0;
+            this.responseText = "";
+
+            do {
+                this.readyStateChange(FakeXDomainRequest.LOADING);
+                this.responseText += body.substring(index, index + chunkSize);
+                index += chunkSize;
+            } while (index < body.length);
+
+            this.readyStateChange(FakeXDomainRequest.DONE);
+        },
+
+        respond: function respond(status, contentType, body) {
+            // content-type ignored, since XDomainRequest does not carry this
+            // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
+            // test integration across browsers
+            this.status = typeof status == "number" ? status : 200;
+            this.setResponseBody(body || "");
+        },
+
+        simulatetimeout: function(){
+            this.status = 0;
+            this.isTimeout = true;
+            // Access to this should actually throw an error
+            this.responseText = undefined;
+            this.readyStateChange(FakeXDomainRequest.DONE);
+        }
+    });
+
+    sinon.extend(FakeXDomainRequest, {
+        UNSENT: 0,
+        OPENED: 1,
+        LOADING: 3,
+        DONE: 4
+    });
+
+    sinon.useFakeXDomainRequest = function () {
+        sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
+            if (xdr.supportsXDR) {
+                global.XDomainRequest = xdr.GlobalXDomainRequest;
+            }
+
+            delete sinon.FakeXDomainRequest.restore;
+
+            if (keepOnCreate !== true) {
+                delete sinon.FakeXDomainRequest.onCreate;
+            }
+        };
+        if (xdr.supportsXDR) {
+            global.XDomainRequest = sinon.FakeXDomainRequest;
+        }
+        return sinon.FakeXDomainRequest;
+    };
+
+    sinon.FakeXDomainRequest = FakeXDomainRequest;
+})(this);
+
+if (typeof module == "object" && typeof require == "function") {
+    module.exports = sinon;
+}
+
+return sinon;}.call(typeof window != 'undefined' && window || {}));
diff --git a/resources/lib/sinonjs/sinon-1.9.0.js b/resources/lib/sinonjs/sinon-1.9.0.js
deleted file mode 100644 (file)
index 428b729..0000000
+++ /dev/null
@@ -1,4794 +0,0 @@
-/**
- * Sinon.JS 1.9.0, 2014/03/05
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
- *
- * (The BSD License)
- * 
- * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 
- *     * Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright notice,
- *       this list of conditions and the following disclaimer in the documentation
- *       and/or other materials provided with the distribution.
- *     * Neither the name of Christian Johansen nor the names of his contributors
- *       may be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-this.sinon = (function () {
-var samsam, formatio;
-function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else { formatio = fn(samsam); } }
-define.amd = true;
-((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
- (typeof module === "object" &&
-      function (m) { module.exports = m(); }) || // Node
- function (m) { this.samsam = m(); } // Browser globals
-)(function () {
-    var o = Object.prototype;
-    var div = typeof document !== "undefined" && document.createElement("div");
-
-    function isNaN(value) {
-        // Unlike global isNaN, this avoids type coercion
-        // typeof check avoids IE host object issues, hat tip to
-        // lodash
-        var val = value; // JsLint thinks value !== value is "weird"
-        return typeof value === "number" && value !== val;
-    }
-
-    function getClass(value) {
-        // Returns the internal [[Class]] by calling Object.prototype.toString
-        // with the provided value as this. Return value is a string, naming the
-        // internal class, e.g. "Array"
-        return o.toString.call(value).split(/[ \]]/)[1];
-    }
-
-    /**
-     * @name samsam.isArguments
-     * @param Object object
-     *
-     * Returns ``true`` if ``object`` is an ``arguments`` object,
-     * ``false`` otherwise.
-     */
-    function isArguments(object) {
-        if (typeof object !== "object" || typeof object.length !== "number" ||
-                getClass(object) === "Array") {
-            return false;
-        }
-        if (typeof object.callee == "function") { return true; }
-        try {
-            object[object.length] = 6;
-            delete object[object.length];
-        } catch (e) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @name samsam.isElement
-     * @param Object object
-     *
-     * Returns ``true`` if ``object`` is a DOM element node. Unlike
-     * Underscore.js/lodash, this function will return ``false`` if ``object``
-     * is an *element-like* object, i.e. a regular object with a ``nodeType``
-     * property that holds the value ``1``.
-     */
-    function isElement(object) {
-        if (!object || object.nodeType !== 1 || !div) { return false; }
-        try {
-            object.appendChild(div);
-            object.removeChild(div);
-        } catch (e) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * @name samsam.keys
-     * @param Object object
-     *
-     * Return an array of own property names.
-     */
-    function keys(object) {
-        var ks = [], prop;
-        for (prop in object) {
-            if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
-        }
-        return ks;
-    }
-
-    /**
-     * @name samsam.isDate
-     * @param Object value
-     *
-     * Returns true if the object is a ``Date``, or *date-like*. Duck typing
-     * of date objects work by checking that the object has a ``getTime``
-     * function whose return value equals the return value from the object's
-     * ``valueOf``.
-     */
-    function isDate(value) {
-        return typeof value.getTime == "function" &&
-            value.getTime() == value.valueOf();
-    }
-
-    /**
-     * @name samsam.isNegZero
-     * @param Object value
-     *
-     * Returns ``true`` if ``value`` is ``-0``.
-     */
-    function isNegZero(value) {
-        return value === 0 && 1 / value === -Infinity;
-    }
-
-    /**
-     * @name samsam.equal
-     * @param Object obj1
-     * @param Object obj2
-     *
-     * Returns ``true`` if two objects are strictly equal. Compared to
-     * ``===`` there are two exceptions:
-     *
-     *   - NaN is considered equal to NaN
-     *   - -0 and +0 are not considered equal
-     */
-    function identical(obj1, obj2) {
-        if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
-            return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
-        }
-    }
-
-
-    /**
-     * @name samsam.deepEqual
-     * @param Object obj1
-     * @param Object obj2
-     *
-     * Deep equal comparison. Two values are "deep equal" if:
-     *
-     *   - They are equal, according to samsam.identical
-     *   - They are both date objects representing the same time
-     *   - They are both arrays containing elements that are all deepEqual
-     *   - They are objects with the same set of properties, and each property
-     *     in ``obj1`` is deepEqual to the corresponding property in ``obj2``
-     *
-     * Supports cyclic objects.
-     */
-    function deepEqualCyclic(obj1, obj2) {
-
-        // used for cyclic comparison
-        // contain already visited objects
-        var objects1 = [],
-            objects2 = [],
-        // contain pathes (position in the object structure)
-        // of the already visited objects
-        // indexes same as in objects arrays
-            paths1 = [],
-            paths2 = [],
-        // contains combinations of already compared objects
-        // in the manner: { "$1['ref']$2['ref']": true }
-            compared = {};
-
-        /**
-         * used to check, if the value of a property is an object
-         * (cyclic logic is only needed for objects)
-         * only needed for cyclic logic
-         */
-        function isObject(value) {
-
-            if (typeof value === 'object' && value !== null &&
-                    !(value instanceof Boolean) &&
-                    !(value instanceof Date)    &&
-                    !(value instanceof Number)  &&
-                    !(value instanceof RegExp)  &&
-                    !(value instanceof String)) {
-
-                return true;
-            }
-
-            return false;
-        }
-
-        /**
-         * returns the index of the given object in the
-         * given objects array, -1 if not contained
-         * only needed for cyclic logic
-         */
-        function getIndex(objects, obj) {
-
-            var i;
-            for (i = 0; i < objects.length; i++) {
-                if (objects[i] === obj) {
-                    return i;
-                }
-            }
-
-            return -1;
-        }
-
-        // does the recursion for the deep equal check
-        return (function deepEqual(obj1, obj2, path1, path2) {
-            var type1 = typeof obj1;
-            var type2 = typeof obj2;
-
-            // == null also matches undefined
-            if (obj1 === obj2 ||
-                    isNaN(obj1) || isNaN(obj2) ||
-                    obj1 == null || obj2 == null ||
-                    type1 !== "object" || type2 !== "object") {
-
-                return identical(obj1, obj2);
-            }
-
-            // Elements are only equal if identical(expected, actual)
-            if (isElement(obj1) || isElement(obj2)) { return false; }
-
-            var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
-            if (isDate1 || isDate2) {
-                if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
-                    return false;
-                }
-            }
-
-            if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
-                if (obj1.toString() !== obj2.toString()) { return false; }
-            }
-
-            var class1 = getClass(obj1);
-            var class2 = getClass(obj2);
-            var keys1 = keys(obj1);
-            var keys2 = keys(obj2);
-
-            if (isArguments(obj1) || isArguments(obj2)) {
-                if (obj1.length !== obj2.length) { return false; }
-            } else {
-                if (type1 !== type2 || class1 !== class2 ||
-                        keys1.length !== keys2.length) {
-                    return false;
-                }
-            }
-
-            var key, i, l,
-                // following vars are used for the cyclic logic
-                value1, value2,
-                isObject1, isObject2,
-                index1, index2,
-                newPath1, newPath2;
-
-            for (i = 0, l = keys1.length; i < l; i++) {
-                key = keys1[i];
-                if (!o.hasOwnProperty.call(obj2, key)) {
-                    return false;
-                }
-
-                // Start of the cyclic logic
-
-                value1 = obj1[key];
-                value2 = obj2[key];
-
-                isObject1 = isObject(value1);
-                isObject2 = isObject(value2);
-
-                // determine, if the objects were already visited
-                // (it's faster to check for isObject first, than to
-                // get -1 from getIndex for non objects)
-                index1 = isObject1 ? getIndex(objects1, value1) : -1;
-                index2 = isObject2 ? getIndex(objects2, value2) : -1;
-
-                // determine the new pathes of the objects
-                // - for non cyclic objects the current path will be extended
-                //   by current property name
-                // - for cyclic objects the stored path is taken
-                newPath1 = index1 !== -1
-                    ? paths1[index1]
-                    : path1 + '[' + JSON.stringify(key) + ']';
-                newPath2 = index2 !== -1
-                    ? paths2[index2]
-                    : path2 + '[' + JSON.stringify(key) + ']';
-
-                // stop recursion if current objects are already compared
-                if (compared[newPath1 + newPath2]) {
-                    return true;
-                }
-
-                // remember the current objects and their pathes
-                if (index1 === -1 && isObject1) {
-                    objects1.push(value1);
-                    paths1.push(newPath1);
-                }
-                if (index2 === -1 && isObject2) {
-                    objects2.push(value2);
-                    paths2.push(newPath2);
-                }
-
-                // remember that the current objects are already compared
-                if (isObject1 && isObject2) {
-                    compared[newPath1 + newPath2] = true;
-                }
-
-                // End of cyclic logic
-
-                // neither value1 nor value2 is a cycle
-                // continue with next level
-                if (!deepEqual(value1, value2, newPath1, newPath2)) {
-                    return false;
-                }
-            }
-
-            return true;
-
-        }(obj1, obj2, '$1', '$2'));
-    }
-
-    var match;
-
-    function arrayContains(array, subset) {
-        if (subset.length === 0) { return true; }
-        var i, l, j, k;
-        for (i = 0, l = array.length; i < l; ++i) {
-            if (match(array[i], subset[0])) {
-                for (j = 0, k = subset.length; j < k; ++j) {
-                    if (!match(array[i + j], subset[j])) { return false; }
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * @name samsam.match
-     * @param Object object
-     * @param Object matcher
-     *
-     * Compare arbitrary value ``object`` with matcher.
-     */
-    match = function match(object, matcher) {
-        if (matcher && typeof matcher.test === "function") {
-            return matcher.test(object);
-        }
-
-        if (typeof matcher === "function") {
-            return matcher(object) === true;
-        }
-
-        if (typeof matcher === "string") {
-            matcher = matcher.toLowerCase();
-            var notNull = typeof object === "string" || !!object;
-            return notNull &&
-                (String(object)).toLowerCase().indexOf(matcher) >= 0;
-        }
-
-        if (typeof matcher === "number") {
-            return matcher === object;
-        }
-
-        if (typeof matcher === "boolean") {
-            return matcher === object;
-        }
-
-        if (getClass(object) === "Array" && getClass(matcher) === "Array") {
-            return arrayContains(object, matcher);
-        }
-
-        if (matcher && typeof matcher === "object") {
-            var prop;
-            for (prop in matcher) {
-                if (!match(object[prop], matcher[prop])) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        throw new Error("Matcher was not a string, a number, a " +
-                        "function, a boolean or an object");
-    };
-
-    return {
-        isArguments: isArguments,
-        isElement: isElement,
-        isDate: isDate,
-        isNegZero: isNegZero,
-        identical: identical,
-        deepEqual: deepEqualCyclic,
-        match: match,
-        keys: keys
-    };
-});
-((typeof define === "function" && define.amd && function (m) {
-    define("formatio", ["samsam"], m);
-}) || (typeof module === "object" && function (m) {
-    module.exports = m(require("samsam"));
-}) || function (m) { this.formatio = m(this.samsam); }
-)(function (samsam) {
-    
-    var formatio = {
-        excludeConstructors: ["Object", /^.$/],
-        quoteStrings: true
-    };
-
-    var hasOwn = Object.prototype.hasOwnProperty;
-
-    var specialObjects = [];
-    if (typeof global !== "undefined") {
-        specialObjects.push({ object: global, value: "[object global]" });
-    }
-    if (typeof document !== "undefined") {
-        specialObjects.push({
-            object: document,
-            value: "[object HTMLDocument]"
-        });
-    }
-    if (typeof window !== "undefined") {
-        specialObjects.push({ object: window, value: "[object Window]" });
-    }
-
-    function functionName(func) {
-        if (!func) { return ""; }
-        if (func.displayName) { return func.displayName; }
-        if (func.name) { return func.name; }
-        var matches = func.toString().match(/function\s+([^\(]+)/m);
-        return (matches && matches[1]) || "";
-    }
-
-    function constructorName(f, object) {
-        var name = functionName(object && object.constructor);
-        var excludes = f.excludeConstructors ||
-                formatio.excludeConstructors || [];
-
-        var i, l;
-        for (i = 0, l = excludes.length; i < l; ++i) {
-            if (typeof excludes[i] === "string" && excludes[i] === name) {
-                return "";
-            } else if (excludes[i].test && excludes[i].test(name)) {
-                return "";
-            }
-        }
-
-        return name;
-    }
-
-    function isCircular(object, objects) {
-        if (typeof object !== "object") { return false; }
-        var i, l;
-        for (i = 0, l = objects.length; i < l; ++i) {
-            if (objects[i] === object) { return true; }
-        }
-        return false;
-    }
-
-    function ascii(f, object, processed, indent) {
-        if (typeof object === "string") {
-            var qs = f.quoteStrings;
-            var quote = typeof qs !== "boolean" || qs;
-            return processed || quote ? '"' + object + '"' : object;
-        }
-
-        if (typeof object === "function" && !(object instanceof RegExp)) {
-            return ascii.func(object);
-        }
-
-        processed = processed || [];
-
-        if (isCircular(object, processed)) { return "[Circular]"; }
-
-        if (Object.prototype.toString.call(object) === "[object Array]") {
-            return ascii.array.call(f, object, processed);
-        }
-
-        if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
-        if (samsam.isElement(object)) { return ascii.element(object); }
-
-        if (typeof object.toString === "function" &&
-                object.toString !== Object.prototype.toString) {
-            return object.toString();
-        }
-
-        var i, l;
-        for (i = 0, l = specialObjects.length; i < l; i++) {
-            if (object === specialObjects[i].object) {
-                return specialObjects[i].value;
-            }
-        }
-
-        return ascii.object.call(f, object, processed, indent);
-    }
-
-    ascii.func = function (func) {
-        return "function " + functionName(func) + "() {}";
-    };
-
-    ascii.array = function (array, processed) {
-        processed = processed || [];
-        processed.push(array);
-        var i, l, pieces = [];
-        for (i = 0, l = array.length; i < l; ++i) {
-            pieces.push(ascii(this, array[i], processed));
-        }
-        return "[" + pieces.join(", ") + "]";
-    };
-
-    ascii.object = function (object, processed, indent) {
-        processed = processed || [];
-        processed.push(object);
-        indent = indent || 0;
-        var pieces = [], properties = samsam.keys(object).sort();
-        var length = 3;
-        var prop, str, obj, i, l;
-
-        for (i = 0, l = properties.length; i < l; ++i) {
-            prop = properties[i];
-            obj = object[prop];
-
-            if (isCircular(obj, processed)) {
-                str = "[Circular]";
-            } else {
-                str = ascii(this, obj, processed, indent + 2);
-            }
-
-            str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
-            length += str.length;
-            pieces.push(str);
-        }
-
-        var cons = constructorName(this, object);
-        var prefix = cons ? "[" + cons + "] " : "";
-        var is = "";
-        for (i = 0, l = indent; i < l; ++i) { is += " "; }
-
-        if (length + indent > 80) {
-            return prefix + "{\n  " + is + pieces.join(",\n  " + is) + "\n" +
-                is + "}";
-        }
-        return prefix + "{ " + pieces.join(", ") + " }";
-    };
-
-    ascii.element = function (element) {
-        var tagName = element.tagName.toLowerCase();
-        var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
-
-        for (i = 0, l = attrs.length; i < l; ++i) {
-            attr = attrs.item(i);
-            attrName = attr.nodeName.toLowerCase().replace("html:", "");
-            val = attr.nodeValue;
-            if (attrName !== "contenteditable" || val !== "inherit") {
-                if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
-            }
-        }
-
-        var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
-        var content = element.innerHTML;
-
-        if (content.length > 20) {
-            content = content.substr(0, 20) + "[...]";
-        }
-
-        var res = formatted + pairs.join(" ") + ">" + content +
-                "</" + tagName + ">";
-
-        return res.replace(/ contentEditable="inherit"/, "");
-    };
-
-    function Formatio(options) {
-        for (var opt in options) {
-            this[opt] = options[opt];
-        }
-    }
-
-    Formatio.prototype = {
-        functionName: functionName,
-
-        configure: function (options) {
-            return new Formatio(options);
-        },
-
-        constructorName: function (object) {
-            return constructorName(this, object);
-        },
-
-        ascii: function (object, processed, indent) {
-            return ascii(this, object, processed, indent);
-        }
-    };
-
-    return Formatio.prototype;
-});
-/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
-/*global module, require, __dirname, document*/
-/**
- * Sinon core utilities. For internal use only.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-var sinon = (function (formatio) {
-    var div = typeof document != "undefined" && document.createElement("div");
-    var hasOwn = Object.prototype.hasOwnProperty;
-
-    function isDOMNode(obj) {
-        var success = false;
-
-        try {
-            obj.appendChild(div);
-            success = div.parentNode == obj;
-        } catch (e) {
-            return false;
-        } finally {
-            try {
-                obj.removeChild(div);
-            } catch (e) {
-                // Remove failed, not much we can do about that
-            }
-        }
-
-        return success;
-    }
-
-    function isElement(obj) {
-        return div && obj && obj.nodeType === 1 && isDOMNode(obj);
-    }
-
-    function isFunction(obj) {
-        return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
-    }
-
-    function mirrorProperties(target, source) {
-        for (var prop in source) {
-            if (!hasOwn.call(target, prop)) {
-                target[prop] = source[prop];
-            }
-        }
-    }
-
-    function isRestorable (obj) {
-        return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
-    }
-
-    var sinon = {
-        wrapMethod: function wrapMethod(object, property, method) {
-            if (!object) {
-                throw new TypeError("Should wrap property of object");
-            }
-
-            if (typeof method != "function") {
-                throw new TypeError("Method wrapper should be function");
-            }
-
-            var wrappedMethod = object[property],
-                error;
-
-            if (!isFunction(wrappedMethod)) {
-                error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
-                                    property + " as function");
-            }
-
-            if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
-                error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
-            }
-
-            if (wrappedMethod.calledBefore) {
-                var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
-                error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
-            }
-
-            if (error) {
-                if (wrappedMethod._stack) {
-                    error.stack += '\n--------------\n' + wrappedMethod._stack;
-                }
-                throw error;
-            }
-
-            // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
-            // when using hasOwn.call on objects from other frames.
-            var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
-            object[property] = method;
-            method.displayName = property;
-            // Set up a stack trace which can be used later to find what line of
-            // code the original method was created on.
-            method._stack = (new Error('Stack Trace for original')).stack;
-
-            method.restore = function () {
-                // For prototype properties try to reset by delete first.
-                // If this fails (ex: localStorage on mobile safari) then force a reset
-                // via direct assignment.
-                if (!owned) {
-                    delete object[property];
-                }
-                if (object[property] === method) {
-                    object[property] = wrappedMethod;
-                }
-            };
-
-            method.restore.sinon = true;
-            mirrorProperties(method, wrappedMethod);
-
-            return method;
-        },
-
-        extend: function extend(target) {
-            for (var i = 1, l = arguments.length; i < l; i += 1) {
-                for (var prop in arguments[i]) {
-                    if (arguments[i].hasOwnProperty(prop)) {
-                        target[prop] = arguments[i][prop];
-                    }
-
-                    // DONT ENUM bug, only care about toString
-                    if (arguments[i].hasOwnProperty("toString") &&
-                        arguments[i].toString != target.toString) {
-                        target.toString = arguments[i].toString;
-                    }
-                }
-            }
-
-            return target;
-        },
-
-        create: function create(proto) {
-            var F = function () {};
-            F.prototype = proto;
-            return new F();
-        },
-
-        deepEqual: function deepEqual(a, b) {
-            if (sinon.match && sinon.match.isMatcher(a)) {
-                return a.test(b);
-            }
-            if (typeof a != "object" || typeof b != "object") {
-                return a === b;
-            }
-
-            if (isElement(a) || isElement(b)) {
-                return a === b;
-            }
-
-            if (a === b) {
-                return true;
-            }
-
-            if ((a === null && b !== null) || (a !== null && b === null)) {
-                return false;
-            }
-
-            if (a instanceof RegExp && b instanceof RegExp) {
-              return (a.source === b.source) && (a.global === b.global) && 
-                (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
-            }
-
-            var aString = Object.prototype.toString.call(a);
-            if (aString != Object.prototype.toString.call(b)) {
-                return false;
-            }
-
-            if (aString == "[object Date]") {
-                return a.valueOf() === b.valueOf();
-            }
-
-            var prop, aLength = 0, bLength = 0;
-
-            if (aString == "[object Array]" && a.length !== b.length) {
-                return false;
-            }
-
-            for (prop in a) {
-                aLength += 1;
-
-                if (!deepEqual(a[prop], b[prop])) {
-                    return false;
-                }
-            }
-
-            for (prop in b) {
-                bLength += 1;
-            }
-
-            return aLength == bLength;
-        },
-
-        functionName: function functionName(func) {
-            var name = func.displayName || func.name;
-
-            // Use function decomposition as a last resort to get function
-            // name. Does not rely on function decomposition to work - if it
-            // doesn't debugging will be slightly less informative
-            // (i.e. toString will say 'spy' rather than 'myFunc').
-            if (!name) {
-                var matches = func.toString().match(/function ([^\s\(]+)/);
-                name = matches && matches[1];
-            }
-
-            return name;
-        },
-
-        functionToString: function toString() {
-            if (this.getCall && this.callCount) {
-                var thisValue, prop, i = this.callCount;
-
-                while (i--) {
-                    thisValue = this.getCall(i).thisValue;
-
-                    for (prop in thisValue) {
-                        if (thisValue[prop] === this) {
-                            return prop;
-                        }
-                    }
-                }
-            }
-
-            return this.displayName || "sinon fake";
-        },
-
-        getConfig: function (custom) {
-            var config = {};
-            custom = custom || {};
-            var defaults = sinon.defaultConfig;
-
-            for (var prop in defaults) {
-                if (defaults.hasOwnProperty(prop)) {
-                    config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
-                }
-            }
-
-            return config;
-        },
-
-        format: function (val) {
-            return "" + val;
-        },
-
-        defaultConfig: {
-            injectIntoThis: true,
-            injectInto: null,
-            properties: ["spy", "stub", "mock", "clock", "server", "requests"],
-            useFakeTimers: true,
-            useFakeServer: true
-        },
-
-        timesInWords: function timesInWords(count) {
-            return count == 1 && "once" ||
-                count == 2 && "twice" ||
-                count == 3 && "thrice" ||
-                (count || 0) + " times";
-        },
-
-        calledInOrder: function (spies) {
-            for (var i = 1, l = spies.length; i < l; i++) {
-                if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
-                    return false;
-                }
-            }
-
-            return true;
-        },
-
-        orderByFirstCall: function (spies) {
-            return spies.sort(function (a, b) {
-                // uuid, won't ever be equal
-                var aCall = a.getCall(0);
-                var bCall = b.getCall(0);
-                var aId = aCall && aCall.callId || -1;
-                var bId = bCall && bCall.callId || -1;
-
-                return aId < bId ? -1 : 1;
-            });
-        },
-
-        log: function () {},
-
-        logError: function (label, err) {
-            var msg = label + " threw exception: ";
-            sinon.log(msg + "[" + err.name + "] " + err.message);
-            if (err.stack) { sinon.log(err.stack); }
-
-            setTimeout(function () {
-                err.message = msg + err.message;
-                throw err;
-            }, 0);
-        },
-
-        typeOf: function (value) {
-            if (value === null) {
-                return "null";
-            }
-            else if (value === undefined) {
-                return "undefined";
-            }
-            var string = Object.prototype.toString.call(value);
-            return string.substring(8, string.length - 1).toLowerCase();
-        },
-
-        createStubInstance: function (constructor) {
-            if (typeof constructor !== "function") {
-                throw new TypeError("The constructor should be a function.");
-            }
-            return sinon.stub(sinon.create(constructor.prototype));
-        },
-
-        restore: function (object) {
-            if (object !== null && typeof object === "object") {
-                for (var prop in object) {
-                    if (isRestorable(object[prop])) {
-                        object[prop].restore();
-                    }
-                }
-            }
-            else if (isRestorable(object)) {
-                object.restore();
-            }
-        }
-    };
-
-    var isNode = typeof module !== "undefined" && module.exports;
-    var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
-
-    if (isAMD) {
-        define(function(){
-            return sinon;
-        });
-    } else if (isNode) {
-        try {
-            formatio = require("formatio");
-        } catch (e) {}
-        module.exports = sinon;
-        module.exports.spy = require("./sinon/spy");
-        module.exports.spyCall = require("./sinon/call");
-        module.exports.behavior = require("./sinon/behavior");
-        module.exports.stub = require("./sinon/stub");
-        module.exports.mock = require("./sinon/mock");
-        module.exports.collection = require("./sinon/collection");
-        module.exports.assert = require("./sinon/assert");
-        module.exports.sandbox = require("./sinon/sandbox");
-        module.exports.test = require("./sinon/test");
-        module.exports.testCase = require("./sinon/test_case");
-        module.exports.assert = require("./sinon/assert");
-        module.exports.match = require("./sinon/match");
-    }
-
-    if (formatio) {
-        var formatter = formatio.configure({ quoteStrings: false });
-        sinon.format = function () {
-            return formatter.ascii.apply(formatter, arguments);
-        };
-    } else if (isNode) {
-        try {
-            var util = require("util");
-            sinon.format = function (value) {
-                return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
-            };
-        } catch (e) {
-            /* Node, but no util module - would be very old, but better safe than
-             sorry */
-        }
-    }
-
-    return sinon;
-}(typeof formatio == "object" && formatio));
-
-/* @depend ../sinon.js */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Match functions
- *
- * @author Maximilian Antoni (mail@maxantoni.de)
- * @license BSD
- *
- * Copyright (c) 2012 Maximilian Antoni
- */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    function assertType(value, type, name) {
-        var actual = sinon.typeOf(value);
-        if (actual !== type) {
-            throw new TypeError("Expected type of " + name + " to be " +
-                type + ", but was " + actual);
-        }
-    }
-
-    var matcher = {
-        toString: function () {
-            return this.message;
-        }
-    };
-
-    function isMatcher(object) {
-        return matcher.isPrototypeOf(object);
-    }
-
-    function matchObject(expectation, actual) {
-        if (actual === null || actual === undefined) {
-            return false;
-        }
-        for (var key in expectation) {
-            if (expectation.hasOwnProperty(key)) {
-                var exp = expectation[key];
-                var act = actual[key];
-                if (match.isMatcher(exp)) {
-                    if (!exp.test(act)) {
-                        return false;
-                    }
-                } else if (sinon.typeOf(exp) === "object") {
-                    if (!matchObject(exp, act)) {
-                        return false;
-                    }
-                } else if (!sinon.deepEqual(exp, act)) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    matcher.or = function (m2) {
-        if (!arguments.length) {
-            throw new TypeError("Matcher expected");
-        } else if (!isMatcher(m2)) {
-            m2 = match(m2);
-        }
-        var m1 = this;
-        var or = sinon.create(matcher);
-        or.test = function (actual) {
-            return m1.test(actual) || m2.test(actual);
-        };
-        or.message = m1.message + ".or(" + m2.message + ")";
-        return or;
-    };
-
-    matcher.and = function (m2) {
-        if (!arguments.length) {
-            throw new TypeError("Matcher expected");
-        } else if (!isMatcher(m2)) {
-            m2 = match(m2);
-        }
-        var m1 = this;
-        var and = sinon.create(matcher);
-        and.test = function (actual) {
-            return m1.test(actual) && m2.test(actual);
-        };
-        and.message = m1.message + ".and(" + m2.message + ")";
-        return and;
-    };
-
-    var match = function (expectation, message) {
-        var m = sinon.create(matcher);
-        var type = sinon.typeOf(expectation);
-        switch (type) {
-        case "object":
-            if (typeof expectation.test === "function") {
-                m.test = function (actual) {
-                    return expectation.test(actual) === true;
-                };
-                m.message = "match(" + sinon.functionName(expectation.test) + ")";
-                return m;
-            }
-            var str = [];
-            for (var key in expectation) {
-                if (expectation.hasOwnProperty(key)) {
-                    str.push(key + ": " + expectation[key]);
-                }
-            }
-            m.test = function (actual) {
-                return matchObject(expectation, actual);
-            };
-            m.message = "match(" + str.join(", ") + ")";
-            break;
-        case "number":
-            m.test = function (actual) {
-                return expectation == actual;
-            };
-            break;
-        case "string":
-            m.test = function (actual) {
-                if (typeof actual !== "string") {
-                    return false;
-                }
-                return actual.indexOf(expectation) !== -1;
-            };
-            m.message = "match(\"" + expectation + "\")";
-            break;
-        case "regexp":
-            m.test = function (actual) {
-                if (typeof actual !== "string") {
-                    return false;
-                }
-                return expectation.test(actual);
-            };
-            break;
-        case "function":
-            m.test = expectation;
-            if (message) {
-                m.message = message;
-            } else {
-                m.message = "match(" + sinon.functionName(expectation) + ")";
-            }
-            break;
-        default:
-            m.test = function (actual) {
-              return sinon.deepEqual(expectation, actual);
-            };
-        }
-        if (!m.message) {
-            m.message = "match(" + expectation + ")";
-        }
-        return m;
-    };
-
-    match.isMatcher = isMatcher;
-
-    match.any = match(function () {
-        return true;
-    }, "any");
-
-    match.defined = match(function (actual) {
-        return actual !== null && actual !== undefined;
-    }, "defined");
-
-    match.truthy = match(function (actual) {
-        return !!actual;
-    }, "truthy");
-
-    match.falsy = match(function (actual) {
-        return !actual;
-    }, "falsy");
-
-    match.same = function (expectation) {
-        return match(function (actual) {
-            return expectation === actual;
-        }, "same(" + expectation + ")");
-    };
-
-    match.typeOf = function (type) {
-        assertType(type, "string", "type");
-        return match(function (actual) {
-            return sinon.typeOf(actual) === type;
-        }, "typeOf(\"" + type + "\")");
-    };
-
-    match.instanceOf = function (type) {
-        assertType(type, "function", "type");
-        return match(function (actual) {
-            return actual instanceof type;
-        }, "instanceOf(" + sinon.functionName(type) + ")");
-    };
-
-    function createPropertyMatcher(propertyTest, messagePrefix) {
-        return function (property, value) {
-            assertType(property, "string", "property");
-            var onlyProperty = arguments.length === 1;
-            var message = messagePrefix + "(\"" + property + "\"";
-            if (!onlyProperty) {
-                message += ", " + value;
-            }
-            message += ")";
-            return match(function (actual) {
-                if (actual === undefined || actual === null ||
-                        !propertyTest(actual, property)) {
-                    return false;
-                }
-                return onlyProperty || sinon.deepEqual(value, actual[property]);
-            }, message);
-        };
-    }
-
-    match.has = createPropertyMatcher(function (actual, property) {
-        if (typeof actual === "object") {
-            return property in actual;
-        }
-        return actual[property] !== undefined;
-    }, "has");
-
-    match.hasOwn = createPropertyMatcher(function (actual, property) {
-        return actual.hasOwnProperty(property);
-    }, "hasOwn");
-
-    match.bool = match.typeOf("boolean");
-    match.number = match.typeOf("number");
-    match.string = match.typeOf("string");
-    match.object = match.typeOf("object");
-    match.func = match.typeOf("function");
-    match.array = match.typeOf("array");
-    match.regexp = match.typeOf("regexp");
-    match.date = match.typeOf("date");
-
-    if (commonJSModule) {
-        module.exports = match;
-    } else {
-        sinon.match = match;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-/**
-  * @depend ../sinon.js
-  * @depend match.js
-  */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
-  * Spy calls
-  *
-  * @author Christian Johansen (christian@cjohansen.no)
-  * @author Maximilian Antoni (mail@maxantoni.de)
-  * @license BSD
-  *
-  * Copyright (c) 2010-2013 Christian Johansen
-  * Copyright (c) 2013 Maximilian Antoni
-  */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    function throwYieldError(proxy, text, args) {
-        var msg = sinon.functionName(proxy) + text;
-        if (args.length) {
-            msg += " Received [" + slice.call(args).join(", ") + "]";
-        }
-        throw new Error(msg);
-    }
-
-    var slice = Array.prototype.slice;
-
-    var callProto = {
-        calledOn: function calledOn(thisValue) {
-            if (sinon.match && sinon.match.isMatcher(thisValue)) {
-                return thisValue.test(this.thisValue);
-            }
-            return this.thisValue === thisValue;
-        },
-
-        calledWith: function calledWith() {
-            for (var i = 0, l = arguments.length; i < l; i += 1) {
-                if (!sinon.deepEqual(arguments[i], this.args[i])) {
-                    return false;
-                }
-            }
-
-            return true;
-        },
-
-        calledWithMatch: function calledWithMatch() {
-            for (var i = 0, l = arguments.length; i < l; i += 1) {
-                var actual = this.args[i];
-                var expectation = arguments[i];
-                if (!sinon.match || !sinon.match(expectation).test(actual)) {
-                    return false;
-                }
-            }
-            return true;
-        },
-
-        calledWithExactly: function calledWithExactly() {
-            return arguments.length == this.args.length &&
-                this.calledWith.apply(this, arguments);
-        },
-
-        notCalledWith: function notCalledWith() {
-            return !this.calledWith.apply(this, arguments);
-        },
-
-        notCalledWithMatch: function notCalledWithMatch() {
-            return !this.calledWithMatch.apply(this, arguments);
-        },
-
-        returned: function returned(value) {
-            return sinon.deepEqual(value, this.returnValue);
-        },
-
-        threw: function threw(error) {
-            if (typeof error === "undefined" || !this.exception) {
-                return !!this.exception;
-            }
-
-            return this.exception === error || this.exception.name === error;
-        },
-
-        calledWithNew: function calledWithNew() {
-            return this.proxy.prototype && this.thisValue instanceof this.proxy;
-        },
-
-        calledBefore: function (other) {
-            return this.callId < other.callId;
-        },
-
-        calledAfter: function (other) {
-            return this.callId > other.callId;
-        },
-
-        callArg: function (pos) {
-            this.args[pos]();
-        },
-
-        callArgOn: function (pos, thisValue) {
-            this.args[pos].apply(thisValue);
-        },
-
-        callArgWith: function (pos) {
-            this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
-        },
-
-        callArgOnWith: function (pos, thisValue) {
-            var args = slice.call(arguments, 2);
-            this.args[pos].apply(thisValue, args);
-        },
-
-        "yield": function () {
-            this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
-        },
-
-        yieldOn: function (thisValue) {
-            var args = this.args;
-            for (var i = 0, l = args.length; i < l; ++i) {
-                if (typeof args[i] === "function") {
-                    args[i].apply(thisValue, slice.call(arguments, 1));
-                    return;
-                }
-            }
-            throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
-        },
-
-        yieldTo: function (prop) {
-            this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
-        },
-
-        yieldToOn: function (prop, thisValue) {
-            var args = this.args;
-            for (var i = 0, l = args.length; i < l; ++i) {
-                if (args[i] && typeof args[i][prop] === "function") {
-                    args[i][prop].apply(thisValue, slice.call(arguments, 2));
-                    return;
-                }
-            }
-            throwYieldError(this.proxy, " cannot yield to '" + prop +
-                "' since no callback was passed.", args);
-        },
-
-        toString: function () {
-            var callStr = this.proxy.toString() + "(";
-            var args = [];
-
-            for (var i = 0, l = this.args.length; i < l; ++i) {
-                args.push(sinon.format(this.args[i]));
-            }
-
-            callStr = callStr + args.join(", ") + ")";
-
-            if (typeof this.returnValue != "undefined") {
-                callStr += " => " + sinon.format(this.returnValue);
-            }
-
-            if (this.exception) {
-                callStr += " !" + this.exception.name;
-
-                if (this.exception.message) {
-                    callStr += "(" + this.exception.message + ")";
-                }
-            }
-
-            return callStr;
-        }
-    };
-
-    callProto.invokeCallback = callProto.yield;
-
-    function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
-        if (typeof id !== "number") {
-            throw new TypeError("Call id is not a number");
-        }
-        var proxyCall = sinon.create(callProto);
-        proxyCall.proxy = spy;
-        proxyCall.thisValue = thisValue;
-        proxyCall.args = args;
-        proxyCall.returnValue = returnValue;
-        proxyCall.exception = exception;
-        proxyCall.callId = id;
-
-        return proxyCall;
-    }
-    createSpyCall.toString = callProto.toString; // used by mocks
-
-    if (commonJSModule) {
-        module.exports = createSpyCall;
-    } else {
-        sinon.spyCall = createSpyCall;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-
-/**
-  * @depend ../sinon.js
-  * @depend call.js
-  */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
-  * Spy functions
-  *
-  * @author Christian Johansen (christian@cjohansen.no)
-  * @license BSD
-  *
-  * Copyright (c) 2010-2013 Christian Johansen
-  */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-    var push = Array.prototype.push;
-    var slice = Array.prototype.slice;
-    var callId = 0;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    function spy(object, property) {
-        if (!property && typeof object == "function") {
-            return spy.create(object);
-        }
-
-        if (!object && !property) {
-            return spy.create(function () { });
-        }
-
-        var method = object[property];
-        return sinon.wrapMethod(object, property, spy.create(method));
-    }
-
-    function matchingFake(fakes, args, strict) {
-        if (!fakes) {
-            return;
-        }
-
-        for (var i = 0, l = fakes.length; i < l; i++) {
-            if (fakes[i].matches(args, strict)) {
-                return fakes[i];
-            }
-        }
-    }
-
-    function incrementCallCount() {
-        this.called = true;
-        this.callCount += 1;
-        this.notCalled = false;
-        this.calledOnce = this.callCount == 1;
-        this.calledTwice = this.callCount == 2;
-        this.calledThrice = this.callCount == 3;
-    }
-
-    function createCallProperties() {
-        this.firstCall = this.getCall(0);
-        this.secondCall = this.getCall(1);
-        this.thirdCall = this.getCall(2);
-        this.lastCall = this.getCall(this.callCount - 1);
-    }
-
-    var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
-    function createProxy(func) {
-        // Retain the function length:
-        var p;
-        if (func.length) {
-            eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
-                ") { return p.invoke(func, this, slice.call(arguments)); });");
-        }
-        else {
-            p = function proxy() {
-                return p.invoke(func, this, slice.call(arguments));
-            };
-        }
-        return p;
-    }
-
-    var uuid = 0;
-
-    // Public API
-    var spyApi = {
-        reset: function () {
-            this.called = false;
-            this.notCalled = true;
-            this.calledOnce = false;
-            this.calledTwice = false;
-            this.calledThrice = false;
-            this.callCount = 0;
-            this.firstCall = null;
-            this.secondCall = null;
-            this.thirdCall = null;
-            this.lastCall = null;
-            this.args = [];
-            this.returnValues = [];
-            this.thisValues = [];
-            this.exceptions = [];
-            this.callIds = [];
-            if (this.fakes) {
-                for (var i = 0; i < this.fakes.length; i++) {
-                    this.fakes[i].reset();
-                }
-            }
-        },
-
-        create: function create(func) {
-            var name;
-
-            if (typeof func != "function") {
-                func = function () { };
-            } else {
-                name = sinon.functionName(func);
-            }
-
-            var proxy = createProxy(func);
-
-            sinon.extend(proxy, spy);
-            delete proxy.create;
-            sinon.extend(proxy, func);
-
-            proxy.reset();
-            proxy.prototype = func.prototype;
-            proxy.displayName = name || "spy";
-            proxy.toString = sinon.functionToString;
-            proxy._create = sinon.spy.create;
-            proxy.id = "spy#" + uuid++;
-
-            return proxy;
-        },
-
-        invoke: function invoke(func, thisValue, args) {
-            var matching = matchingFake(this.fakes, args);
-            var exception, returnValue;
-
-            incrementCallCount.call(this);
-            push.call(this.thisValues, thisValue);
-            push.call(this.args, args);
-            push.call(this.callIds, callId++);
-
-            try {
-                if (matching) {
-                    returnValue = matching.invoke(func, thisValue, args);
-                } else {
-                    returnValue = (this.func || func).apply(thisValue, args);
-                }
-
-                var thisCall = this.getCall(this.callCount - 1);
-                if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
-                    returnValue = thisValue;
-                }
-            } catch (e) {
-                exception = e;
-            }
-
-            push.call(this.exceptions, exception);
-            push.call(this.returnValues, returnValue);
-
-            createCallProperties.call(this);
-
-            if (exception !== undefined) {
-                throw exception;
-            }
-
-            return returnValue;
-        },
-
-        getCall: function getCall(i) {
-            if (i < 0 || i >= this.callCount) {
-                return null;
-            }
-
-            return sinon.spyCall(this, this.thisValues[i], this.args[i],
-                                    this.returnValues[i], this.exceptions[i],
-                                    this.callIds[i]);
-        },
-
-        getCalls: function () {
-            var calls = [];
-            var i;
-
-            for (i = 0; i < this.callCount; i++) {
-                calls.push(this.getCall(i));
-            }
-
-            return calls;
-        },
-
-        calledBefore: function calledBefore(spyFn) {
-            if (!this.called) {
-                return false;
-            }
-
-            if (!spyFn.called) {
-                return true;
-            }
-
-            return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
-        },
-
-        calledAfter: function calledAfter(spyFn) {
-            if (!this.called || !spyFn.called) {
-                return false;
-            }
-
-            return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
-        },
-
-        withArgs: function () {
-            var args = slice.call(arguments);
-
-            if (this.fakes) {
-                var match = matchingFake(this.fakes, args, true);
-
-                if (match) {
-                    return match;
-                }
-            } else {
-                this.fakes = [];
-            }
-
-            var original = this;
-            var fake = this._create();
-            fake.matchingAguments = args;
-            fake.parent = this;
-            push.call(this.fakes, fake);
-
-            fake.withArgs = function () {
-                return original.withArgs.apply(original, arguments);
-            };
-
-            for (var i = 0; i < this.args.length; i++) {
-                if (fake.matches(this.args[i])) {
-                    incrementCallCount.call(fake);
-                    push.call(fake.thisValues, this.thisValues[i]);
-                    push.call(fake.args, this.args[i]);
-                    push.call(fake.returnValues, this.returnValues[i]);
-                    push.call(fake.exceptions, this.exceptions[i]);
-                    push.call(fake.callIds, this.callIds[i]);
-                }
-            }
-            createCallProperties.call(fake);
-
-            return fake;
-        },
-
-        matches: function (args, strict) {
-            var margs = this.matchingAguments;
-
-            if (margs.length <= args.length &&
-                sinon.deepEqual(margs, args.slice(0, margs.length))) {
-                return !strict || margs.length == args.length;
-            }
-        },
-
-        printf: function (format) {
-            var spy = this;
-            var args = slice.call(arguments, 1);
-            var formatter;
-
-            return (format || "").replace(/%(.)/g, function (match, specifyer) {
-                formatter = spyApi.formatters[specifyer];
-
-                if (typeof formatter == "function") {
-                    return formatter.call(null, spy, args);
-                } else if (!isNaN(parseInt(specifyer, 10))) {
-                    return sinon.format(args[specifyer - 1]);
-                }
-
-                return "%" + specifyer;
-            });
-        }
-    };
-
-    function delegateToCalls(method, matchAny, actual, notCalled) {
-        spyApi[method] = function () {
-            if (!this.called) {
-                if (notCalled) {
-                    return notCalled.apply(this, arguments);
-                }
-                return false;
-            }
-
-            var currentCall;
-            var matches = 0;
-
-            for (var i = 0, l = this.callCount; i < l; i += 1) {
-                currentCall = this.getCall(i);
-
-                if (currentCall[actual || method].apply(currentCall, arguments)) {
-                    matches += 1;
-
-                    if (matchAny) {
-                        return true;
-                    }
-                }
-            }
-
-            return matches === this.callCount;
-        };
-    }
-
-    delegateToCalls("calledOn", true);
-    delegateToCalls("alwaysCalledOn", false, "calledOn");
-    delegateToCalls("calledWith", true);
-    delegateToCalls("calledWithMatch", true);
-    delegateToCalls("alwaysCalledWith", false, "calledWith");
-    delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
-    delegateToCalls("calledWithExactly", true);
-    delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
-    delegateToCalls("neverCalledWith", false, "notCalledWith",
-        function () { return true; });
-    delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
-        function () { return true; });
-    delegateToCalls("threw", true);
-    delegateToCalls("alwaysThrew", false, "threw");
-    delegateToCalls("returned", true);
-    delegateToCalls("alwaysReturned", false, "returned");
-    delegateToCalls("calledWithNew", true);
-    delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
-    delegateToCalls("callArg", false, "callArgWith", function () {
-        throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
-    });
-    spyApi.callArgWith = spyApi.callArg;
-    delegateToCalls("callArgOn", false, "callArgOnWith", function () {
-        throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
-    });
-    spyApi.callArgOnWith = spyApi.callArgOn;
-    delegateToCalls("yield", false, "yield", function () {
-        throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
-    });
-    // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
-    spyApi.invokeCallback = spyApi.yield;
-    delegateToCalls("yieldOn", false, "yieldOn", function () {
-        throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
-    });
-    delegateToCalls("yieldTo", false, "yieldTo", function (property) {
-        throw new Error(this.toString() + " cannot yield to '" + property +
-            "' since it was not yet invoked.");
-    });
-    delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
-        throw new Error(this.toString() + " cannot yield to '" + property +
-            "' since it was not yet invoked.");
-    });
-
-    spyApi.formatters = {
-        "c": function (spy) {
-            return sinon.timesInWords(spy.callCount);
-        },
-
-        "n": function (spy) {
-            return spy.toString();
-        },
-
-        "C": function (spy) {
-            var calls = [];
-
-            for (var i = 0, l = spy.callCount; i < l; ++i) {
-                var stringifiedCall = "    " + spy.getCall(i).toString();
-                if (/\n/.test(calls[i - 1])) {
-                    stringifiedCall = "\n" + stringifiedCall;
-                }
-                push.call(calls, stringifiedCall);
-            }
-
-            return calls.length > 0 ? "\n" + calls.join("\n") : "";
-        },
-
-        "t": function (spy) {
-            var objects = [];
-
-            for (var i = 0, l = spy.callCount; i < l; ++i) {
-                push.call(objects, sinon.format(spy.thisValues[i]));
-            }
-
-            return objects.join(", ");
-        },
-
-        "*": function (spy, args) {
-            var formatted = [];
-
-            for (var i = 0, l = args.length; i < l; ++i) {
-                push.call(formatted, sinon.format(args[i]));
-            }
-
-            return formatted.join(", ");
-        }
-    };
-
-    sinon.extend(spy, spyApi);
-
-    spy.spyCall = sinon.spyCall;
-
-    if (commonJSModule) {
-        module.exports = spy;
-    } else {
-        sinon.spy = spy;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- */
-/*jslint eqeqeq: false, onevar: false*/
-/*global module, require, sinon, process, setImmediate, setTimeout*/
-/**
- * Stub behavior
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @author Tim Fischbach (mail@timfischbach.de)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    var slice = Array.prototype.slice;
-    var join = Array.prototype.join;
-    var proto;
-
-    var nextTick = (function () {
-        if (typeof process === "object" && typeof process.nextTick === "function") {
-            return process.nextTick;
-        } else if (typeof setImmediate === "function") {
-            return setImmediate;
-        } else {
-            return function (callback) {
-                setTimeout(callback, 0);
-            };
-        }
-    })();
-
-    function throwsException(error, message) {
-        if (typeof error == "string") {
-            this.exception = new Error(message || "");
-            this.exception.name = error;
-        } else if (!error) {
-            this.exception = new Error("Error");
-        } else {
-            this.exception = error;
-        }
-
-        return this;
-    }
-
-    function getCallback(behavior, args) {
-        var callArgAt = behavior.callArgAt;
-
-        if (callArgAt < 0) {
-            var callArgProp = behavior.callArgProp;
-
-            for (var i = 0, l = args.length; i < l; ++i) {
-                if (!callArgProp && typeof args[i] == "function") {
-                    return args[i];
-                }
-
-                if (callArgProp && args[i] &&
-                    typeof args[i][callArgProp] == "function") {
-                    return args[i][callArgProp];
-                }
-            }
-
-            return null;
-        }
-
-        return args[callArgAt];
-    }
-
-    function getCallbackError(behavior, func, args) {
-        if (behavior.callArgAt < 0) {
-            var msg;
-
-            if (behavior.callArgProp) {
-                msg = sinon.functionName(behavior.stub) +
-                    " expected to yield to '" + behavior.callArgProp +
-                    "', but no object with such a property was passed.";
-            } else {
-                msg = sinon.functionName(behavior.stub) +
-                    " expected to yield, but no callback was passed.";
-            }
-
-            if (args.length > 0) {
-                msg += " Received [" + join.call(args, ", ") + "]";
-            }
-
-            return msg;
-        }
-
-        return "argument at index " + behavior.callArgAt + " is not a function: " + func;
-    }
-
-    function callCallback(behavior, args) {
-        if (typeof behavior.callArgAt == "number") {
-            var func = getCallback(behavior, args);
-
-            if (typeof func != "function") {
-                throw new TypeError(getCallbackError(behavior, func, args));
-            }
-
-            if (behavior.callbackAsync) {
-                nextTick(function() {
-                    func.apply(behavior.callbackContext, behavior.callbackArguments);
-                });
-            } else {
-                func.apply(behavior.callbackContext, behavior.callbackArguments);
-            }
-        }
-    }
-
-    proto = {
-        create: function(stub) {
-            var behavior = sinon.extend({}, sinon.behavior);
-            delete behavior.create;
-            behavior.stub = stub;
-
-            return behavior;
-        },
-
-        isPresent: function() {
-            return (typeof this.callArgAt == 'number' ||
-                    this.exception ||
-                    typeof this.returnArgAt == 'number' ||
-                    this.returnThis ||
-                    this.returnValueDefined);
-        },
-
-        invoke: function(context, args) {
-            callCallback(this, args);
-
-            if (this.exception) {
-                throw this.exception;
-            } else if (typeof this.returnArgAt == 'number') {
-                return args[this.returnArgAt];
-            } else if (this.returnThis) {
-                return context;
-            }
-
-            return this.returnValue;
-        },
-
-        onCall: function(index) {
-            return this.stub.onCall(index);
-        },
-
-        onFirstCall: function() {
-            return this.stub.onFirstCall();
-        },
-
-        onSecondCall: function() {
-            return this.stub.onSecondCall();
-        },
-
-        onThirdCall: function() {
-            return this.stub.onThirdCall();
-        },
-
-        withArgs: function(/* arguments */) {
-            throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
-                            'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
-        },
-
-        callsArg: function callsArg(pos) {
-            if (typeof pos != "number") {
-                throw new TypeError("argument index is not number");
-            }
-
-            this.callArgAt = pos;
-            this.callbackArguments = [];
-            this.callbackContext = undefined;
-            this.callArgProp = undefined;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-        callsArgOn: function callsArgOn(pos, context) {
-            if (typeof pos != "number") {
-                throw new TypeError("argument index is not number");
-            }
-            if (typeof context != "object") {
-                throw new TypeError("argument context is not an object");
-            }
-
-            this.callArgAt = pos;
-            this.callbackArguments = [];
-            this.callbackContext = context;
-            this.callArgProp = undefined;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-        callsArgWith: function callsArgWith(pos) {
-            if (typeof pos != "number") {
-                throw new TypeError("argument index is not number");
-            }
-
-            this.callArgAt = pos;
-            this.callbackArguments = slice.call(arguments, 1);
-            this.callbackContext = undefined;
-            this.callArgProp = undefined;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-        callsArgOnWith: function callsArgWith(pos, context) {
-            if (typeof pos != "number") {
-                throw new TypeError("argument index is not number");
-            }
-            if (typeof context != "object") {
-                throw new TypeError("argument context is not an object");
-            }
-
-            this.callArgAt = pos;
-            this.callbackArguments = slice.call(arguments, 2);
-            this.callbackContext = context;
-            this.callArgProp = undefined;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-        yields: function () {
-            this.callArgAt = -1;
-            this.callbackArguments = slice.call(arguments, 0);
-            this.callbackContext = undefined;
-            this.callArgProp = undefined;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-        yieldsOn: function (context) {
-            if (typeof context != "object") {
-                throw new TypeError("argument context is not an object");
-            }
-
-            this.callArgAt = -1;
-            this.callbackArguments = slice.call(arguments, 1);
-            this.callbackContext = context;
-            this.callArgProp = undefined;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-        yieldsTo: function (prop) {
-            this.callArgAt = -1;
-            this.callbackArguments = slice.call(arguments, 1);
-            this.callbackContext = undefined;
-            this.callArgProp = prop;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-        yieldsToOn: function (prop, context) {
-            if (typeof context != "object") {
-                throw new TypeError("argument context is not an object");
-            }
-
-            this.callArgAt = -1;
-            this.callbackArguments = slice.call(arguments, 2);
-            this.callbackContext = context;
-            this.callArgProp = prop;
-            this.callbackAsync = false;
-
-            return this;
-        },
-
-
-        "throws": throwsException,
-        throwsException: throwsException,
-
-        returns: function returns(value) {
-            this.returnValue = value;
-            this.returnValueDefined = true;
-
-            return this;
-        },
-
-        returnsArg: function returnsArg(pos) {
-            if (typeof pos != "number") {
-                throw new TypeError("argument index is not number");
-            }
-
-            this.returnArgAt = pos;
-
-            return this;
-        },
-
-        returnsThis: function returnsThis() {
-            this.returnThis = true;
-
-            return this;
-        }
-    };
-
-    // create asynchronous versions of callsArg* and yields* methods
-    for (var method in proto) {
-        // need to avoid creating anotherasync versions of the newly added async methods
-        if (proto.hasOwnProperty(method) &&
-            method.match(/^(callsArg|yields)/) &&
-            !method.match(/Async/)) {
-            proto[method + 'Async'] = (function (syncFnName) {
-                return function () {
-                    var result = this[syncFnName].apply(this, arguments);
-                    this.callbackAsync = true;
-                    return result;
-                };
-            })(method);
-        }
-    }
-
-    if (commonJSModule) {
-        module.exports = proto;
-    } else {
-        sinon.behavior = proto;
-    }
-}(typeof sinon == "object" && sinon || null));
-/**
- * @depend ../sinon.js
- * @depend spy.js
- * @depend behavior.js
- */
-/*jslint eqeqeq: false, onevar: false*/
-/*global module, require, sinon*/
-/**
- * Stub functions
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    function stub(object, property, func) {
-        if (!!func && typeof func != "function") {
-            throw new TypeError("Custom stub should be function");
-        }
-
-        var wrapper;
-
-        if (func) {
-            wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
-        } else {
-            wrapper = stub.create();
-        }
-
-        if (!object && typeof property === "undefined") {
-            return sinon.stub.create();
-        }
-
-        if (typeof property === "undefined" && typeof object == "object") {
-            for (var prop in object) {
-                if (typeof object[prop] === "function") {
-                    stub(object, prop);
-                }
-            }
-
-            return object;
-        }
-
-        return sinon.wrapMethod(object, property, wrapper);
-    }
-
-    function getDefaultBehavior(stub) {
-        return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
-    }
-
-    function getParentBehaviour(stub) {
-        return (stub.parent && getCurrentBehavior(stub.parent));
-    }
-
-    function getCurrentBehavior(stub) {
-        var behavior = stub.behaviors[stub.callCount - 1];
-        return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
-    }
-
-    var uuid = 0;
-
-    sinon.extend(stub, (function () {
-        var proto = {
-            create: function create() {
-                var functionStub = function () {
-                    return getCurrentBehavior(functionStub).invoke(this, arguments);
-                };
-
-                functionStub.id = "stub#" + uuid++;
-                var orig = functionStub;
-                functionStub = sinon.spy.create(functionStub);
-                functionStub.func = orig;
-
-                sinon.extend(functionStub, stub);
-                functionStub._create = sinon.stub.create;
-                functionStub.displayName = "stub";
-                functionStub.toString = sinon.functionToString;
-
-                functionStub.defaultBehavior = null;
-                functionStub.behaviors = [];
-
-                return functionStub;
-            },
-
-            resetBehavior: function () {
-                var i;
-
-                this.defaultBehavior = null;
-                this.behaviors = [];
-
-                delete this.returnValue;
-                delete this.returnArgAt;
-                this.returnThis = false;
-
-                if (this.fakes) {
-                    for (i = 0; i < this.fakes.length; i++) {
-                        this.fakes[i].resetBehavior();
-                    }
-                }
-            },
-
-            onCall: function(index) {
-                if (!this.behaviors[index]) {
-                    this.behaviors[index] = sinon.behavior.create(this);
-                }
-
-                return this.behaviors[index];
-            },
-
-            onFirstCall: function() {
-                return this.onCall(0);
-            },
-
-            onSecondCall: function() {
-                return this.onCall(1);
-            },
-
-            onThirdCall: function() {
-                return this.onCall(2);
-            }
-        };
-
-        for (var method in sinon.behavior) {
-            if (sinon.behavior.hasOwnProperty(method) &&
-                !proto.hasOwnProperty(method) &&
-                method != 'create' &&
-                method != 'withArgs' &&
-                method != 'invoke') {
-                proto[method] = (function(behaviorMethod) {
-                    return function() {
-                        this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
-                        this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
-                        return this;
-                    };
-                }(method));
-            }
-        }
-
-        return proto;
-    }()));
-
-    if (commonJSModule) {
-        module.exports = stub;
-    } else {
-        sinon.stub = stub;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- */
-/*jslint eqeqeq: false, onevar: false, nomen: false*/
-/*global module, require, sinon*/
-/**
- * Mock functions.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-    var push = [].push;
-    var match;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    match = sinon.match;
-
-    if (!match && commonJSModule) {
-        match = require("./match");
-    }
-
-    function mock(object) {
-        if (!object) {
-            return sinon.expectation.create("Anonymous mock");
-        }
-
-        return mock.create(object);
-    }
-
-    sinon.mock = mock;
-
-    sinon.extend(mock, (function () {
-        function each(collection, callback) {
-            if (!collection) {
-                return;
-            }
-
-            for (var i = 0, l = collection.length; i < l; i += 1) {
-                callback(collection[i]);
-            }
-        }
-
-        return {
-            create: function create(object) {
-                if (!object) {
-                    throw new TypeError("object is null");
-                }
-
-                var mockObject = sinon.extend({}, mock);
-                mockObject.object = object;
-                delete mockObject.create;
-
-                return mockObject;
-            },
-
-            expects: function expects(method) {
-                if (!method) {
-                    throw new TypeError("method is falsy");
-                }
-
-                if (!this.expectations) {
-                    this.expectations = {};
-                    this.proxies = [];
-                }
-
-                if (!this.expectations[method]) {
-                    this.expectations[method] = [];
-                    var mockObject = this;
-
-                    sinon.wrapMethod(this.object, method, function () {
-                        return mockObject.invokeMethod(method, this, arguments);
-                    });
-
-                    push.call(this.proxies, method);
-                }
-
-                var expectation = sinon.expectation.create(method);
-                push.call(this.expectations[method], expectation);
-
-                return expectation;
-            },
-
-            restore: function restore() {
-                var object = this.object;
-
-                each(this.proxies, function (proxy) {
-                    if (typeof object[proxy].restore == "function") {
-                        object[proxy].restore();
-                    }
-                });
-            },
-
-            verify: function verify() {
-                var expectations = this.expectations || {};
-                var messages = [], met = [];
-
-                each(this.proxies, function (proxy) {
-                    each(expectations[proxy], function (expectation) {
-                        if (!expectation.met()) {
-                            push.call(messages, expectation.toString());
-                        } else {
-                            push.call(met, expectation.toString());
-                        }
-                    });
-                });
-
-                this.restore();
-
-                if (messages.length > 0) {
-                    sinon.expectation.fail(messages.concat(met).join("\n"));
-                } else {
-                    sinon.expectation.pass(messages.concat(met).join("\n"));
-                }
-
-                return true;
-            },
-
-            invokeMethod: function invokeMethod(method, thisValue, args) {
-                var expectations = this.expectations && this.expectations[method];
-                var length = expectations && expectations.length || 0, i;
-
-                for (i = 0; i < length; i += 1) {
-                    if (!expectations[i].met() &&
-                        expectations[i].allowsCall(thisValue, args)) {
-                        return expectations[i].apply(thisValue, args);
-                    }
-                }
-
-                var messages = [], available, exhausted = 0;
-
-                for (i = 0; i < length; i += 1) {
-                    if (expectations[i].allowsCall(thisValue, args)) {
-                        available = available || expectations[i];
-                    } else {
-                        exhausted += 1;
-                    }
-                    push.call(messages, "    " + expectations[i].toString());
-                }
-
-                if (exhausted === 0) {
-                    return available.apply(thisValue, args);
-                }
-
-                messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
-                    proxy: method,
-                    args: args
-                }));
-
-                sinon.expectation.fail(messages.join("\n"));
-            }
-        };
-    }()));
-
-    var times = sinon.timesInWords;
-
-    sinon.expectation = (function () {
-        var slice = Array.prototype.slice;
-        var _invoke = sinon.spy.invoke;
-
-        function callCountInWords(callCount) {
-            if (callCount == 0) {
-                return "never called";
-            } else {
-                return "called " + times(callCount);
-            }
-        }
-
-        function expectedCallCountInWords(expectation) {
-            var min = expectation.minCalls;
-            var max = expectation.maxCalls;
-
-            if (typeof min == "number" && typeof max == "number") {
-                var str = times(min);
-
-                if (min != max) {
-                    str = "at least " + str + " and at most " + times(max);
-                }
-
-                return str;
-            }
-
-            if (typeof min == "number") {
-                return "at least " + times(min);
-            }
-
-            return "at most " + times(max);
-        }
-
-        function receivedMinCalls(expectation) {
-            var hasMinLimit = typeof expectation.minCalls == "number";
-            return !hasMinLimit || expectation.callCount >= expectation.minCalls;
-        }
-
-        function receivedMaxCalls(expectation) {
-            if (typeof expectation.maxCalls != "number") {
-                return false;
-            }
-
-            return expectation.callCount == expectation.maxCalls;
-        }
-
-        function verifyMatcher(possibleMatcher, arg){
-            if (match && match.isMatcher(possibleMatcher)) {
-                return possibleMatcher.test(arg);
-            } else {
-                return true;
-            }
-        }
-
-        return {
-            minCalls: 1,
-            maxCalls: 1,
-
-            create: function create(methodName) {
-                var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
-                delete expectation.create;
-                expectation.method = methodName;
-
-                return expectation;
-            },
-
-            invoke: function invoke(func, thisValue, args) {
-                this.verifyCallAllowed(thisValue, args);
-
-                return _invoke.apply(this, arguments);
-            },
-
-            atLeast: function atLeast(num) {
-                if (typeof num != "number") {
-                    throw new TypeError("'" + num + "' is not number");
-                }
-
-                if (!this.limitsSet) {
-                    this.maxCalls = null;
-                    this.limitsSet = true;
-                }
-
-                this.minCalls = num;
-
-                return this;
-            },
-
-            atMost: function atMost(num) {
-                if (typeof num != "number") {
-                    throw new TypeError("'" + num + "' is not number");
-                }
-
-                if (!this.limitsSet) {
-                    this.minCalls = null;
-                    this.limitsSet = true;
-                }
-
-                this.maxCalls = num;
-
-                return this;
-            },
-
-            never: function never() {
-                return this.exactly(0);
-            },
-
-            once: function once() {
-                return this.exactly(1);
-            },
-
-            twice: function twice() {
-                return this.exactly(2);
-            },
-
-            thrice: function thrice() {
-                return this.exactly(3);
-            },
-
-            exactly: function exactly(num) {
-                if (typeof num != "number") {
-                    throw new TypeError("'" + num + "' is not a number");
-                }
-
-                this.atLeast(num);
-                return this.atMost(num);
-            },
-
-            met: function met() {
-                return !this.failed && receivedMinCalls(this);
-            },
-
-            verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
-                if (receivedMaxCalls(this)) {
-                    this.failed = true;
-                    sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
-                }
-
-                if ("expectedThis" in this && this.expectedThis !== thisValue) {
-                    sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
-                        this.expectedThis);
-                }
-
-                if (!("expectedArguments" in this)) {
-                    return;
-                }
-
-                if (!args) {
-                    sinon.expectation.fail(this.method + " received no arguments, expected " +
-                        sinon.format(this.expectedArguments));
-                }
-
-                if (args.length < this.expectedArguments.length) {
-                    sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
-                        "), expected " + sinon.format(this.expectedArguments));
-                }
-
-                if (this.expectsExactArgCount &&
-                    args.length != this.expectedArguments.length) {
-                    sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
-                        "), expected " + sinon.format(this.expectedArguments));
-                }
-
-                for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
-
-                    if (!verifyMatcher(this.expectedArguments[i],args[i])) {
-                        sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
-                            ", didn't match " + this.expectedArguments.toString());
-                    }
-
-                    if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
-                        sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
-                            ", expected " + sinon.format(this.expectedArguments));
-                    }
-                }
-            },
-
-            allowsCall: function allowsCall(thisValue, args) {
-                if (this.met() && receivedMaxCalls(this)) {
-                    return false;
-                }
-
-                if ("expectedThis" in this && this.expectedThis !== thisValue) {
-                    return false;
-                }
-
-                if (!("expectedArguments" in this)) {
-                    return true;
-                }
-
-                args = args || [];
-
-                if (args.length < this.expectedArguments.length) {
-                    return false;
-                }
-
-                if (this.expectsExactArgCount &&
-                    args.length != this.expectedArguments.length) {
-                    return false;
-                }
-
-                for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
-                    if (!verifyMatcher(this.expectedArguments[i],args[i])) {
-                        return false;
-                    }
-
-                    if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
-                        return false;
-                    }
-                }
-
-                return true;
-            },
-
-            withArgs: function withArgs() {
-                this.expectedArguments = slice.call(arguments);
-                return this;
-            },
-
-            withExactArgs: function withExactArgs() {
-                this.withArgs.apply(this, arguments);
-                this.expectsExactArgCount = true;
-                return this;
-            },
-
-            on: function on(thisValue) {
-                this.expectedThis = thisValue;
-                return this;
-            },
-
-            toString: function () {
-                var args = (this.expectedArguments || []).slice();
-
-                if (!this.expectsExactArgCount) {
-                    push.call(args, "[...]");
-                }
-
-                var callStr = sinon.spyCall.toString.call({
-                    proxy: this.method || "anonymous mock expectation",
-                    args: args
-                });
-
-                var message = callStr.replace(", [...", "[, ...") + " " +
-                    expectedCallCountInWords(this);
-
-                if (this.met()) {
-                    return "Expectation met: " + message;
-                }
-
-                return "Expected " + message + " (" +
-                    callCountInWords(this.callCount) + ")";
-            },
-
-            verify: function verify() {
-                if (!this.met()) {
-                    sinon.expectation.fail(this.toString());
-                } else {
-                    sinon.expectation.pass(this.toString());
-                }
-
-                return true;
-            },
-
-            pass: function(message) {
-              sinon.assert.pass(message);
-            },
-            fail: function (message) {
-                var exception = new Error(message);
-                exception.name = "ExpectationError";
-
-                throw exception;
-            }
-        };
-    }());
-
-    if (commonJSModule) {
-        module.exports = mock;
-    } else {
-        sinon.mock = mock;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- * @depend mock.js
- */
-/*jslint eqeqeq: false, onevar: false, forin: true*/
-/*global module, require, sinon*/
-/**
- * Collections of stubs, spies and mocks.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-    var push = [].push;
-    var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    function getFakes(fakeCollection) {
-        if (!fakeCollection.fakes) {
-            fakeCollection.fakes = [];
-        }
-
-        return fakeCollection.fakes;
-    }
-
-    function each(fakeCollection, method) {
-        var fakes = getFakes(fakeCollection);
-
-        for (var i = 0, l = fakes.length; i < l; i += 1) {
-            if (typeof fakes[i][method] == "function") {
-                fakes[i][method]();
-            }
-        }
-    }
-
-    function compact(fakeCollection) {
-        var fakes = getFakes(fakeCollection);
-        var i = 0;
-        while (i < fakes.length) {
-          fakes.splice(i, 1);
-        }
-    }
-
-    var collection = {
-        verify: function resolve() {
-            each(this, "verify");
-        },
-
-        restore: function restore() {
-            each(this, "restore");
-            compact(this);
-        },
-
-        verifyAndRestore: function verifyAndRestore() {
-            var exception;
-
-            try {
-                this.verify();
-            } catch (e) {
-                exception = e;
-            }
-
-            this.restore();
-
-            if (exception) {
-                throw exception;
-            }
-        },
-
-        add: function add(fake) {
-            push.call(getFakes(this), fake);
-            return fake;
-        },
-
-        spy: function spy() {
-            return this.add(sinon.spy.apply(sinon, arguments));
-        },
-
-        stub: function stub(object, property, value) {
-            if (property) {
-                var original = object[property];
-
-                if (typeof original != "function") {
-                    if (!hasOwnProperty.call(object, property)) {
-                        throw new TypeError("Cannot stub non-existent own property " + property);
-                    }
-
-                    object[property] = value;
-
-                    return this.add({
-                        restore: function () {
-                            object[property] = original;
-                        }
-                    });
-                }
-            }
-            if (!property && !!object && typeof object == "object") {
-                var stubbedObj = sinon.stub.apply(sinon, arguments);
-
-                for (var prop in stubbedObj) {
-                    if (typeof stubbedObj[prop] === "function") {
-                        this.add(stubbedObj[prop]);
-                    }
-                }
-
-                return stubbedObj;
-            }
-
-            return this.add(sinon.stub.apply(sinon, arguments));
-        },
-
-        mock: function mock() {
-            return this.add(sinon.mock.apply(sinon, arguments));
-        },
-
-        inject: function inject(obj) {
-            var col = this;
-
-            obj.spy = function () {
-                return col.spy.apply(col, arguments);
-            };
-
-            obj.stub = function () {
-                return col.stub.apply(col, arguments);
-            };
-
-            obj.mock = function () {
-                return col.mock.apply(col, arguments);
-            };
-
-            return obj;
-        }
-    };
-
-    if (commonJSModule) {
-        module.exports = collection;
-    } else {
-        sinon.collection = collection;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
-/*global module, require, window*/
-/**
- * Fake timer API
- * setTimeout
- * setInterval
- * clearTimeout
- * clearInterval
- * tick
- * reset
- * Date
- *
- * Inspired by jsUnitMockTimeOut from JsUnit
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-if (typeof sinon == "undefined") {
-    var sinon = {};
-}
-
-(function (global) {
-    var id = 1;
-
-    function addTimer(args, recurring) {
-        if (args.length === 0) {
-            throw new Error("Function requires at least 1 parameter");
-        }
-
-        if (typeof args[0] === "undefined") {
-            throw new Error("Callback must be provided to timer calls");
-        }
-
-        var toId = id++;
-        var delay = args[1] || 0;
-
-        if (!this.timeouts) {
-            this.timeouts = {};
-        }
-
-        this.timeouts[toId] = {
-            id: toId,
-            func: args[0],
-            callAt: this.now + delay,
-            invokeArgs: Array.prototype.slice.call(args, 2)
-        };
-
-        if (recurring === true) {
-            this.timeouts[toId].interval = delay;
-        }
-
-        return toId;
-    }
-
-    function parseTime(str) {
-        if (!str) {
-            return 0;
-        }
-
-        var strings = str.split(":");
-        var l = strings.length, i = l;
-        var ms = 0, parsed;
-
-        if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
-            throw new Error("tick only understands numbers and 'h:m:s'");
-        }
-
-        while (i--) {
-            parsed = parseInt(strings[i], 10);
-
-            if (parsed >= 60) {
-                throw new Error("Invalid time " + str);
-            }
-
-            ms += parsed * Math.pow(60, (l - i - 1));
-        }
-
-        return ms * 1000;
-    }
-
-    function createObject(object) {
-        var newObject;
-
-        if (Object.create) {
-            newObject = Object.create(object);
-        } else {
-            var F = function () {};
-            F.prototype = object;
-            newObject = new F();
-        }
-
-        newObject.Date.clock = newObject;
-        return newObject;
-    }
-
-    sinon.clock = {
-        now: 0,
-
-        create: function create(now) {
-            var clock = createObject(this);
-
-            if (typeof now == "number") {
-                clock.now = now;
-            }
-
-            if (!!now && typeof now == "object") {
-                throw new TypeError("now should be milliseconds since UNIX epoch");
-            }
-
-            return clock;
-        },
-
-        setTimeout: function setTimeout(callback, timeout) {
-            return addTimer.call(this, arguments, false);
-        },
-
-        clearTimeout: function clearTimeout(timerId) {
-            if (!this.timeouts) {
-                this.timeouts = [];
-            }
-
-            if (timerId in this.timeouts) {
-                delete this.timeouts[timerId];
-            }
-        },
-
-        setInterval: function setInterval(callback, timeout) {
-            return addTimer.call(this, arguments, true);
-        },
-
-        clearInterval: function clearInterval(timerId) {
-            this.clearTimeout(timerId);
-        },
-
-        setImmediate: function setImmediate(callback) {
-            var passThruArgs = Array.prototype.slice.call(arguments, 1);
-
-            return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
-        },
-
-        clearImmediate: function clearImmediate(timerId) {
-            this.clearTimeout(timerId);
-        },
-
-        tick: function tick(ms) {
-            ms = typeof ms == "number" ? ms : parseTime(ms);
-            var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
-            var timer = this.firstTimerInRange(tickFrom, tickTo);
-
-            var firstException;
-            while (timer && tickFrom <= tickTo) {
-                if (this.timeouts[timer.id]) {
-                    tickFrom = this.now = timer.callAt;
-                    try {
-                      this.callTimer(timer);
-                    } catch (e) {
-                      firstException = firstException || e;
-                    }
-                }
-
-                timer = this.firstTimerInRange(previous, tickTo);
-                previous = tickFrom;
-            }
-
-            this.now = tickTo;
-
-            if (firstException) {
-              throw firstException;
-            }
-
-            return this.now;
-        },
-
-        firstTimerInRange: function (from, to) {
-            var timer, smallest = null, originalTimer;
-
-            for (var id in this.timeouts) {
-                if (this.timeouts.hasOwnProperty(id)) {
-                    if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
-                        continue;
-                    }
-
-                    if (smallest === null || this.timeouts[id].callAt < smallest) {
-                        originalTimer = this.timeouts[id];
-                        smallest = this.timeouts[id].callAt;
-
-                        timer = {
-                            func: this.timeouts[id].func,
-                            callAt: this.timeouts[id].callAt,
-                            interval: this.timeouts[id].interval,
-                            id: this.timeouts[id].id,
-                            invokeArgs: this.timeouts[id].invokeArgs
-                        };
-                    }
-                }
-            }
-
-            return timer || null;
-        },
-
-        callTimer: function (timer) {
-            if (typeof timer.interval == "number") {
-                this.timeouts[timer.id].callAt += timer.interval;
-            } else {
-                delete this.timeouts[timer.id];
-            }
-
-            try {
-                if (typeof timer.func == "function") {
-                    timer.func.apply(null, timer.invokeArgs);
-                } else {
-                    eval(timer.func);
-                }
-            } catch (e) {
-              var exception = e;
-            }
-
-            if (!this.timeouts[timer.id]) {
-                if (exception) {
-                  throw exception;
-                }
-                return;
-            }
-
-            if (exception) {
-              throw exception;
-            }
-        },
-
-        reset: function reset() {
-            this.timeouts = {};
-        },
-
-        Date: (function () {
-            var NativeDate = Date;
-
-            function ClockDate(year, month, date, hour, minute, second, ms) {
-                // Defensive and verbose to avoid potential harm in passing
-                // explicit undefined when user does not pass argument
-                switch (arguments.length) {
-                case 0:
-                    return new NativeDate(ClockDate.clock.now);
-                case 1:
-                    return new NativeDate(year);
-                case 2:
-                    return new NativeDate(year, month);
-                case 3:
-                    return new NativeDate(year, month, date);
-                case 4:
-                    return new NativeDate(year, month, date, hour);
-                case 5:
-                    return new NativeDate(year, month, date, hour, minute);
-                case 6:
-                    return new NativeDate(year, month, date, hour, minute, second);
-                default:
-                    return new NativeDate(year, month, date, hour, minute, second, ms);
-                }
-            }
-
-            return mirrorDateProperties(ClockDate, NativeDate);
-        }())
-    };
-
-    function mirrorDateProperties(target, source) {
-        if (source.now) {
-            target.now = function now() {
-                return target.clock.now;
-            };
-        } else {
-            delete target.now;
-        }
-
-        if (source.toSource) {
-            target.toSource = function toSource() {
-                return source.toSource();
-            };
-        } else {
-            delete target.toSource;
-        }
-
-        target.toString = function toString() {
-            return source.toString();
-        };
-
-        target.prototype = source.prototype;
-        target.parse = source.parse;
-        target.UTC = source.UTC;
-        target.prototype.toUTCString = source.prototype.toUTCString;
-
-        for (var prop in source) {
-            if (source.hasOwnProperty(prop)) {
-                target[prop] = source[prop];
-            }
-        }
-
-        return target;
-    }
-
-    var methods = ["Date", "setTimeout", "setInterval",
-                   "clearTimeout", "clearInterval"];
-
-    if (typeof global.setImmediate !== "undefined") {
-        methods.push("setImmediate");
-    }
-
-    if (typeof global.clearImmediate !== "undefined") {
-        methods.push("clearImmediate");
-    }
-
-    function restore() {
-        var method;
-
-        for (var i = 0, l = this.methods.length; i < l; i++) {
-            method = this.methods[i];
-
-            if (global[method].hadOwnProperty) {
-                global[method] = this["_" + method];
-            } else {
-                try {
-                    delete global[method];
-                } catch (e) {}
-            }
-        }
-
-        // Prevent multiple executions which will completely remove these props
-        this.methods = [];
-    }
-
-    function stubGlobal(method, clock) {
-        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
-        clock["_" + method] = global[method];
-
-        if (method == "Date") {
-            var date = mirrorDateProperties(clock[method], global[method]);
-            global[method] = date;
-        } else {
-            global[method] = function () {
-                return clock[method].apply(clock, arguments);
-            };
-
-            for (var prop in clock[method]) {
-                if (clock[method].hasOwnProperty(prop)) {
-                    global[method][prop] = clock[method][prop];
-                }
-            }
-        }
-
-        global[method].clock = clock;
-    }
-
-    sinon.useFakeTimers = function useFakeTimers(now) {
-        var clock = sinon.clock.create(now);
-        clock.restore = restore;
-        clock.methods = Array.prototype.slice.call(arguments,
-                                                   typeof now == "number" ? 1 : 0);
-
-        if (clock.methods.length === 0) {
-            clock.methods = methods;
-        }
-
-        for (var i = 0, l = clock.methods.length; i < l; i++) {
-            stubGlobal(clock.methods[i], clock);
-        }
-
-        return clock;
-    };
-}(typeof global != "undefined" && typeof global !== "function" ? global : this));
-
-sinon.timers = {
-    setTimeout: setTimeout,
-    clearTimeout: clearTimeout,
-    setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
-    clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
-    setInterval: setInterval,
-    clearInterval: clearInterval,
-    Date: Date
-};
-
-if (typeof module !== 'undefined' && module.exports) {
-    module.exports = sinon;
-}
-
-/*jslint eqeqeq: false, onevar: false*/
-/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
-/**
- * Minimal Event interface implementation
- *
- * Original implementation by Sven Fuchs: https://gist.github.com/995028
- * Modifications and tests by Christian Johansen.
- *
- * @author Sven Fuchs (svenfuchs@artweb-design.de)
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2011 Sven Fuchs, Christian Johansen
- */
-
-if (typeof sinon == "undefined") {
-    this.sinon = {};
-}
-
-(function () {
-    var push = [].push;
-
-    sinon.Event = function Event(type, bubbles, cancelable, target) {
-        this.initEvent(type, bubbles, cancelable, target);
-    };
-
-    sinon.Event.prototype = {
-        initEvent: function(type, bubbles, cancelable, target) {
-            this.type = type;
-            this.bubbles = bubbles;
-            this.cancelable = cancelable;
-            this.target = target;
-        },
-
-        stopPropagation: function () {},
-
-        preventDefault: function () {
-            this.defaultPrevented = true;
-        }
-    };
-
-    sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
-        this.initEvent(type, false, false, target);
-        this.loaded = progressEventRaw.loaded || null;
-        this.total = progressEventRaw.total || null;
-    };
-
-    sinon.ProgressEvent.prototype = new sinon.Event();
-
-    sinon.ProgressEvent.prototype.constructor =  sinon.ProgressEvent;
-
-    sinon.CustomEvent = function CustomEvent(type, customData, target) {
-        this.initEvent(type, false, false, target);
-        this.detail = customData.detail || null;
-    };
-
-    sinon.CustomEvent.prototype = new sinon.Event();
-
-    sinon.CustomEvent.prototype.constructor =  sinon.CustomEvent;
-
-    sinon.EventTarget = {
-        addEventListener: function addEventListener(event, listener) {
-            this.eventListeners = this.eventListeners || {};
-            this.eventListeners[event] = this.eventListeners[event] || [];
-            push.call(this.eventListeners[event], listener);
-        },
-
-        removeEventListener: function removeEventListener(event, listener) {
-            var listeners = this.eventListeners && this.eventListeners[event] || [];
-
-            for (var i = 0, l = listeners.length; i < l; ++i) {
-                if (listeners[i] == listener) {
-                    return listeners.splice(i, 1);
-                }
-            }
-        },
-
-        dispatchEvent: function dispatchEvent(event) {
-            var type = event.type;
-            var listeners = this.eventListeners && this.eventListeners[type] || [];
-
-            for (var i = 0; i < listeners.length; i++) {
-                if (typeof listeners[i] == "function") {
-                    listeners[i].call(this, event);
-                } else {
-                    listeners[i].handleEvent(event);
-                }
-            }
-
-            return !!event.defaultPrevented;
-        }
-    };
-}());
-
-/**
- * @depend ../../sinon.js
- * @depend event.js
- */
-/*jslint eqeqeq: false, onevar: false*/
-/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
-/**
- * Fake XMLHttpRequest object
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-// wrapper for global
-(function(global) {
-    if (typeof sinon === "undefined") {
-        global.sinon = {};
-    }
-
-    var supportsProgress = typeof ProgressEvent !== "undefined";
-    var supportsCustomEvent = typeof CustomEvent !== "undefined";
-    sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
-    var xhr = sinon.xhr;
-    xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
-    xhr.GlobalActiveXObject = global.ActiveXObject;
-    xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
-    xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
-    xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
-                                     ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
-    xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
-
-    /*jsl:ignore*/
-    var unsafeHeaders = {
-        "Accept-Charset": true,
-        "Accept-Encoding": true,
-        "Connection": true,
-        "Content-Length": true,
-        "Cookie": true,
-        "Cookie2": true,
-        "Content-Transfer-Encoding": true,
-        "Date": true,
-        "Expect": true,
-        "Host": true,
-        "Keep-Alive": true,
-        "Referer": true,
-        "TE": true,
-        "Trailer": true,
-        "Transfer-Encoding": true,
-        "Upgrade": true,
-        "User-Agent": true,
-        "Via": true
-    };
-    /*jsl:end*/
-
-    function FakeXMLHttpRequest() {
-        this.readyState = FakeXMLHttpRequest.UNSENT;
-        this.requestHeaders = {};
-        this.requestBody = null;
-        this.status = 0;
-        this.statusText = "";
-        this.upload = new UploadProgress();
-        if (sinon.xhr.supportsCORS) {
-            this.withCredentials = false;
-        }
-
-
-        var xhr = this;
-        var events = ["loadstart", "load", "abort", "loadend"];
-
-        function addEventListener(eventName) {
-            xhr.addEventListener(eventName, function (event) {
-                var listener = xhr["on" + eventName];
-
-                if (listener && typeof listener == "function") {
-                    listener.call(this, event);
-                }
-            });
-        }
-
-        for (var i = events.length - 1; i >= 0; i--) {
-            addEventListener(events[i]);
-        }
-
-        if (typeof FakeXMLHttpRequest.onCreate == "function") {
-            FakeXMLHttpRequest.onCreate(this);
-        }
-    }
-
-    // An upload object is created for each
-    // FakeXMLHttpRequest and allows upload
-    // events to be simulated using uploadProgress
-    // and uploadError.
-    function UploadProgress() {
-        this.eventListeners = {
-            "progress": [],
-            "load": [],
-            "abort": [],
-            "error": []
-        }
-    }
-
-    UploadProgress.prototype.addEventListener = function(event, listener) {
-        this.eventListeners[event].push(listener);
-    };
-
-    UploadProgress.prototype.removeEventListener = function(event, listener) {
-        var listeners = this.eventListeners[event] || [];
-
-        for (var i = 0, l = listeners.length; i < l; ++i) {
-            if (listeners[i] == listener) {
-                return listeners.splice(i, 1);
-            }
-        }
-    };
-
-    UploadProgress.prototype.dispatchEvent = function(event) {
-        var listeners = this.eventListeners[event.type] || [];
-
-        for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
-            listener(event);
-        }
-    };
-
-    function verifyState(xhr) {
-        if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
-            throw new Error("INVALID_STATE_ERR");
-        }
-
-        if (xhr.sendFlag) {
-            throw new Error("INVALID_STATE_ERR");
-        }
-    }
-
-    // filtering to enable a white-list version of Sinon FakeXhr,
-    // where whitelisted requests are passed through to real XHR
-    function each(collection, callback) {
-        if (!collection) return;
-        for (var i = 0, l = collection.length; i < l; i += 1) {
-            callback(collection[i]);
-        }
-    }
-    function some(collection, callback) {
-        for (var index = 0; index < collection.length; index++) {
-            if(callback(collection[index]) === true) return true;
-        }
-        return false;
-    }
-    // largest arity in XHR is 5 - XHR#open
-    var apply = function(obj,method,args) {
-        switch(args.length) {
-        case 0: return obj[method]();
-        case 1: return obj[method](args[0]);
-        case 2: return obj[method](args[0],args[1]);
-        case 3: return obj[method](args[0],args[1],args[2]);
-        case 4: return obj[method](args[0],args[1],args[2],args[3]);
-        case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
-        }
-    };
-
-    FakeXMLHttpRequest.filters = [];
-    FakeXMLHttpRequest.addFilter = function(fn) {
-        this.filters.push(fn)
-    };
-    var IE6Re = /MSIE 6/;
-    FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
-        var xhr = new sinon.xhr.workingXHR();
-        each(["open","setRequestHeader","send","abort","getResponseHeader",
-              "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
-             function(method) {
-                 fakeXhr[method] = function() {
-                   return apply(xhr,method,arguments);
-                 };
-             });
-
-        var copyAttrs = function(args) {
-            each(args, function(attr) {
-              try {
-                fakeXhr[attr] = xhr[attr]
-              } catch(e) {
-                if(!IE6Re.test(navigator.userAgent)) throw e;
-              }
-            });
-        };
-
-        var stateChange = function() {
-            fakeXhr.readyState = xhr.readyState;
-            if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
-                copyAttrs(["status","statusText"]);
-            }
-            if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
-                copyAttrs(["responseText"]);
-            }
-            if(xhr.readyState === FakeXMLHttpRequest.DONE) {
-                copyAttrs(["responseXML"]);
-            }
-            if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
-        };
-        if(xhr.addEventListener) {
-          for(var event in fakeXhr.eventListeners) {
-              if(fakeXhr.eventListeners.hasOwnProperty(event)) {
-                  each(fakeXhr.eventListeners[event],function(handler) {
-                      xhr.addEventListener(event, handler);
-                  });
-              }
-          }
-          xhr.addEventListener("readystatechange",stateChange);
-        } else {
-          xhr.onreadystatechange = stateChange;
-        }
-        apply(xhr,"open",xhrArgs);
-    };
-    FakeXMLHttpRequest.useFilters = false;
-
-    function verifyRequestOpened(xhr) {
-        if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
-            throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
-        }
-    }
-
-    function verifyRequestSent(xhr) {
-        if (xhr.readyState == FakeXMLHttpRequest.DONE) {
-            throw new Error("Request done");
-        }
-    }
-
-    function verifyHeadersReceived(xhr) {
-        if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
-            throw new Error("No headers received");
-        }
-    }
-
-    function verifyResponseBodyType(body) {
-        if (typeof body != "string") {
-            var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
-                                 body + ", which is not a string.");
-            error.name = "InvalidBodyException";
-            throw error;
-        }
-    }
-
-    sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
-        async: true,
-
-        open: function open(method, url, async, username, password) {
-            this.method = method;
-            this.url = url;
-            this.async = typeof async == "boolean" ? async : true;
-            this.username = username;
-            this.password = password;
-            this.responseText = null;
-            this.responseXML = null;
-            this.requestHeaders = {};
-            this.sendFlag = false;
-            if(sinon.FakeXMLHttpRequest.useFilters === true) {
-                var xhrArgs = arguments;
-                var defake = some(FakeXMLHttpRequest.filters,function(filter) {
-                    return filter.apply(this,xhrArgs)
-                });
-                if (defake) {
-                  return sinon.FakeXMLHttpRequest.defake(this,arguments);
-                }
-            }
-            this.readyStateChange(FakeXMLHttpRequest.OPENED);
-        },
-
-        readyStateChange: function readyStateChange(state) {
-            this.readyState = state;
-
-            if (typeof this.onreadystatechange == "function") {
-                try {
-                    this.onreadystatechange();
-                } catch (e) {
-                    sinon.logError("Fake XHR onreadystatechange handler", e);
-                }
-            }
-
-            this.dispatchEvent(new sinon.Event("readystatechange"));
-
-            switch (this.readyState) {
-                case FakeXMLHttpRequest.DONE:
-                    this.dispatchEvent(new sinon.Event("load", false, false, this));
-                    this.dispatchEvent(new sinon.Event("loadend", false, false, this));
-                    this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
-                    if (supportsProgress) {
-                        this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
-                    }
-                    break;
-            }
-        },
-
-        setRequestHeader: function setRequestHeader(header, value) {
-            verifyState(this);
-
-            if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
-                throw new Error("Refused to set unsafe header \"" + header + "\"");
-            }
-
-            if (this.requestHeaders[header]) {
-                this.requestHeaders[header] += "," + value;
-            } else {
-                this.requestHeaders[header] = value;
-            }
-        },
-
-        // Helps testing
-        setResponseHeaders: function setResponseHeaders(headers) {
-            verifyRequestOpened(this);
-            this.responseHeaders = {};
-
-            for (var header in headers) {
-                if (headers.hasOwnProperty(header)) {
-                    this.responseHeaders[header] = headers[header];
-                }
-            }
-
-            if (this.async) {
-                this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
-            } else {
-                this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
-            }
-        },
-
-        // Currently treats ALL data as a DOMString (i.e. no Document)
-        send: function send(data) {
-            verifyState(this);
-
-            if (!/^(get|head)$/i.test(this.method)) {
-                if (this.requestHeaders["Content-Type"]) {
-                    var value = this.requestHeaders["Content-Type"].split(";");
-                    this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
-                } else {
-                    this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
-                }
-
-                this.requestBody = data;
-            }
-
-            this.errorFlag = false;
-            this.sendFlag = this.async;
-            this.readyStateChange(FakeXMLHttpRequest.OPENED);
-
-            if (typeof this.onSend == "function") {
-                this.onSend(this);
-            }
-
-            this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
-        },
-
-        abort: function abort() {
-            this.aborted = true;
-            this.responseText = null;
-            this.errorFlag = true;
-            this.requestHeaders = {};
-
-            if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
-                this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
-                this.sendFlag = false;
-            }
-
-            this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
-
-            this.dispatchEvent(new sinon.Event("abort", false, false, this));
-
-            this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
-
-            if (typeof this.onerror === "function") {
-                this.onerror();
-            }
-        },
-
-        getResponseHeader: function getResponseHeader(header) {
-            if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
-                return null;
-            }
-
-            if (/^Set-Cookie2?$/i.test(header)) {
-                return null;
-            }
-
-            header = header.toLowerCase();
-
-            for (var h in this.responseHeaders) {
-                if (h.toLowerCase() == header) {
-                    return this.responseHeaders[h];
-                }
-            }
-
-            return null;
-        },
-
-        getAllResponseHeaders: function getAllResponseHeaders() {
-            if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
-                return "";
-            }
-
-            var headers = "";
-
-            for (var header in this.responseHeaders) {
-                if (this.responseHeaders.hasOwnProperty(header) &&
-                    !/^Set-Cookie2?$/i.test(header)) {
-                    headers += header + ": " + this.responseHeaders[header] + "\r\n";
-                }
-            }
-
-            return headers;
-        },
-
-        setResponseBody: function setResponseBody(body) {
-            verifyRequestSent(this);
-            verifyHeadersReceived(this);
-            verifyResponseBodyType(body);
-
-            var chunkSize = this.chunkSize || 10;
-            var index = 0;
-            this.responseText = "";
-
-            do {
-                if (this.async) {
-                    this.readyStateChange(FakeXMLHttpRequest.LOADING);
-                }
-
-                this.responseText += body.substring(index, index + chunkSize);
-                index += chunkSize;
-            } while (index < body.length);
-
-            var type = this.getResponseHeader("Content-Type");
-
-            if (this.responseText &&
-                (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
-                try {
-                    this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
-                } catch (e) {
-                    // Unable to parse XML - no biggie
-                }
-            }
-
-            if (this.async) {
-                this.readyStateChange(FakeXMLHttpRequest.DONE);
-            } else {
-                this.readyState = FakeXMLHttpRequest.DONE;
-            }
-        },
-
-        respond: function respond(status, headers, body) {
-            this.status = typeof status == "number" ? status : 200;
-            this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
-            this.setResponseHeaders(headers || {});
-            this.setResponseBody(body || "");
-        },
-
-        uploadProgress: function uploadProgress(progressEventRaw) {
-            if (supportsProgress) {
-                this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
-            }
-        },
-
-        uploadError: function uploadError(error) {
-            if (supportsCustomEvent) {
-                this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
-            }
-        }
-    });
-
-    sinon.extend(FakeXMLHttpRequest, {
-        UNSENT: 0,
-        OPENED: 1,
-        HEADERS_RECEIVED: 2,
-        LOADING: 3,
-        DONE: 4
-    });
-
-    // Borrowed from JSpec
-    FakeXMLHttpRequest.parseXML = function parseXML(text) {
-        var xmlDoc;
-
-        if (typeof DOMParser != "undefined") {
-            var parser = new DOMParser();
-            xmlDoc = parser.parseFromString(text, "text/xml");
-        } else {
-            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
-            xmlDoc.async = "false";
-            xmlDoc.loadXML(text);
-        }
-
-        return xmlDoc;
-    };
-
-    FakeXMLHttpRequest.statusCodes = {
-        100: "Continue",
-        101: "Switching Protocols",
-        200: "OK",
-        201: "Created",
-        202: "Accepted",
-        203: "Non-Authoritative Information",
-        204: "No Content",
-        205: "Reset Content",
-        206: "Partial Content",
-        300: "Multiple Choice",
-        301: "Moved Permanently",
-        302: "Found",
-        303: "See Other",
-        304: "Not Modified",
-        305: "Use Proxy",
-        307: "Temporary Redirect",
-        400: "Bad Request",
-        401: "Unauthorized",
-        402: "Payment Required",
-        403: "Forbidden",
-        404: "Not Found",
-        405: "Method Not Allowed",
-        406: "Not Acceptable",
-        407: "Proxy Authentication Required",
-        408: "Request Timeout",
-        409: "Conflict",
-        410: "Gone",
-        411: "Length Required",
-        412: "Precondition Failed",
-        413: "Request Entity Too Large",
-        414: "Request-URI Too Long",
-        415: "Unsupported Media Type",
-        416: "Requested Range Not Satisfiable",
-        417: "Expectation Failed",
-        422: "Unprocessable Entity",
-        500: "Internal Server Error",
-        501: "Not Implemented",
-        502: "Bad Gateway",
-        503: "Service Unavailable",
-        504: "Gateway Timeout",
-        505: "HTTP Version Not Supported"
-    };
-
-    sinon.useFakeXMLHttpRequest = function () {
-        sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
-            if (xhr.supportsXHR) {
-                global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
-            }
-
-            if (xhr.supportsActiveX) {
-                global.ActiveXObject = xhr.GlobalActiveXObject;
-            }
-
-            delete sinon.FakeXMLHttpRequest.restore;
-
-            if (keepOnCreate !== true) {
-                delete sinon.FakeXMLHttpRequest.onCreate;
-            }
-        };
-        if (xhr.supportsXHR) {
-            global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
-        }
-
-        if (xhr.supportsActiveX) {
-            global.ActiveXObject = function ActiveXObject(objId) {
-                if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
-
-                    return new sinon.FakeXMLHttpRequest();
-                }
-
-                return new xhr.GlobalActiveXObject(objId);
-            };
-        }
-
-        return sinon.FakeXMLHttpRequest;
-    };
-
-    sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
-
-})(typeof global === "object" ? global : this);
-
-if (typeof module !== 'undefined' && module.exports) {
-    module.exports = sinon;
-}
-
-/**
- * @depend fake_xml_http_request.js
- */
-/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
-/*global module, require, window*/
-/**
- * The Sinon "server" mimics a web server that receives requests from
- * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
- * both synchronously and asynchronously. To respond synchronuously, canned
- * answers have to be provided upfront.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-if (typeof sinon == "undefined") {
-    var sinon = {};
-}
-
-sinon.fakeServer = (function () {
-    var push = [].push;
-    function F() {}
-
-    function create(proto) {
-        F.prototype = proto;
-        return new F();
-    }
-
-    function responseArray(handler) {
-        var response = handler;
-
-        if (Object.prototype.toString.call(handler) != "[object Array]") {
-            response = [200, {}, handler];
-        }
-
-        if (typeof response[2] != "string") {
-            throw new TypeError("Fake server response body should be string, but was " +
-                                typeof response[2]);
-        }
-
-        return response;
-    }
-
-    var wloc = typeof window !== "undefined" ? window.location : {};
-    var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
-
-    function matchOne(response, reqMethod, reqUrl) {
-        var rmeth = response.method;
-        var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
-        var url = response.url;
-        var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
-
-        return matchMethod && matchUrl;
-    }
-
-    function match(response, request) {
-        var requestUrl = request.url;
-
-        if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
-            requestUrl = requestUrl.replace(rCurrLoc, "");
-        }
-
-        if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
-            if (typeof response.response == "function") {
-                var ru = response.url;
-                var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
-                return response.response.apply(response, args);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    function log(response, request) {
-        var str;
-
-        str =  "Request:\n"  + sinon.format(request)  + "\n\n";
-        str += "Response:\n" + sinon.format(response) + "\n\n";
-
-        sinon.log(str);
-    }
-
-    return {
-        create: function () {
-            var server = create(this);
-            this.xhr = sinon.useFakeXMLHttpRequest();
-            server.requests = [];
-
-            this.xhr.onCreate = function (xhrObj) {
-                server.addRequest(xhrObj);
-            };
-
-            return server;
-        },
-
-        addRequest: function addRequest(xhrObj) {
-            var server = this;
-            push.call(this.requests, xhrObj);
-
-            xhrObj.onSend = function () {
-                server.handleRequest(this);
-
-                if (server.autoRespond && !server.responding) {
-                    setTimeout(function () {
-                        server.responding = false;
-                        server.respond();
-                    }, server.autoRespondAfter || 10);
-
-                    server.responding = true;
-                }
-            };
-        },
-
-        getHTTPMethod: function getHTTPMethod(request) {
-            if (this.fakeHTTPMethods && /post/i.test(request.method)) {
-                var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
-                return !!matches ? matches[1] : request.method;
-            }
-
-            return request.method;
-        },
-
-        handleRequest: function handleRequest(xhr) {
-            if (xhr.async) {
-                if (!this.queue) {
-                    this.queue = [];
-                }
-
-                push.call(this.queue, xhr);
-            } else {
-                this.processRequest(xhr);
-            }
-        },
-
-        respondWith: function respondWith(method, url, body) {
-            if (arguments.length == 1 && typeof method != "function") {
-                this.response = responseArray(method);
-                return;
-            }
-
-            if (!this.responses) { this.responses = []; }
-
-            if (arguments.length == 1) {
-                body = method;
-                url = method = null;
-            }
-
-            if (arguments.length == 2) {
-                body = url;
-                url = method;
-                method = null;
-            }
-
-            push.call(this.responses, {
-                method: method,
-                url: url,
-                response: typeof body == "function" ? body : responseArray(body)
-            });
-        },
-
-        respond: function respond() {
-            if (arguments.length > 0) this.respondWith.apply(this, arguments);
-            var queue = this.queue || [];
-            var requests = queue.splice(0);
-            var request;
-
-            while(request = requests.shift()) {
-                this.processRequest(request);
-            }
-        },
-
-        processRequest: function processRequest(request) {
-            try {
-                if (request.aborted) {
-                    return;
-                }
-
-                var response = this.response || [404, {}, ""];
-
-                if (this.responses) {
-                    for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
-                        if (match.call(this, this.responses[i], request)) {
-                            response = this.responses[i].response;
-                            break;
-                        }
-                    }
-                }
-
-                if (request.readyState != 4) {
-                    log(response, request);
-
-                    request.respond(response[0], response[1], response[2]);
-                }
-            } catch (e) {
-                sinon.logError("Fake server request processing", e);
-            }
-        },
-
-        restore: function restore() {
-            return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
-        }
-    };
-}());
-
-if (typeof module !== 'undefined' && module.exports) {
-    module.exports = sinon;
-}
-
-/**
- * @depend fake_server.js
- * @depend fake_timers.js
- */
-/*jslint browser: true, eqeqeq: false, onevar: false*/
-/*global sinon*/
-/**
- * Add-on for sinon.fakeServer that automatically handles a fake timer along with
- * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
- * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
- * it polls the object for completion with setInterval. Dispite the direct
- * motivation, there is nothing jQuery-specific in this file, so it can be used
- * in any environment where the ajax implementation depends on setInterval or
- * setTimeout.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function () {
-    function Server() {}
-    Server.prototype = sinon.fakeServer;
-
-    sinon.fakeServerWithClock = new Server();
-
-    sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
-        if (xhr.async) {
-            if (typeof setTimeout.clock == "object") {
-                this.clock = setTimeout.clock;
-            } else {
-                this.clock = sinon.useFakeTimers();
-                this.resetClock = true;
-            }
-
-            if (!this.longestTimeout) {
-                var clockSetTimeout = this.clock.setTimeout;
-                var clockSetInterval = this.clock.setInterval;
-                var server = this;
-
-                this.clock.setTimeout = function (fn, timeout) {
-                    server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
-
-                    return clockSetTimeout.apply(this, arguments);
-                };
-
-                this.clock.setInterval = function (fn, timeout) {
-                    server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
-
-                    return clockSetInterval.apply(this, arguments);
-                };
-            }
-        }
-
-        return sinon.fakeServer.addRequest.call(this, xhr);
-    };
-
-    sinon.fakeServerWithClock.respond = function respond() {
-        var returnVal = sinon.fakeServer.respond.apply(this, arguments);
-
-        if (this.clock) {
-            this.clock.tick(this.longestTimeout || 0);
-            this.longestTimeout = 0;
-
-            if (this.resetClock) {
-                this.clock.restore();
-                this.resetClock = false;
-            }
-        }
-
-        return returnVal;
-    };
-
-    sinon.fakeServerWithClock.restore = function restore() {
-        if (this.clock) {
-            this.clock.restore();
-        }
-
-        return sinon.fakeServer.restore.apply(this, arguments);
-    };
-}());
-
-/**
- * @depend ../sinon.js
- * @depend collection.js
- * @depend util/fake_timers.js
- * @depend util/fake_server_with_clock.js
- */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global require, module*/
-/**
- * Manages fake collections as well as fake utilities such as Sinon's
- * timers and fake XHR implementation in one convenient object.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-if (typeof module !== 'undefined' && module.exports) {
-    var sinon = require("../sinon");
-    sinon.extend(sinon, require("./util/fake_timers"));
-}
-
-(function () {
-    var push = [].push;
-
-    function exposeValue(sandbox, config, key, value) {
-        if (!value) {
-            return;
-        }
-
-        if (config.injectInto && !(key in config.injectInto)) {
-            config.injectInto[key] = value;
-            sandbox.injectedKeys.push(key);
-        } else {
-            push.call(sandbox.args, value);
-        }
-    }
-
-    function prepareSandboxFromConfig(config) {
-        var sandbox = sinon.create(sinon.sandbox);
-
-        if (config.useFakeServer) {
-            if (typeof config.useFakeServer == "object") {
-                sandbox.serverPrototype = config.useFakeServer;
-            }
-
-            sandbox.useFakeServer();
-        }
-
-        if (config.useFakeTimers) {
-            if (typeof config.useFakeTimers == "object") {
-                sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
-            } else {
-                sandbox.useFakeTimers();
-            }
-        }
-
-        return sandbox;
-    }
-
-    sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
-        useFakeTimers: function useFakeTimers() {
-            this.clock = sinon.useFakeTimers.apply(sinon, arguments);
-
-            return this.add(this.clock);
-        },
-
-        serverPrototype: sinon.fakeServer,
-
-        useFakeServer: function useFakeServer() {
-            var proto = this.serverPrototype || sinon.fakeServer;
-
-            if (!proto || !proto.create) {
-                return null;
-            }
-
-            this.server = proto.create();
-            return this.add(this.server);
-        },
-
-        inject: function (obj) {
-            sinon.collection.inject.call(this, obj);
-
-            if (this.clock) {
-                obj.clock = this.clock;
-            }
-
-            if (this.server) {
-                obj.server = this.server;
-                obj.requests = this.server.requests;
-            }
-
-            return obj;
-        },
-
-        restore: function () {
-            sinon.collection.restore.apply(this, arguments);
-            this.restoreContext();
-        },
-
-        restoreContext: function () {
-            if (this.injectedKeys) {
-                for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
-                    delete this.injectInto[this.injectedKeys[i]];
-                }
-                this.injectedKeys = [];
-            }
-        },
-
-        create: function (config) {
-            if (!config) {
-                return sinon.create(sinon.sandbox);
-            }
-
-            var sandbox = prepareSandboxFromConfig(config);
-            sandbox.args = sandbox.args || [];
-            sandbox.injectedKeys = [];
-            sandbox.injectInto = config.injectInto;
-            var prop, value, exposed = sandbox.inject({});
-
-            if (config.properties) {
-                for (var i = 0, l = config.properties.length; i < l; i++) {
-                    prop = config.properties[i];
-                    value = exposed[prop] || prop == "sandbox" && sandbox;
-                    exposeValue(sandbox, config, prop, value);
-                }
-            } else {
-                exposeValue(sandbox, config, "sandbox", value);
-            }
-
-            return sandbox;
-        }
-    });
-
-    sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
-
-    if (typeof module !== 'undefined' && module.exports) {
-        module.exports = sinon.sandbox;
-    }
-}());
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- * @depend mock.js
- * @depend sandbox.js
- */
-/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Test function, sandboxes fakes
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    function test(callback) {
-        var type = typeof callback;
-
-        if (type != "function") {
-            throw new TypeError("sinon.test needs to wrap a test function, got " + type);
-        }
-
-        return function () {
-            var config = sinon.getConfig(sinon.config);
-            config.injectInto = config.injectIntoThis && this || config.injectInto;
-            var sandbox = sinon.sandbox.create(config);
-            var exception, result;
-            var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
-
-            try {
-                result = callback.apply(this, args);
-            } catch (e) {
-                exception = e;
-            }
-
-            if (typeof exception !== "undefined") {
-                sandbox.restore();
-                throw exception;
-            }
-            else {
-                sandbox.verifyAndRestore();
-            }
-
-            return result;
-        };
-    }
-
-    test.config = {
-        injectIntoThis: true,
-        injectInto: null,
-        properties: ["spy", "stub", "mock", "clock", "server", "requests"],
-        useFakeTimers: true,
-        useFakeServer: true
-    };
-
-    if (commonJSModule) {
-        module.exports = test;
-    } else {
-        sinon.test = test;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend test.js
- */
-/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
-/*global module, require, sinon*/
-/**
- * Test case, sandboxes all test functions
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
-    var commonJSModule = typeof module !== 'undefined' && module.exports;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon || !Object.prototype.hasOwnProperty) {
-        return;
-    }
-
-    function createTest(property, setUp, tearDown) {
-        return function () {
-            if (setUp) {
-                setUp.apply(this, arguments);
-            }
-
-            var exception, result;
-
-            try {
-                result = property.apply(this, arguments);
-            } catch (e) {
-                exception = e;
-            }
-
-            if (tearDown) {
-                tearDown.apply(this, arguments);
-            }
-
-            if (exception) {
-                throw exception;
-            }
-
-            return result;
-        };
-    }
-
-    function testCase(tests, prefix) {
-        /*jsl:ignore*/
-        if (!tests || typeof tests != "object") {
-            throw new TypeError("sinon.testCase needs an object with test functions");
-        }
-        /*jsl:end*/
-
-        prefix = prefix || "test";
-        var rPrefix = new RegExp("^" + prefix);
-        var methods = {}, testName, property, method;
-        var setUp = tests.setUp;
-        var tearDown = tests.tearDown;
-
-        for (testName in tests) {
-            if (tests.hasOwnProperty(testName)) {
-                property = tests[testName];
-
-                if (/^(setUp|tearDown)$/.test(testName)) {
-                    continue;
-                }
-
-                if (typeof property == "function" && rPrefix.test(testName)) {
-                    method = property;
-
-                    if (setUp || tearDown) {
-                        method = createTest(property, setUp, tearDown);
-                    }
-
-                    methods[testName] = sinon.test(method);
-                } else {
-                    methods[testName] = tests[testName];
-                }
-            }
-        }
-
-        return methods;
-    }
-
-    if (commonJSModule) {
-        module.exports = testCase;
-    } else {
-        sinon.testCase = testCase;
-    }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- */
-/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Assertions matching the test spy retrieval interface.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon, global) {
-    var commonJSModule = typeof module !== "undefined" && module.exports;
-    var slice = Array.prototype.slice;
-    var assert;
-
-    if (!sinon && commonJSModule) {
-        sinon = require("../sinon");
-    }
-
-    if (!sinon) {
-        return;
-    }
-
-    function verifyIsStub() {
-        var method;
-
-        for (var i = 0, l = arguments.length; i < l; ++i) {
-            method = arguments[i];
-
-            if (!method) {
-                assert.fail("fake is not a spy");
-            }
-
-            if (typeof method != "function") {
-                assert.fail(method + " is not a function");
-            }
-
-            if (typeof method.getCall != "function") {
-                assert.fail(method + " is not stubbed");
-            }
-        }
-    }
-
-    function failAssertion(object, msg) {
-        object = object || global;
-        var failMethod = object.fail || assert.fail;
-        failMethod.call(object, msg);
-    }
-
-    function mirrorPropAsAssertion(name, method, message) {
-        if (arguments.length == 2) {
-            message = method;
-            method = name;
-        }
-
-        assert[name] = function (fake) {
-            verifyIsStub(fake);
-
-            var args = slice.call(arguments, 1);
-            var failed = false;
-
-            if (typeof method == "function") {
-                failed = !method(fake);
-            } else {
-                failed = typeof fake[method] == "function" ?
-                    !fake[method].apply(fake, args) : !fake[method];
-            }
-
-            if (failed) {
-                failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
-            } else {
-                assert.pass(name);
-            }
-        };
-    }
-
-    function exposedName(prefix, prop) {
-        return !prefix || /^fail/.test(prop) ? prop :
-            prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
-    }
-
-    assert = {
-        failException: "AssertError",
-
-        fail: function fail(message) {
-            var error = new Error(message);
-            error.name = this.failException || assert.failException;
-
-            throw error;
-        },
-
-        pass: function pass(assertion) {},
-
-        callOrder: function assertCallOrder() {
-            verifyIsStub.apply(null, arguments);
-            var expected = "", actual = "";
-
-            if (!sinon.calledInOrder(arguments)) {
-                try {
-                    expected = [].join.call(arguments, ", ");
-                    var calls = slice.call(arguments);
-                    var i = calls.length;
-                    while (i) {
-                        if (!calls[--i].called) {
-                            calls.splice(i, 1);
-                        }
-                    }
-                    actual = sinon.orderByFirstCall(calls).join(", ");
-                } catch (e) {
-                    // If this fails, we'll just fall back to the blank string
-                }
-
-                failAssertion(this, "expected " + expected + " to be " +
-                              "called in order but were called as " + actual);
-            } else {
-                assert.pass("callOrder");
-            }
-        },
-
-        callCount: function assertCallCount(method, count) {
-            verifyIsStub(method);
-
-            if (method.callCount != count) {
-                var msg = "expected %n to be called " + sinon.timesInWords(count) +
-                    " but was called %c%C";
-                failAssertion(this, method.printf(msg));
-            } else {
-                assert.pass("callCount");
-            }
-        },
-
-        expose: function expose(target, options) {
-            if (!target) {
-                throw new TypeError("target is null or undefined");
-            }
-
-            var o = options || {};
-            var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
-            var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
-
-            for (var method in this) {
-                if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
-                    target[exposedName(prefix, method)] = this[method];
-                }
-            }
-
-            return target;
-        },
-
-        match: function match(actual, expectation) {
-            var matcher = sinon.match(expectation);
-            if (matcher.test(actual)) {
-                assert.pass("match");
-            } else {
-                var formatted = [
-                    "expected value to match",
-                    "    expected = " + sinon.format(expectation),
-                    "    actual = " + sinon.format(actual)
-                ]
-                failAssertion(this, formatted.join("\n"));
-            }
-        }
-    };
-
-    mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
-    mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
-                          "expected %n to not have been called but was called %c%C");
-    mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
-    mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
-    mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
-    mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
-    mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
-    mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
-    mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
-    mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
-    mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
-    mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
-    mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
-    mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
-    mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
-    mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
-    mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
-    mirrorPropAsAssertion("threw", "%n did not throw exception%C");
-    mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
-
-    if (commonJSModule) {
-        module.exports = assert;
-    } else {
-        sinon.assert = assert;
-    }
-}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
-
-return sinon;}.call(typeof window != 'undefined' && window || {}));
diff --git a/resources/lib/sinonjs/sinon-ie-1.10.3.js b/resources/lib/sinonjs/sinon-ie-1.10.3.js
new file mode 100644 (file)
index 0000000..de8c23d
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * Sinon.JS 1.10.3, 2014/07/11
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
+ *
+ * (The BSD License)
+ * 
+ * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ *     * Neither the name of Christian Johansen nor the names of his contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
+/**
+ * Helps IE run the fake timers. By defining global functions, IE allows
+ * them to be overwritten at a later point. If these are not defined like
+ * this, overwriting them will result in anything from an exception to browser
+ * crash.
+ *
+ * If you don't require fake timers to work in IE, don't include this file.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+function setTimeout() {}
+function clearTimeout() {}
+function setImmediate() {}
+function clearImmediate() {}
+function setInterval() {}
+function clearInterval() {}
+function Date() {}
+
+// Reassign the original functions. Now their writable attribute
+// should be true. Hackish, I know, but it works.
+setTimeout = sinon.timers.setTimeout;
+clearTimeout = sinon.timers.clearTimeout;
+setImmediate = sinon.timers.setImmediate;
+clearImmediate = sinon.timers.clearImmediate;
+setInterval = sinon.timers.setInterval;
+clearInterval = sinon.timers.clearInterval;
+Date = sinon.timers.Date;
+
+/*global sinon*/
+/**
+ * Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows
+ * them to be overwritten at a later point. If these are not defined like
+ * this, overwriting them will result in anything from an exception to browser
+ * crash.
+ *
+ * If you don't require fake XHR to work in IE, don't include this file.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+function XMLHttpRequest() {}
+
+// Reassign the original function. Now its writable attribute
+// should be true. Hackish, I know, but it works.
+XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
+/*global sinon*/
+/**
+ * Helps IE run the fake XDomainRequest. By defining global functions, IE allows
+ * them to be overwritten at a later point. If these are not defined like
+ * this, overwriting them will result in anything from an exception to browser
+ * crash.
+ *
+ * If you don't require fake XDR to work in IE, don't include this file.
+ */
+function XDomainRequest() {}
+
+// Reassign the original function. Now its writable attribute
+// should be true. Hackish, I know, but it works.
+XDomainRequest = sinon.xdr.XDomainRequest || undefined;
diff --git a/resources/lib/sinonjs/sinon-ie-1.9.0.js b/resources/lib/sinonjs/sinon-ie-1.9.0.js
deleted file mode 100644 (file)
index c9fbd9d..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Sinon.JS 1.9.0, 2014/03/05
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
- *
- * (The BSD License)
- * 
- * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 
- *     * Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright notice,
- *       this list of conditions and the following disclaimer in the documentation
- *       and/or other materials provided with the distribution.
- *     * Neither the name of Christian Johansen nor the names of his contributors
- *       may be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
-/**
- * Helps IE run the fake timers. By defining global functions, IE allows
- * them to be overwritten at a later point. If these are not defined like
- * this, overwriting them will result in anything from an exception to browser
- * crash.
- *
- * If you don't require fake timers to work in IE, don't include this file.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-function setTimeout() {}
-function clearTimeout() {}
-function setImmediate() {}
-function clearImmediate() {}
-function setInterval() {}
-function clearInterval() {}
-function Date() {}
-
-// Reassign the original functions. Now their writable attribute
-// should be true. Hackish, I know, but it works.
-setTimeout = sinon.timers.setTimeout;
-clearTimeout = sinon.timers.clearTimeout;
-setImmediate = sinon.timers.setImmediate;
-clearImmediate = sinon.timers.clearImmediate;
-setInterval = sinon.timers.setInterval;
-clearInterval = sinon.timers.clearInterval;
-Date = sinon.timers.Date;
-
-/*global sinon*/
-/**
- * Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows
- * them to be overwritten at a later point. If these are not defined like
- * this, overwriting them will result in anything from an exception to browser
- * crash.
- *
- * If you don't require fake XHR to work in IE, don't include this file.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-function XMLHttpRequest() {}
-
-// Reassign the original function. Now its writable attribute
-// should be true. Hackish, I know, but it works.
-XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
index d14c64b..a4039d8 100644 (file)
@@ -2,14 +2,17 @@
  * Skip function for es5-shim module.
  *
  * Test for strict mode as a proxy for full ES5 function support (but not syntax)
- * Per http://kangax.github.io/compat-table/es5/ this is a reasonable short-cut
- * that still allows this to be as short as possible (there are no function "No"s
- * for non-"obsolete" real browsers where strict support is available).
+ * Per http://kangax.github.io/compat-table/es5/ this is a reasonable shortcut
+ * that still allows this to be as short as possible (there are no browsers we
+ * support that have strict mode, but lack other features).
  *
- * Note that this will cause IE9 users to get the shim (which should be close to
- * a no-op but will increase page payload).
+ * Do explicitly test for Function#bind because of PhantomJS (which implements
+ * strict mode, but lacks Function#bind).
+ *
+ * IE9 supports all features except strict mode, so loading es5-shim should be close to
+ * a no-op but does increase page payload).
  */
 return ( function () {
        'use strict';
-       return !this;
+       return !this && !!Function.prototype.bind;
 }() );
index 485d9c0..f38decd 100644 (file)
@@ -1,6 +1,8 @@
 ( function ( mw, $ ) {
+       // @deprecated since 1.24.  The 'jquery.json' module will be removed in MW 1.25.  Use the 'json' module.
+
        mw.log.deprecate( $, 'toJSON', $.toJSON, 'Use JSON.stringify instead (module "json" for polyfill).' );
        mw.log.deprecate( $, 'evalJSON', $.evalJSON, 'Use JSON.parse instead (module "json" for polyfill).' );
        mw.log.deprecate( $, 'secureEvalJSON', $.secureEvalJSON, 'Use JSON.parse instead (module "json" for polyfill).' );
-       mw.log.deprecate( $, 'quoteString', $.quoteString, 'Use JSON.parse instead (module "json" for polyfill).' );
+       mw.log.deprecate( $, 'quoteString', $.quoteString, 'Use JSON.stringify instead (module "json" for polyfill).' );
 }( mediaWiki, jQuery ) );
index 09de537..bffcf35 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_flat_15_cd0a0a_40x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_flat_15_cd0a0a_40x100.png differ
index c06dd56..8e211d8 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_flat_70_000000_40x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_flat_70_000000_40x100.png differ
index 5308b46..66329e9 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png differ
index 0c8997f..495a561 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-hard_80_d7ebf9_1x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-hard_80_d7ebf9_1x100.png differ
index 3149255..e088e7d 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_100_e4f1fb_1x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_100_e4f1fb_1x100.png differ
index 09b2376..53d4b24 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_100_ffffff_1x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_100_ffffff_1x100.png differ
index 66627c1..b217d9e 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_25_ffef8f_1x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_highlight-soft_25_ffef8f_1x100.png differ
index ccb6dc0..b1fc456 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-bg_inset-hard_100_f0f0f0_1x100.png and b/resources/src/jquery.ui-themes/vector/images/ui-bg_inset-hard_100_f0f0f0_1x100.png differ
index 998ac3b..252bf0f 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-icons_2694e8_256x240.png and b/resources/src/jquery.ui-themes/vector/images/ui-icons_2694e8_256x240.png differ
index 34e38d1..84b601b 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-icons_2e83ff_256x240.png and b/resources/src/jquery.ui-themes/vector/images/ui-icons_2e83ff_256x240.png differ
index ec129a8..ff1c26f 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-icons_3d80b3_256x240.png and b/resources/src/jquery.ui-themes/vector/images/ui-icons_3d80b3_256x240.png differ
index a32c57d..76cecfc 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-icons_666666_256x240.png and b/resources/src/jquery.ui-themes/vector/images/ui-icons_666666_256x240.png differ
index 88fad1a..9d07914 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-icons_72a7cf_256x240.png and b/resources/src/jquery.ui-themes/vector/images/ui-icons_72a7cf_256x240.png differ
index 29ba7d2..4f624bb 100644 (file)
Binary files a/resources/src/jquery.ui-themes/vector/images/ui-icons_ffffff_256x240.png and b/resources/src/jquery.ui-themes/vector/images/ui-icons_ffffff_256x240.png differ
index 8d8a1a6..d429fd2 100644 (file)
@@ -1,12 +1,16 @@
-/* Accordion
-----------------------------------*/
-.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
-.ui-accordion .ui-accordion-li-fix { display: inline; }
-.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
-.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
-/* IE7-/Win - Fix extra vertical space in lists */
-.ui-accordion a { zoom: 1; }
-.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
-.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
-.ui-accordion .ui-accordion-content-active { display: block; }
\ No newline at end of file
+/*!
+ * jQuery UI Accordion 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/Accordion#theming
+ */
+.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; }
+.ui-accordion .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
+.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
index da6de45..e08d14e 100644 (file)
@@ -1,40 +1,20 @@
-/* Autocomplete
-----------------------------------*/
-.ui-autocomplete { position: absolute; cursor: default; }
+/*!
+ * jQuery UI Autocomplete 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/Autocomplete#theming
+ */
+.ui-autocomplete {
+       position: absolute;
+       top: 0;
+       left: 0;
+       cursor: default;
+}
 .ui-autocomplete-loading { /* @embed */ background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }
 
 /* workarounds */
 * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/* Menu
-----------------------------------*/
-.ui-menu {
-       list-style:none;
-       padding: 2px;
-       margin: 0;
-       display:block;
-       float: left;
-}
-.ui-menu .ui-menu {
-       margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
-       margin:0;
-       padding: 0;
-       zoom: 1;
-       float: left;
-       clear: left;
-       width: 100%;
-}
-.ui-menu .ui-menu-item a {
-       text-decoration:none;
-       display:block;
-       padding:.2em .4em;
-       line-height:1.5;
-       zoom:1;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
-       font-weight: normal;
-       margin: -1px;
-}
index 8c2286d..1838f48 100644 (file)
@@ -1,92 +1,44 @@
-/* Button
-----------------------------------*/
-
-.ui-button {
-       display: inline-block;
-       position: relative;
-       padding: 0;
-       margin-right: .1em;
-       text-decoration: none !important;
-       cursor: pointer;
-       text-align: center;
-       zoom: 1;
-       overflow: visible; /* the overflow property removes extra width in IE */
-}
+/*!
+ * jQuery UI Button 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/Button#theming
+ */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; }
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
 
 /*button text element */
-.ui-button .ui-button-text {
-       display: block;
-       line-height: 1.4;
-       text-shadow: 0 1px 1px #fff;
-}
-.ui-button-text-only .ui-button-text {
-       padding: 0.3em 1em 0.25em 1em;
-}
-.ui-button-icon-only .ui-button-text,
-.ui-button-icons-only .ui-button-text {
-       padding: 0.3em;
-       text-indent: -9999999px;
-}
-.ui-button-text-icon-primary .ui-button-text,
-.ui-button-text-icons .ui-button-text {
-       padding: 0.3em 1em 0.25em 2.1em;
-}
-.ui-button-text-icon-secondary .ui-button-text,
-.ui-button-text-icons .ui-button-text {
-       padding: 0.3em 2.1em 0.25em 1em;
-}
-.ui-button-text-icons .ui-button-text {
-       padding-left: 2.1em;
-       padding-right: 2.1em;
-}
-
+.ui-button .ui-button-text { display: block; line-height: 1.4;  }
+.ui-button-text-only .ui-button-text { padding: .125em .25em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
 /* no icon support for input elements, provide padding by default */
-input.ui-button {
-       padding: 0.3em 1em;
-}
+input.ui-button { padding: .4em 1em; }
 
 /*button icon element(s) */
-.ui-button-icon-only .ui-icon,
-.ui-button-text-icon-primary .ui-icon,
-.ui-button-text-icon-secondary .ui-icon,
-.ui-button-text-icons .ui-icon,
-.ui-button-text-icon .ui-icon,
-.ui-button-icons-only .ui-icon {
-       position: absolute;
-       top: 50%;
-       margin-top: -9px;
-}
-.ui-button-icon-only .ui-icon {
-       left: 50%;
-       margin-left: -8px;
-}
-.ui-button-text-icon-primary .ui-button-icon-primary,
-.ui-button-text-icon .ui-button-icon-primary,
-.ui-button-text-icons .ui-button-icon-primary,
-.ui-button-icons-only .ui-button-icon-primary {
-       left: 0.5em;
-}
-.ui-button-text-icon-secondary .ui-button-icon-secondary,
-.ui-button-text-icon .ui-button-icon-secondary,
-.ui-button-text-icons .ui-button-icon-secondary,
-.ui-button-icons-only .ui-button-icon-secondary {
-       right: 0.5em;
-}
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
 
 /*button sets*/
-.ui-buttonset {
-       margin-right: 7px;
-}
-.ui-buttonset .ui-button {
-       margin-left: 0;
-       margin-right: -.4em;
-}
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.4em; }
 
 /* workarounds */
-button.ui-button::-moz-focus-inner {
-       border: 0;
-       padding: 0; /* reset extra padding in Firefox */
-}
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+
 /* Disables the annoying dashed border Firefox puts on active buttons */
 body button.ui-button::-moz-focus-inner {
        border: 0;
index b3e8193..2e088ca 100644 (file)
@@ -1,20 +1,22 @@
-/*
-* jQuery UI CSS Framework
-* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-*/
+/*!
+ * jQuery UI CSS Framework 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/Theming/API
+ */
 
 /* Layout helpers
 ----------------------------------*/
 .ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
 .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-.ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ui-helper-clearfix { height:1%; }
-.ui-helper-clearfix { display:block; }
-/* end clearfix */
+.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
+.ui-helper-clearfix:after { clear: both; }
+.ui-helper-clearfix { zoom: 1; }
 .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
 
 
index 871bf69..c946ce4 100644 (file)
@@ -1,5 +1,13 @@
-/* Datepicker
-----------------------------------*/
+/*!
+ * jQuery UI Datepicker 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/Datepicker#theming
+ */
 .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
 .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
 .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
@@ -18,7 +26,7 @@
 .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
 .ui-datepicker td { border: 0; padding: 1px; }
 .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .2em 0 0 0; padding: 0 .2em; border-top: 1px solid #DDDDDD; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-top: 1px solid #DDDDDD; border-left: 0; border-right: 0; border-bottom: 0; }
 .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
 .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
 
@@ -32,7 +40,7 @@
 .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
 .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
 .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; }
+.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
 
 /* RTL support */
 /* @noflip */ .ui-datepicker-rtl { direction: rtl; }
@@ -49,8 +57,6 @@
 
 /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
 .ui-datepicker-cover {
-    display: none; /*sorry for IE5*/
-    display/**/: block; /*sorry for IE5*/
     position: absolute; /*must have*/
     z-index: -1; /*must have*/
     filter: mask(); /*must have*/
index cd85f14..78f8f8f 100644 (file)
@@ -1,16 +1,26 @@
-/* Dialog
-----------------------------------*/
-.ui-dialog { position: absolute; padding: 0; width: 300px; }
-.ui-dialog .ui-dialog-titlebar { padding: .75em; position: relative;  }
-.ui-dialog .ui-dialog-title { float: left; margin: 0; } 
+/*!
+ * jQuery UI Dialog 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/Dialog#theming
+ */
+.ui-dialog { position: absolute; top: 0; left: 0; padding: 0; width: 300px; }
+.ui-dialog .ui-dialog-titlebar { padding: .75em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: 0; }
 .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .75em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
 .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
 .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
 .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
 .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
 .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
 .ui-draggable .ui-dialog-titlebar { cursor: move; }
+
 /* Customizations */
 body .ui-dialog .ui-dialog-titlebar-close:hover {
        text-decoration: none;
diff --git a/resources/src/jquery.ui-themes/vector/jquery.ui.menu.css b/resources/src/jquery.ui-themes/vector/jquery.ui.menu.css
new file mode 100644 (file)
index 0000000..83fd84e
--- /dev/null
@@ -0,0 +1,30 @@
+/*!
+ * jQuery UI Menu 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/Menu#theming
+ */
+.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; }
+.ui-menu .ui-menu { margin-top: -3px; position: absolute; }
+.ui-menu .ui-menu-item { margin: 0; padding: 0; zoom: 1; width: 100%; }
+.ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; }
+.ui-menu .ui-menu-item a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; }
+.ui-menu .ui-menu-item a.ui-state-focus,
+.ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; }
+
+.ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; }
+.ui-menu .ui-state-disabled a { cursor: default; }
+
+/* icon support */
+.ui-menu-icons { position: relative; }
+.ui-menu-icons .ui-menu-item a { position: relative; padding-left: 2em; }
+
+/* left-aligned */
+.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; }
+
+/* right-aligned */
+.ui-menu .ui-menu-icon { position: static; float: right; }
index bc0939e..bd7e403 100644 (file)
@@ -1,4 +1,12 @@
-/* Progressbar
-----------------------------------*/
-.ui-progressbar { height:2em; text-align: left; }
+/*!
+ * jQuery UI Progressbar 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/Progressbar#theming
+ */
+.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
 .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
index f1bd7c5..f8822e8 100644 (file)
@@ -1,7 +1,15 @@
-/* Resizable
-----------------------------------*/
+/*!
+ * jQuery UI Resizable 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/Resizable#theming
+ */
 .ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
 .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
 .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
 .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
index c5d46ce..5854c41 100644 (file)
@@ -1,3 +1,11 @@
-/* Selectable
-----------------------------------*/
-.ui-selectable-helper { border:1px dotted black }
+/*!
+ * jQuery UI Selectable 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/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
index 07c6f4e..e579478 100644 (file)
@@ -1,5 +1,13 @@
-/* Slider
-----------------------------------*/
+/*!
+ * jQuery UI Slider 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/Slider#theming
+ */
 .ui-slider { position: relative; text-align: left; }
 .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
 .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
diff --git a/resources/src/jquery.ui-themes/vector/jquery.ui.spinner.css b/resources/src/jquery.ui-themes/vector/jquery.ui.spinner.css
new file mode 100644 (file)
index 0000000..e89b720
--- /dev/null
@@ -0,0 +1,23 @@
+/*!
+ * 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 99e16db..11a000f 100644 (file)
@@ -1,11 +1,18 @@
-/* Tabs
-----------------------------------*/
+/*!
+ * jQuery UI Tabs 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/Tabs#theming
+ */
 .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
 .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; }
 .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
-.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
 .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
-.ui-tabs .ui-tabs-hide { display: none !important; }
index 8f46645..7452e97 100644 (file)
@@ -1,11 +1,15 @@
-
-
-/*
-* jQuery UI CSS Framework
-* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
-* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
-* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=sans-serif&fwDefault=normal&fsDefault=1.0em&cornerRadius=3px&bgColorHeader=ffffff&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=04_highlight_hard.png&bgImgOpacityContent=100&borderColorContent=cccccc&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=04_highlight_hard.png&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=f0f0f0&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=cccccc&fcActive=000000&iconColorActive=666666&bgColorHighlight=ffef8f&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=01_flat.png&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=000000&bgTextureOverlay=21_glow_ball.png&bgImgOpacityOverlay=100&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=70&opacityShadow=20&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px
-*/
+/*!
+ * jQuery UI CSS Framework 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/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=sans-serif&fwDefault=normal&fsDefault=1.0em&cornerRadius=3px&bgColorHeader=ffffff&bgTextureHeader=highlight_soft&bgImgOpacityHeader=100&borderColorHeader=aed0ea&fcHeader=222222&iconColorHeader=72a7cf&bgColorContent=f2f5f7&bgTextureContent=highlight_hard&bgImgOpacityContent=100&borderColorContent=cccccc&fcContent=362b36&iconColorContent=72a7cf&bgColorDefault=d7ebf9&bgTextureDefault=highlight_hard&bgImgOpacityDefault=80&borderColorDefault=aed0ea&fcDefault=2779aa&iconColorDefault=3d80b3&bgColorHover=e4f1fb&bgTextureHover=highlight_soft&bgImgOpacityHover=100&borderColorHover=74b2e2&fcHover=0070a3&iconColorHover=2694e8&bgColorActive=f0f0f0&bgTextureActive=inset_hard&bgImgOpacityActive=100&borderColorActive=cccccc&fcActive=000000&iconColorActive=666666&bgColorHighlight=ffef8f&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=25&borderColorHighlight=f9dd34&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=cd0a0a&bgTextureError=flat&bgImgOpacityError=15&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=000000&bgTextureOverlay=glow_ball&bgImgOpacityOverlay=100&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=70&opacityShadow=20&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px
+ */
 
 
 /* Component containers
 .ui-widget { font-family: sans-serif; font-size: 0.8em; }
 .ui-widget .ui-widget { font-size: 1em; }
 .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: sans-serif; font-size: 1em; }
-.ui-widget-content { border: 1px solid #cccccc; /* @embed */ background: #f2f5f7 url(images/ui-bg_highlight-hard_100_f2f5f7_1x100.png) 50% top repeat-x; color: #362b36; }
-.ui-widget-content a { color: #362b36; }
-.ui-widget-header { border-bottom: 1px solid #bbbbbb; line-height: 1em; /* @embed */ background: #ffffff url(images/ui-bg_highlight-soft_100_ffffff_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
-.ui-widget-header a { color: #222222; }
+.ui-widget-content { border: 1px solid #cccccc; /* @embed */ background: #f2f5f7 url("images/ui-bg_highlight-hard_100_f2f5f7_1x100.png") 50% top repeat-x; color: #362b36; }
+.ui-widget-header { border-bottom: 1px solid #bbbbbb; line-height: 1em; /* @embed */ background: #ffffff url("images/ui-bg_highlight-soft_100_ffffff_1x100.png") 50% 50% repeat-x; color: #222222; font-weight: bold; }
 
 /* Interaction states
 ----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #aed0ea; /* @embed */ background: #d7ebf9 url(images/ui-bg_highlight-hard_80_d7ebf9_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #2779aa; }
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #aed0ea; /* @embed */ background: #d7ebf9 url("images/ui-bg_highlight-hard_80_d7ebf9_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #2779aa; }
 .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2779aa; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #74b2e2; /* @embed */ background: #e4f1fb url(images/ui-bg_highlight-soft_100_e4f1fb_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #0070a3; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #0070a3; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #cccccc; background: #f0f0f0 /* @embed */ url(images/ui-bg_inset-hard_100_f0f0f0_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #000000; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #74b2e2; /* @embed */ background: #e4f1fb url("images/ui-bg_highlight-soft_100_e4f1fb_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #0070a3; }
+.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #0070a3; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #cccccc; background: #f0f0f0 /* @embed */ url("images/ui-bg_inset-hard_100_f0f0f0_1x100.png") 50% 50% repeat-x; font-weight: normal; color: #000000; }
 .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #000000; text-decoration: none; }
-.ui-widget :active { outline: none; }
 
 /* Interaction Cues
 ----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #f9dd34; background: #ffef8f /* @embed */ url(images/ui-bg_highlight-soft_25_ffef8f_1x100.png) 50% top repeat-x; color: #363636; }
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #f9dd34; background: #ffef8f /* @embed */ url("images/ui-bg_highlight-soft_25_ffef8f_1x100.png") 50% top repeat-x; color: #363636; }
 .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #cd0a0a /* @embed */ url(images/ui-bg_flat_15_cd0a0a_40x100.png) 50% 50% repeat-x; color: #ffffff; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #cd0a0a /* @embed */ url("images/ui-bg_flat_15_cd0a0a_40x100.png") 50% 50% repeat-x; color: #ffffff; }
 .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
 .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
 .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
 .ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
 .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */
 
 /* Icons
 ----------------------------------*/
 
 /* states and images */
 .ui-icon { width: 16px; height: 16px; }
-.ui-icon, .ui-widget-content .ui-icon, .ui-widget-header .ui-icon { /* @embed */ background-image: url(images/ui-icons_72a7cf_256x240.png); }
-.ui-state-default .ui-icon { /* @embed */ background-image: url(images/ui-icons_3d80b3_256x240.png); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon { /* @embed */ background-image: url(images/ui-icons_2694e8_256x240.png); }
-.ui-state-active .ui-icon { /* @embed */ background-image: url(images/ui-icons_666666_256x240.png); }
-.ui-state-highlight .ui-icon { /* @embed */ background-image: url(images/ui-icons_2e83ff_256x240.png); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon { /* @embed */ background-image: url(images/ui-icons_ffffff_256x240.png); }
+.ui-icon, .ui-widget-content .ui-icon, .ui-widget-header .ui-icon { /* @embed */ background-image: url("images/ui-icons_72a7cf_256x240.png"); }
+.ui-state-default .ui-icon { /* @embed */ background-image: url("images/ui-icons_3d80b3_256x240.png"); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon { /* @embed */ background-image: url("images/ui-icons_2694e8_256x240.png"); }
+.ui-state-active .ui-icon { /* @embed */ background-image: url("images/ui-icons_666666_256x240.png"); }
+.ui-state-highlight .ui-icon { /* @embed */ background-image: url("images/ui-icons_2e83ff_256x240.png"); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon { /* @embed */ background-image: url("images/ui-icons_ffffff_256x240.png"); }
 
 /* positioning */
 .ui-icon-carat-1-n { background-position: 0 0; }
 .ui-icon-help { background-position: -48px -144px; }
 .ui-icon-check { background-position: -64px -144px; }
 .ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
 .ui-icon-pin-w { background-position: -128px -144px; }
 .ui-icon-pin-s { background-position: -144px -144px; }
 .ui-icon-play { background-position: 0 -160px; }
 ----------------------------------*/
 
 /* Corner radius */
-.ui-corner-tl { border-top-left-radius: 0; }
-.ui-corner-tr { border-top-right-radius: 0; }
-.ui-corner-bl { border-bottom-left-radius: 0; }
-.ui-corner-br { border-bottom-right-radius: 0; }
-.ui-corner-top { border-top-left-radius: 0; border-top-right-radius: 0; }
-.ui-corner-bottom { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
-.ui-corner-right {  border-top-right-radius: 0; border-bottom-right-radius: 0; }
-.ui-corner-left { border-top-left-radius: 0; border-bottom-left-radius: 0; }
-.ui-corner-all { border-radius: 0; }
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 0; -webkit-border-top-left-radius: 0; -khtml-border-top-left-radius: 0; border-top-left-radius: 0; }
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 0; -webkit-border-top-right-radius: 0; -khtml-border-top-right-radius: 0; border-top-right-radius: 0; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 0; -webkit-border-bottom-left-radius: 0; -khtml-border-bottom-left-radius: 0; border-bottom-left-radius: 0; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 0; -webkit-border-bottom-right-radius: 0; -khtml-border-bottom-right-radius: 0; border-bottom-right-radius: 0; }
 
 /* Overlays */
 .ui-widget-overlay { background: #000000; opacity: .75;filter:Alpha(Opacity=75); }
-.ui-widget-shadow { margin: -7px 0 0 -7px; padding: 7px; /* @embed */ background: #000000 url(images/ui-bg_flat_70_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); border-radius: 8px; }
+.ui-widget-shadow { margin: -7px 0 0 -7px; padding: 7px; /* @embed */ background: #000000 url("images/ui-bg_flat_70_000000_40x100.png") 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
\ No newline at end of file
diff --git a/resources/src/jquery.ui-themes/vector/jquery.ui.tooltip.css b/resources/src/jquery.ui-themes/vector/jquery.ui.tooltip.css
new file mode 100644 (file)
index 0000000..88b0d02
--- /dev/null
@@ -0,0 +1,21 @@
+/*!
+ * jQuery UI Tooltip 1.9.2
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+.ui-tooltip {
+       padding: 8px;
+       position: absolute;
+       z-index: 9999;
+       max-width: 300px;
+       -webkit-box-shadow: 0 0 5px #aaa;
+       box-shadow: 0 0 5px #aaa;
+}
+/* Fades and background-images don't work well together in IE6, drop the image */
+* html .ui-tooltip {
+       background-image: none;
+}
+body .ui-tooltip { border-width: 2px; }
index 80b8303..7b49cb2 100644 (file)
@@ -154,7 +154,7 @@ function updateTooltip( element ) {
                        }
                }
 
-               // Search it as parent, because the form control can also inside the label element itself
+               // Search it as parent, because the form control can also be inside the label element itself
                $labelParent = $element.parents( 'label' );
                if ( $labelParent.length === 1 ) {
                        updateTooltipOnElement( element, $labelParent[0] );
index 66a3c56..f8641e1 100644 (file)
         * @chainable
         */
        $.fn.arrowSteps = function () {
-               var $steps, width, arrowWidth,
+               var $steps, width, arrowWidth, $stepDiv,
+                       $el = this,
                        paddingSide = $( 'body' ).hasClass( 'rtl' ) ? 'padding-left' : 'padding-right';
 
-               this.addClass( 'arrowSteps' );
-               $steps = this.find( 'li' );
+               $el.addClass( 'arrowSteps' );
+               $steps = $el.find( 'li' );
 
                width = parseInt( 100 / $steps.length, 10 );
                $steps.css( 'width', width + '%' );
                // Every step except the last one has an arrow pointing forward:
                // at the right hand side in LTR languages, and at the left hand side in RTL.
                // Also add in the padding for the calculated arrow width.
-               arrowWidth = parseInt( this.outerHeight(), 10 );
-               $steps.filter( ':not(:last-child)' ).addClass( 'arrow' )
-                       .find( 'div' ).css( paddingSide, arrowWidth.toString() + 'px' );
+               $stepDiv = $steps.filter( ':not(:last-child)' ).addClass( 'arrow' ).find( 'div' );
+
+               // Execute when complete page is fully loaded, including all frames, objects and images
+               $( window ).load( function () {
+                       arrowWidth = parseInt( $el.outerHeight(), 10 );
+                       $stepDiv.css( paddingSide, arrowWidth.toString() + 'px' );
+               } );
+
+               $el.data( 'arrowSteps', $steps );
 
-               this.data( 'arrowSteps', $steps );
                return this;
        };
 
index be770a9..a6ff8bc 100644 (file)
 
                        // Look for rgb(num,num,num)
                        if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) {
-                               return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];
+                               return [
+                                       parseInt( result[1], 10 ),
+                                       parseInt( result[2], 10 ),
+                                       parseInt( result[3], 10 )
+                               ];
                        }
 
                        // Look for rgb(num%,num%,num%)
                        if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) {
-                               return [parseFloat(result[1],10) * 2.55, parseFloat(result[2],10) * 2.55, parseFloat(result[3]) * 2.55];
+                               return [
+                                       parseFloat( result[1] ) * 2.55,
+                                       parseFloat( result[2] ) * 2.55,
+                                       parseFloat( result[3] ) * 2.55
+                               ];
                        }
 
                        // Look for #a0b1c2
                        if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) {
-                               return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];
+                               return [
+                                       parseInt( result[1], 16 ),
+                                       parseInt( result[2], 16 ),
+                                       parseInt( result[3], 16 )
+                               ];
                        }
 
                        // Look for #fff
                        if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) {
-                               return [parseInt(result[1] + result[1],16), parseInt(result[2] + result[2],16), parseInt(result[3] + result[3],16)];
+                               return [
+                                       parseInt( result[1] + result[1], 16 ),
+                                       parseInt( result[2] + result[2], 16 ),
+                                       parseInt( result[3] + result[3], 16)
+                               ];
                        }
 
                        // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
                 * @property {Object}
                 */
                colors: {
-                       aqua: [0,255,255],
-                       azure: [240,255,255],
-                       beige: [245,245,220],
-                       black: [0,0,0],
-                       blue: [0,0,255],
-                       brown: [165,42,42],
-                       cyan: [0,255,255],
-                       darkblue: [0,0,139],
-                       darkcyan: [0,139,139],
-                       darkgrey: [169,169,169],
-                       darkgreen: [0,100,0],
-                       darkkhaki: [189,183,107],
-                       darkmagenta: [139,0,139],
-                       darkolivegreen: [85,107,47],
-                       darkorange: [255,140,0],
-                       darkorchid: [153,50,204],
-                       darkred: [139,0,0],
-                       darksalmon: [233,150,122],
-                       darkviolet: [148,0,211],
-                       fuchsia: [255,0,255],
-                       gold: [255,215,0],
-                       green: [0,128,0],
-                       indigo: [75,0,130],
-                       khaki: [240,230,140],
-                       lightblue: [173,216,230],
-                       lightcyan: [224,255,255],
-                       lightgreen: [144,238,144],
-                       lightgrey: [211,211,211],
-                       lightpink: [255,182,193],
-                       lightyellow: [255,255,224],
-                       lime: [0,255,0],
-                       magenta: [255,0,255],
-                       maroon: [128,0,0],
-                       navy: [0,0,128],
-                       olive: [128,128,0],
-                       orange: [255,165,0],
-                       pink: [255,192,203],
-                       purple: [128,0,128],
-                       violet: [128,0,128],
-                       red: [255,0,0],
-                       silver: [192,192,192],
-                       white: [255,255,255],
-                       yellow: [255,255,0],
-                       transparent: [255,255,255]
+                       aqua: [0, 255, 255],
+                       azure: [240, 255, 255],
+                       beige: [245, 245, 220],
+                       black: [0, 0, 0],
+                       blue: [0, 0, 255],
+                       brown: [165, 42, 42],
+                       cyan: [0, 255, 255],
+                       darkblue: [0, 0, 139],
+                       darkcyan: [0, 139, 139],
+                       darkgrey: [169, 169, 169],
+                       darkgreen: [0, 100, 0],
+                       darkkhaki: [189, 183, 107],
+                       darkmagenta: [139, 0, 139],
+                       darkolivegreen: [85, 107, 47],
+                       darkorange: [255, 140, 0],
+                       darkorchid: [153, 50, 204],
+                       darkred: [139, 0, 0],
+                       darksalmon: [233, 150, 122],
+                       darkviolet: [148, 0, 211],
+                       fuchsia: [255, 0, 255],
+                       gold: [255, 215, 0],
+                       green: [0, 128, 0],
+                       indigo: [75, 0, 130],
+                       khaki: [240, 230, 140],
+                       lightblue: [173, 216, 230],
+                       lightcyan: [224, 255, 255],
+                       lightgreen: [144, 238, 144],
+                       lightgrey: [211, 211, 211],
+                       lightpink: [255, 182, 193],
+                       lightyellow: [255, 255, 224],
+                       lime: [0, 255, 0],
+                       magenta: [255, 0, 255],
+                       maroon: [128, 0, 0],
+                       navy: [0, 0, 128],
+                       olive: [128, 128, 0],
+                       orange: [255, 165, 0],
+                       pink: [255, 192, 203],
+                       purple: [128, 0, 128],
+                       violet: [128, 0, 128],
+                       red: [255, 0, 0],
+                       silver: [192, 192, 192],
+                       white: [255, 255, 255],
+                       yellow: [255, 255, 0],
+                       transparent: [255, 255, 255]
                },
 
                /**
index 05745f8..c4e2520 100644 (file)
                                        .text( collapseText )
                                        .wrap( '<span class="mw-collapsible-toggle"></span>' )
                                                .parent()
-                                               .prepend( '&nbsp;[' )
-                                               .append( ']&nbsp;' )
+                                               .prepend( '<span class="mw-collapsible-bracket">[</span>' )
+                                               .append( '<span class="mw-collapsible-bracket">]</span>' )
                                                .on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler );
                        };
 
                        } else {
                                collapsibleId = $collapsible.attr( 'id' ) || '';
                                if ( collapsibleId.indexOf( 'mw-customcollapsible-' ) === 0 ) {
-                                       $customTogglers = $( '.' + collapsibleId.replace( 'mw-customcollapsible', 'mw-customtoggle' ) );
-                                       $customTogglers.addClass( 'mw-customtoggle' );
+                                       $customTogglers = $( '.' + collapsibleId.replace( 'mw-customcollapsible', 'mw-customtoggle' ) )
+                                               .addClass( 'mw-customtoggle' );
                                }
                        }
 
                                        togglingHandler( $( this ), $collapsible, e, opts );
                                };
 
-                               $toggleLink = $customTogglers;
-                               $toggleLink.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler );
+                               $toggleLink = $customTogglers
+                                       .on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler )
+                                       .prop( 'tabIndex', 0 );
 
                        } else {
                                // If this is not a custom case, do the default: wrap the
                                                        $toggleLink = buildDefaultToggleLink().appendTo( $caption );
                                                } else {
                                                        actionHandler = premadeToggleHandler;
-                                                       $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler );
+                                                       $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler )
+                                                               .prop( 'tabIndex', 0 );
                                                }
                                        } else {
                                                // The toggle-link will be in one the the cells (td or th) of the first row
                                                        $toggleLink = buildDefaultToggleLink().prependTo( $firstItem.eq( -1 ) );
                                                } else {
                                                        actionHandler = premadeToggleHandler;
-                                                       $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler );
+                                                       $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler )
+                                                               .prop( 'tabIndex', 0 );
                                                }
                                        }
 
                                                $toggleLink.wrap( '<li class="mw-collapsible-toggle-li"></li>' ).parent().prependTo( $collapsible );
                                        } else {
                                                actionHandler = premadeToggleHandler;
-                                               $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler );
+                                               $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler )
+                                                       .prop( 'tabIndex', 0 );
                                        }
 
                                } else { // <div>, <p> etc.
                                                $toggleLink = buildDefaultToggleLink().prependTo( $collapsible );
                                        } else {
                                                actionHandler = premadeToggleHandler;
-                                               $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler );
+                                               $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler )
+                                                       .prop( 'tabIndex', 0 );
                                        }
                                }
                        }
 
-                       // Attributes for accessibility. This isn't necessary when the toggler is already
-                       // an <a> or a <button> etc., but it doesn't hurt either, and it's consistent.
-                       $toggleLink.prop( 'tabIndex', 0 );
-
                        // Initial state
                        if ( options.collapsed || $collapsible.hasClass( 'mw-collapsed' ) ) {
                                // One toggler can hook to multiple elements, and one element can have
index 042db91..0573f66 100644 (file)
@@ -25,7 +25,7 @@
        $.fn.textSelection = function ( command, options ) {
                var fn,
                        context,
-                       hasIframe,
+                       hasWikiEditorSurface, // The alt edit surface needs to implement the WikiEditor API
                        needSave,
                        retval;
 
                                        // Position to start selection at
                                        start: undefined,
                                        // Position to end selection at. Defaults to start
-                                       end: undefined,
-                                       // Element to start selection in (iframe only)
-                                       startContainer: undefined,
-                                       // Element to end selection in (iframe only). Defaults to startContainer
-                                       endContainer: undefined
+                                       end: undefined
                                }, options );
 
                                if ( options.end === undefined ) {
                                        options.end = options.start;
                                }
-                               if ( options.endContainer === undefined ) {
-                                       options.endContainer = options.startContainer;
-                               }
                                // FIXME: We may not need character position-based functions if we insert markers in the right places
                                break;
                        case 'scrollToCaretPosition':
                }
 
                context = $( this ).data( 'wikiEditor-context' );
-               hasIframe = context !== undefined && context && context.$iframe !== undefined;
+               hasWikiEditorSurface = ( context !== undefined );
 
                // IE selection restore voodoo
                needSave = false;
-               if ( hasIframe && context.savedSelection !== null ) {
+               if ( hasWikiEditorSurface && context.savedSelection !== null ) {
                        context.fn.restoreSelection();
                        needSave = true;
                }
-               retval = ( hasIframe ? context.fn : fn )[command].call( this, options );
-               if ( hasIframe && needSave ) {
+               retval = ( hasWikiEditorSurface && context.fn[command] !== undefined ? context.fn : fn )[command].call( this, options );
+               if ( hasWikiEditorSurface && needSave ) {
                        context.fn.saveSelection();
                }
 
index edfb34a..e88ae5e 100644 (file)
                                mw.track( 'mw.deprecate', 'api.cbParam' );
                                mw.log.warn( msg );
                        }
+
                        return this.postWithToken( 'edit', params ).done( ok ).fail( err );
                },
 
                /**
-                * Api helper to grab an edit token.
+                * API helper to grab an edit token.
                 *
                 * @param {Function} [ok] Success callback (deprecated)
                 * @param {Function} [err] Error callback (deprecated)
                                mw.track( 'mw.deprecate', 'api.cbParam' );
                                mw.log.warn( msg );
                        }
+
                        return this.getToken( 'edit' ).done( ok ).fail( err );
                },
 
                /**
-                * Create a new section of the page.
+                * Post a new section to the page.
                 * @see #postWithEditToken
                 * @param {mw.Title|String} title Target page
                 * @param {string} header
                 * @param {string} message wikitext message
+                * @param {Object} [additionalParams] Additional API parameters, e.g. `{ redirect: true }`
                 * @param {Function} [ok] Success handler (deprecated)
                 * @param {Function} [err] Error handler (deprecated)
                 * @return {jQuery.Promise}
                 */
-               newSection: function ( title, header, message, ok, err ) {
+               newSection: function ( title, header, message, additionalParams, ok, err ) {
+                       // Until we remove 'ok' and 'err' parameters, we have to support code that passes them,
+                       // but not additionalParams...
+                       if ( $.isFunction( additionalParams ) ) {
+                               err = ok;
+                               ok = additionalParams;
+                               additionalParams = undefined;
+                       }
+
                        if ( ok || err ) {
                                mw.track( 'mw.deprecate', 'api.cbParam' );
                                mw.log.warn( msg );
                        }
-                       return this.postWithEditToken( {
+
+                       return this.postWithEditToken( $.extend( {
                                action: 'edit',
                                section: 'new',
                                format: 'json',
                                title: String( title ),
                                summary: header,
                                text: message
-                       } ).done( ok ).fail( err );
+                       }, additionalParams ) ).done( ok ).fail( err );
                }
        } );
 
diff --git a/resources/src/mediawiki.hidpi-skip.js b/resources/src/mediawiki.hidpi-skip.js
new file mode 100644 (file)
index 0000000..26b63c7
--- /dev/null
@@ -0,0 +1,4 @@
+/*!
+ * Skip function for mediawiki.hdpi.js.
+ */
+return 'srcset' in new Image();
index 04b7d0a..52e8dd4 100644 (file)
@@ -14,9 +14,9 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
                        word = word.replace( /u[ms]$/i, 'i' ); // 2nd declension singular
                        word = word.replace( /ommunia$/i, 'ommunium' ); // 3rd declension neuter plural (partly)
                        word = word.replace( /a$/i, 'ae' ); // 1st declension singular
-                       word = word.replace( /libri$/i,'librorum' ); // 2nd declension plural (partly)
+                       word = word.replace( /libri$/i, 'librorum' ); // 2nd declension plural (partly)
                        word = word.replace( /nuntii$/i, 'nuntiorum' ); // 2nd declension plural (partly)
-                       word = word.replace( /tio$/i,'tionis' ); // 3rd declension singular (partly)
+                       word = word.replace( /tio$/i, 'tionis' ); // 3rd declension singular (partly)
                        word = word.replace( /ns$/i, 'ntis' );
                        word = word.replace( /as$/i, 'atis' );
                        word = word.replace( /es$/i, 'ei' ); // 5th declension singular
@@ -26,9 +26,9 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
                        word = word.replace( /u[ms]$/i, 'um' ); // 2nd declension singular
                        word = word.replace( /ommunia$/i, 'am' ); // 3rd declension neuter plural (partly)
                        word = word.replace( /a$/i, 'ommunia' ); // 1st declension singular
-                       word = word.replace( /libri$/i,'libros' ); // 2nd declension plural (partly)
+                       word = word.replace( /libri$/i, 'libros' ); // 2nd declension plural (partly)
                        word = word.replace( /nuntii$/i, 'nuntios' );// 2nd declension plural (partly)
-                       word = word.replace( /tio$/i,'tionem' ); // 3rd declension singular (partly)
+                       word = word.replace( /tio$/i, 'tionem' ); // 3rd declension singular (partly)
                        word = word.replace( /ns$/i, 'ntem' );
                        word = word.replace( /as$/i, 'atem');
                        word = word.replace( /es$/i, 'em' ); // 5th declension singular
@@ -38,9 +38,9 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
                        word = word.replace( /u[ms]$/i, 'o' ); // 2nd declension singular
                        word = word.replace( /ommunia$/i, 'ommunibus' ); // 3rd declension neuter plural (partly)
                        word = word.replace( /a$/i, 'a' ); // 1st declension singular
-                       word = word.replace( /libri$/i,'libris' ); // 2nd declension plural (partly)
+                       word = word.replace( /libri$/i, 'libris' ); // 2nd declension plural (partly)
                        word = word.replace( /nuntii$/i, 'nuntiis' ); // 2nd declension plural (partly)
-                       word = word.replace( /tio$/i,'tione' ); // 3rd declension singular (partly)
+                       word = word.replace( /tio$/i, 'tione' ); // 3rd declension singular (partly)
                        word = word.replace( /ns$/i, 'nte' );
                        word = word.replace( /as$/i, 'ate');
                        word = word.replace( /es$/i, 'e' ); // 5th declension singular
index e66b9cd..b6ba59f 100644 (file)
@@ -25,6 +25,8 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
                                word = word.substr(0, word.length - 2 ) + 'тей';
                        } else if ( word.substr( word.length - 2 ) === 'ды' ) {
                                word = word.substr(0, word.length - 2 ) + 'дов';
+                       } else if ( word.substr( word.length - 1 ) === 'д' ) {
+                               word = word.substr(0, word.length - 1 ) + 'да';
                        } else if ( word.substr( word.length - 3 ) === 'ные' ) {
                                word = word.substr(0, word.length - 3 ) + 'ных';
                        } else if ( word.substr( word.length - 3 ) === 'ник' ) {
@@ -42,6 +44,8 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
                                word = word.substr(0, word.length - 2 ) + 'тях';
                        } else if ( word.substr( word.length - 2 ) === 'ды' ) {
                                word = word.substr(0, word.length - 2 ) + 'дах';
+                       } else if ( word.substr( word.length - 1 ) === 'д' ) {
+                               word = word.substr(0, word.length - 1 ) + 'де';
                        } else if ( word.substr( word.length - 3 ) === 'ные' ) {
                                word = word.substr(0, word.length - 3 ) + 'ных';
                        } else if ( word.substr( word.length - 3 ) === 'ник' ) {
index b65a62b..8c28884 100644 (file)
 }
 
 .transition(@value) {
-       -webkit-transition: @value;
-       -moz-transition: @value;
-       -o-transition: @value;
-       transition: @value;
+       -webkit-transition: @value; // Safari 3.1-6.0, iOS 3.2-6.1, Android 2.1-4.3
+       -moz-transition: @value; // Firefox 4-15
+       -o-transition: @value; // Opera 10.5-12.0
+       transition: @value; // Chrome 26+, Firefox 16+, IE 10+, Safari 6.1+, Opera 12.1+, iOS 7+, Android 4.4+
 }
 
 .box-sizing(@value) {
-       -webkit-box-sizing: @value;
-       -moz-box-sizing: @value;
-       box-sizing: @value;
+       -webkit-box-sizing: @value; // Safari 3.1-5.0, iOS 3.2-4.3, Android 2.1-3.0
+       -moz-box-sizing: @value; // Firefox 4-28,
+       box-sizing: @value; // Chrome 10+, Firefox 29+, IE 8+, Safari 5.1+, Opera 10+, iOS 5+, Android 4+
 }
 
 .box-shadow(@value) {
-       -webkit-box-shadow: @value; // Android 2.3+, iOS 4.0.2-4.2, Safari 3-4
-       box-shadow: @value; // Chrome 6+, Firefox 4+, IE 9+, iOS 5+, Opera 10.50+
+       -webkit-box-shadow: @value; // Safari 3.1-5.0, iOS 3.2-4.3, Android 2.1-3.0
+       box-shadow: @value; // Chrome 10+, Firefox 4+, IE 9+, Safari 5.1+, Opera 11+, iOS 5+, Android 4+
 }
diff --git a/resources/src/mediawiki.less/mediawiki.ui/mixins.less b/resources/src/mediawiki.less/mediawiki.ui/mixins.less
new file mode 100644 (file)
index 0000000..ae08c9f
--- /dev/null
@@ -0,0 +1,146 @@
+// ----------------------------------------------------------------------------
+// Form styling mixins
+// ----------------------------------------------------------------------------
+
+// Font is not included.
+.agora-field-styling() {
+
+       border: 1px solid @colorFieldBorder;
+
+       &:focus {
+               // Styling focus of native checkboxes etc on Mac is almost impossible.
+               &:not([type=checkbox]):not([type=radio]) {
+                       outline: 0; // Removes OS field focus
+               }
+
+               box-shadow: lighten(@colorProgressive, 6%) 0 0 5px;
+
+               border-color: lighten(@colorProgressive, 6%);
+       }
+
+       color: @colorText;
+       padding: 0.35em 0.5em 0.35em 0.5em;
+
+       // Ensure that buttons and inputs are nicely aligned when they have differing heights
+       vertical-align: middle;
+}
+
+.agora-label-styling() {
+       font-size: 0.9em;
+       color: @colorText;
+
+       * {
+               font-weight: normal;
+       }
+}
+
+.agora-inline-label-styling() {
+       margin-bottom: 0.5em;
+       cursor: pointer;
+       vertical-align: bottom;
+       line-height: normal;
+
+       font-weight: normal;
+
+       & > input[type="checkbox"],
+       & > input[type="radio"] {
+               width: auto;
+               height: auto;
+               margin: 0 0.1em 0 0;
+               padding: 0;
+               border: 1px solid @colorFieldBorder;
+               cursor: pointer;
+       }
+}
+
+// ----------------------------------------------------------------------------
+// Button styling
+// ----------------------------------------------------------------------------
+
+.button-colors(@bgColor) {
+       background: @bgColor;
+
+       &:hover,
+       &:focus {
+               // The inner bottom bevel should match the active background color.
+               box-shadow: 0 1px rgba(0, 0, 0, 10%), inset 0 -3px rgba(0, 0, 0, 20%);
+               border-bottom-color: mix(#000, @bgColor, 20%);
+               outline: none;
+               // remove outline in Firefox
+               &::-moz-focus-inner {
+                       border-color: transparent;
+               }
+       }
+
+       &:active,
+       &.mw-ui-checked {
+               // lessphp doesn't implement shade (https://github.com/leafo/lessphp/issues/528);
+               // it passes it through, then ResourceLoader drops it.
+               // background: shade(@bgColor, 20%);
+               background: mix(#000, @bgColor, 20%);
+               box-shadow: none;
+       }
+}
+
+.button-colors(@bgColor) when (lightness(@bgColor) >= 70%) {
+       color: @colorButtonText;
+       border: 1px solid @colorGray12;
+
+       &:disabled {
+               color: @colorDisabledText;
+
+               // make sure disabled buttons don't have hover and active states
+               &:hover,
+               &:active {
+                       background: @bgColor;
+                       box-shadow: none;
+               }
+       }
+}
+
+.button-colors(@bgColor) when (lightness(@bgColor) < 70%) {
+       color: #fff;
+       // border of the same color as background so that light background and
+       // dark background buttons are the same height (only top and bottom to
+       // make box shadow on hover cover the corners too)
+       border: 1px solid @bgColor;
+       border-left: none;
+       border-right: none;
+       text-shadow: 0 1px rgba(0, 0, 0, .1);
+
+       &:disabled {
+               background: @colorGray12;
+               border-color: @colorGray12;
+
+               // make sure disabled buttons don't have hover and active states
+               &:hover,
+               &:active,
+               &.mw-ui-checked {
+                       box-shadow: none;
+               }
+       }
+}
+
+.button-colors-quiet(@textColor) {
+       // Quiet buttons all start gray, and reveal
+       // constructive/progressive/destructive color on hover and active.
+       color: @colorButtonText;
+
+       &:hover,
+       &:focus {
+               // lessphp doesn't implement tint, see above
+               // color: tint(@textColor, 20%);
+               color: mix(#fff, @textColor, 20%);
+       }
+
+       &:active,
+       &.mw-ui-checked {
+               // lessphp doesn't implement shade, see above
+               // color: shade(@textColor, 20%);
+               color: mix(#000, @textColor, 20%);
+       }
+
+       &:disabled {
+               color: @colorDisabledText;
+       }
+}
diff --git a/resources/src/mediawiki.less/mediawiki.ui/variables.less b/resources/src/mediawiki.less/mediawiki.ui/variables.less
new file mode 100644 (file)
index 0000000..8a2741d
--- /dev/null
@@ -0,0 +1,59 @@
+// Colors for use in mediawiki.ui and elsewhere
+
+// Although this defines many shades, be parsimonious in your own use of grays. Prefer
+// colors already in use in MediaWiki. Prefer semantic color names such as "@colorText".
+@colorGray1: #111; // darkest
+@colorGray2: #222;
+@colorGray3: #333;
+@colorGray4: #444;
+@colorGray5: #555;
+@colorGray6: #666;
+@colorGray7: #777;
+@colorGray8: #888;
+@colorGray9: #999;
+@colorGray10: #AAA;
+@colorGray11: #BBB;
+@colorGray12: #CCC;
+@colorGray13: #DDD;
+@colorGray14: #EEE;
+@colorGray15: #F9F9F9; // lightest
+
+// Semantic background colors
+// Blue; for contextual use of a continuing action
+@colorProgressive: #347bff;
+// Green; for contextual use of a positive finalizing action
+@colorConstructive: #00af89;
+// Orange; for contextual use of returning to a past action
+@colorRegressive: #FF5D00;
+// Red; for contextual use of a negative action of high severity
+@colorDestructive: #d11d13;
+// Orange; for contextual use of a potentially negative action of medium severity
+@colorMediumSevere: #FF5D00;
+// Yellow; for contextual use of a potentially negative action of low severity
+@colorLowSevere: #FFB50D;
+
+// Used in mixins to darken contextual colors by the same amount (eg. focus)
+@colorDarkenPercentage: 13.5%;
+// Used in mixins to lighten contextual colors by the same amount (eg. hover)
+@colorLightenPercentage: 13.5%;
+
+// Text colors
+@colorText: @colorGray2;
+@colorTextLight: @colorGray6;
+@colorButtonText: @colorGray8;
+@colorDisabledText: @colorGray12;
+@colorErrorText: #CC0000;
+
+// UI colors
+@colorFieldBorder: @colorGray12;
+@colorShadow: @colorGray14;
+@colorPlaceholder: @colorGray10;
+@colorNeutral: @colorGray7;
+
+// The following rules are deprecated
+@colorWhite: #fff;
+@colorOffWhite: #fafafa;
+@colorGrayDark: #898989;
+@colorGrayLight: #ccc;
+@colorGrayLighter: #ddd;
+@colorGrayLightest: #eee;
index e7c962f..1892967 100644 (file)
@@ -2,7 +2,7 @@
  * Show gallery captions when focused. Copied directly from jquery.mw-jump.js.
  * Also Dynamically resize images to justify them.
  */
-( function ( $, mw ) {
+( function ( $ ) {
        $( function () {
                var isTouchScreen,
                        gettingFocus,
@@ -93,7 +93,6 @@
                                        $imageElm,
                                        imageElm,
                                        $caption,
-                                       hookInfo,
                                        i,
                                        j,
                                        avgZoom,
                                                }
 
                                                if ( curRow[j].aspect === 0 || !isFinite( curRow[j].aspect ) ) {
-                                                       mw.log( 'Skipping item ' + j + ' due to aspect: ' + curRow[j].aspect );
                                                        // One of the dimensions are 0. Probably should
                                                        // not try to resize.
                                                        combinedPadding += curRow[j].width;
                                                // Also on the off chance there is a bug in this
                                                // code, would prevent accidentally expanding to
                                                // be 10 billion pixels wide.
-                                               mw.log( 'mw.page.gallery: Cannot fit row, aspect is ' + preferredHeight / curRowHeight );
                                                if ( i === rows.length - 1 ) {
                                                        // If its the last row, and we can't fit it,
                                                        // don't make the entire row huge.
                                        }
                                        if ( !isFinite( preferredHeight ) ) {
                                                // This *definitely* should not happen.
-                                               mw.log( 'mw.page.gallery: Trying to resize row ' + i + ' to ' + preferredHeight + '?!' );
                                                // Skip this row.
                                                continue;
                                        }
                                        if ( preferredHeight < 5 ) {
                                                // Well something clearly went wrong...
-                                               mw.log( {
-                                                       maxWidth: maxWidth,
-                                                       combinedPadding: combinedPadding,
-                                                       combinedAspect: combinedAspect,
-                                                       wantedWidth: wantedWidth
-                                               } );
-                                               mw.log( 'mw.page.gallery: [BUG!] Fitting row ' + i + ' to too small a size: ' + preferredHeight );
                                                // Skip this row.
                                                continue;
                                        }
 
                                                if ( newWidth < 60 || !isFinite( newWidth ) ) {
                                                        // Making something skinnier than this will mess up captions,
-                                                       mw.log( 'mw.page.gallery: Tried to make image ' + newWidth + 'px wide but too narrow.' );
                                                        if ( newWidth < 1 || !isFinite( newWidth ) ) {
                                                                $innerDiv.height( preferredHeight );
                                                                // Don't even try and touch the image size if it could mean
                                                        $caption.width( curRow[j].captionWidth + ( newWidth - curRow[j].imgWidth ) );
                                                }
 
-                                               hookInfo = {
-                                                       fullWidth: newWidth + padding,
-                                                       imgWidth: newWidth,
-                                                       imgHeight: preferredHeight,
-                                                       $innerDiv: $innerDiv,
-                                                       $imageDiv: $imageDiv,
-                                                       $outerDiv: $outerDiv,
-                                                       // Whether the hook took action
-                                                       resolved: false
-                                               };
-
-                                               /**
-                                                * Gallery resize.
-                                                *
-                                                * If your handler resizes an image, it should also set the resolved
-                                                * property to true. Additionally, because this module only exposes this
-                                                * logic temporarily, you should load your module in position top to
-                                                * ensure it is registered before this runs (FIXME: Don't use mw.hook)
-                                                *
-                                                * See TimedMediaHandler for an example.
-                                                *
-                                                * @event mediawiki_page_gallery_resize
-                                                * @member mw.hook
-                                                * @param {Object} hookInfo
-                                                */
-                                               mw.hook( 'mediawiki.page.gallery.resize' ).fire( hookInfo );
-
-                                               if ( !hookInfo.resolved ) {
-                                                       if ( imageElm ) {
-                                                               // We don't always have an img, e.g. in the case of an invalid file.
-                                                               imageElm.width = newWidth;
-                                                               imageElm.height = preferredHeight;
-                                                       } else {
-                                                               // Not a file box.
-                                                               $imageDiv.height( preferredHeight );
-                                                       }
+                                               if ( imageElm ) {
+                                                       // We don't always have an img, e.g. in the case of an invalid file.
+                                                       imageElm.width = newWidth;
+                                                       imageElm.height = preferredHeight;
+                                               } else {
+                                                       // Not a file box.
+                                                       $imageDiv.height( preferredHeight );
                                                }
                                        }
                                }
                        }() );
                } );
        } );
-}( jQuery, mediaWiki ) );
+}( jQuery ) );
index ccddb3e..a05a054 100644 (file)
@@ -1,6 +1,16 @@
 ( function ( mw, $ ) {
        var supportsPlaceholder = 'placeholder' in document.createElement( 'input' );
 
+       // Break out of framesets
+       if ( mw.config.get( 'wgBreakFrames' ) ) {
+               // Note: In IE < 9 strict comparison to window is non-standard (the standard didn't exist yet)
+               // it works only comparing to window.self or window.window (http://stackoverflow.com/q/4850978/319266)
+               if ( window.top !== window.self ) {
+                       // Un-trap us from framesets
+                       window.top.location = window.location;
+               }
+       }
+
        mw.hook( 'wikipage.content' ).add( function ( $content ) {
                var $sortableTables;
 
index 15e9aba..d252f0e 100644 (file)
@@ -6,7 +6,7 @@
  */
 ( function ( mw, $ ) {
        // The name of the page to watch or unwatch
-       var title = mw.config.get( 'wgRelevantPageName', mw.config.get( 'wgPageName' ) );
+       var title = mw.config.get( 'wgRelevantPageName' );
 
        /**
         * Update the link text, link href attribute and (if applicable)
index ebd6b92..2f1b795 100644 (file)
@@ -68,6 +68,12 @@ figure[typeof*='mw:Image'] {
                float: left;
        }
 
+       &.mw-halign-none {
+               margin: 0;
+               clear: none;
+               float: none;
+       }
+
        &.mw-halign-center {
                margin: 0 auto .5em auto;
                display: table;
@@ -99,7 +105,6 @@ figure[typeof~='mw:Image/Frame'] {
        display: table;
        overflow: auto;
        text-align: center;
-       padding: 3px;
        border: 1px solid #ccc;
        border-bottom: 0; // No border to caption
        border-collapse: collapse;
@@ -115,7 +120,7 @@ figure[typeof~='mw:Image/Thumb'] > *:first-child > img,
 figure[typeof~='mw:Image/Frame'] > *:first-child > img,
 .mw-image-border > *:first-child > img {
        border: 1px solid #cccccc;
-       margin: 4px;
+       margin: 3px;
 }
 
 /* Hide the caption for frameless and plain floated images */
index a805f3e..a30a15d 100644 (file)
@@ -5,3 +5,7 @@
 label[for="mw-input-wpConfirm"] {
        font-weight: bold;
 }
+
+tr.mw-block-hideuser {
+       font-weight: bold;
+}
index 5860adf..7ac8154 100644 (file)
@@ -27,11 +27,6 @@ table.mw-allpages-table-form tr {
        vertical-align: top;
 }
 
-/* Special:Block */
-tr.mw-block-hideuser {
-       font-weight: bold;
-}
-
 /* Special:BlockList */
 table.mw-blocklist span.mw-usertoollinks,
 span.mw-blocklist-actions {
@@ -71,166 +66,6 @@ td#mw-prefixindex-nav-form {
        text-align: right;
 }
 
-
-/* Special:Search */
-.searchresults {
-}
-
-.searchresults p {
-       margin-left: 0.4em;
-       margin-top: 1em;
-       margin-bottom: 1.2em;
-}
-div.searchresult {
-       font-size: 95%;
-       width: 38em;
-}
-.mw-search-results {
-       margin-left: 0.4em;
-}
-.mw-search-results li {
-       padding-bottom: 1.2em;
-       list-style: none;
-       list-style-image: none;
-}
-.mw-search-results li a {
-       font-size: 108%;
-}
-.mw-search-result-data {
-       color: green;
-       font-size: 97%;
-}
-.mw-search-formheader {
-       background-color: #f3f3f3;
-       margin-top: 1em;
-       border: 1px solid silver;
-}
-.mw-search-formheader div.search-types {
-       float: left;
-       padding-left: 0.25em;
-}
-.mw-search-formheader div.search-types ul {
-       margin: 0 !important;
-       padding: 0 !important;
-       list-style: none !important;
-}
-.mw-search-formheader div.search-types ul li {
-       float: left;
-       margin: 0;
-       padding: 0;
-}
-.mw-search-formheader div.search-types ul li a {
-       display: block;
-       padding: 0.5em;
-}
-.mw-search-formheader div.search-types ul li.current a {
-       color: #333333;
-       cursor: default;
-}
-.mw-search-formheader div.search-types ul li.current a:hover {
-       text-decoration: none;
-}
-#mw-search-top-table div.results-info {
-       float: right;
-       padding: 0.5em;
-       padding-right: 0.75em;
-       color: #666;
-       font-size: 95%;
-}
-
-fieldset#mw-searchoptions {
-       margin: 0;
-       padding: 0.5em 0.75em 0.75em 0.75em !important;
-       border: none;
-       background-color: #f9f9f9;
-       border: 1px solid silver !important;
-       border-top-width: 0 !important;
-}
-fieldset#mw-searchoptions legend {
-       display: none;
-}
-fieldset#mw-searchoptions h4 {
-       padding: 0;
-       margin: 0;
-       float: left;
-}
-fieldset#mw-searchoptions div#mw-search-togglebox {
-       float: right;
-}
-fieldset#mw-searchoptions div#mw-search-togglebox label {
-       margin-right: 0.25em;
-}
-fieldset#mw-searchoptions div#mw-search-togglebox input {
-       margin-left: 0.25em;
-}
-fieldset#mw-searchoptions table {
-       float: left;
-       margin-right: 3em;
-}
-fieldset#mw-searchoptions table td {
-       padding-right: 1em;
-}
-fieldset#mw-searchoptions div.divider {
-       clear: both;
-       border-bottom: 1px solid #DDDDDD;
-       padding-top: 0.5em;
-       margin-bottom: 0.5em;
-}
-td#mw-search-menu {
-       padding-left:6em;
-       font-size:85%;
-}
-div#mw-search-interwiki {
-       float: right;
-       width: 18em;
-       border: 1px solid #AAAAAA;
-       margin-top: 2ex;
-}
-div#mw-search-interwiki li {
-       font-size: 95%;
-}
-.mw-search-interwiki-more {
-       float: right;
-       font-size: 90%;
-}
-div#mw-search-interwiki-caption {
-       text-align: center;
-       font-weight: bold;
-       font-size: 95%;
-}
-.mw-search-interwiki-project {
-       font-size: 97%;
-       text-align: left;
-       padding: 0.15em 0.15em 0.2em 0.2em;
-       background-color: #ececec;
-       border-top: 1px solid #BBBBBB;
-}
-span.searchalttitle {
-       font-size: 95%;
-}
-div.searchdidyoumean {
-       font-size: 127%;
-       margin-top: 0.8em;
-       /* Note that this color won't affect the link, as desired. */
-       color: #c00;
-}
-div.searchdidyoumean em {
-       font-weight: bold;
-}
-.searchmatch {
-       font-weight: bold;
-}
-/* Advanced PowerSearch box */
-td#mw-search-togglebox {
-       text-align: right;
-}
-table#mw-search-powertable {
-       width: 100%;
-}
-form#powersearch {
-       clear: both;
-}
-
 /* Special:Specialpages */
 .mw-specialpagerestricted {
        font-weight: bold;
index f6ed82c..ef95507 100644 (file)
@@ -1,3 +1,5 @@
+/* Special:Search */
+
 /*
  * Fixes sister projects box moving down the extract
  * of the first result (bug #16886).
 .searchresult {
        display: inline !ie;
 }
+.searchresults {
+}
+.searchresults p {
+       margin-left: 0.4em;
+       margin-top: 1em;
+       margin-bottom: 1.2em;
+}
+div.searchresult {
+       font-size: 95%;
+       width: 38em;
+}
+.mw-search-results {
+       margin-left: 0.4em;
+}
+.mw-search-results li {
+       padding-bottom: 1.2em;
+       list-style: none;
+       list-style-image: none;
+}
+.mw-search-results li a {
+       font-size: 108%;
+}
+.mw-search-result-data {
+       color: green;
+       font-size: 97%;
+}
+.mw-search-formheader {
+       background-color: #f3f3f3;
+       margin-top: 1em;
+       border: 1px solid silver;
+}
+.mw-search-formheader div.search-types {
+       float: left;
+       padding-left: 0.25em;
+}
+.mw-search-formheader div.search-types ul {
+       margin: 0 !important;
+       padding: 0 !important;
+       list-style: none !important;
+}
+.mw-search-formheader div.search-types ul li {
+       float: left;
+       margin: 0;
+       padding: 0;
+}
+.mw-search-formheader div.search-types ul li a {
+       display: block;
+       padding: 0.5em;
+}
+.mw-search-formheader div.search-types ul li.current a {
+       color: #333333;
+       cursor: default;
+}
+.mw-search-formheader div.search-types ul li.current a:hover {
+       text-decoration: none;
+}
+#mw-search-top-table div.results-info {
+       float: right;
+       padding: 0.5em;
+       padding-right: 0.75em;
+       color: #666;
+       font-size: 95%;
+}
+
+fieldset#mw-searchoptions {
+       margin: 0;
+       padding: 0.5em 0.75em 0.75em 0.75em !important;
+       border: none;
+       background-color: #f9f9f9;
+       border: 1px solid silver !important;
+       border-top-width: 0 !important;
+}
+fieldset#mw-searchoptions legend {
+       display: none;
+}
+fieldset#mw-searchoptions h4 {
+       padding: 0;
+       margin: 0;
+       float: left;
+}
+fieldset#mw-searchoptions div#mw-search-togglebox {
+       float: right;
+}
+fieldset#mw-searchoptions div#mw-search-togglebox label {
+       margin-right: 0.25em;
+}
+fieldset#mw-searchoptions div#mw-search-togglebox input {
+       margin-left: 0.25em;
+}
+fieldset#mw-searchoptions table {
+       float: left;
+       margin-right: 3em;
+}
+fieldset#mw-searchoptions table td {
+       padding-right: 1em;
+       white-space: nowrap;
+}
+fieldset#mw-searchoptions div.divider {
+       clear: both;
+       border-bottom: 1px solid #DDDDDD;
+       padding-top: 0.5em;
+       margin-bottom: 0.5em;
+}
+td#mw-search-menu {
+       padding-left:6em;
+       font-size:85%;
+}
+div#mw-search-interwiki {
+       float: right;
+       width: 18em;
+       border: 1px solid #AAAAAA;
+       margin-top: 2ex;
+}
+div#mw-search-interwiki li {
+       font-size: 95%;
+}
+.mw-search-interwiki-more {
+       float: right;
+       font-size: 90%;
+}
+div#mw-search-interwiki-caption {
+       text-align: center;
+       font-weight: bold;
+       font-size: 95%;
+}
+.mw-search-interwiki-project {
+       font-size: 97%;
+       text-align: left;
+       padding: 0.15em 0.15em 0.2em 0.2em;
+       background-color: #ececec;
+       border-top: 1px solid #BBBBBB;
+}
+span.searchalttitle {
+       font-size: 95%;
+}
+div.searchdidyoumean {
+       font-size: 127%;
+       margin-top: 0.8em;
+       /* Note that this color won't affect the link, as desired. */
+       color: #c00;
+}
+div.searchdidyoumean em {
+       font-weight: bold;
+}
+.searchmatch {
+       font-weight: bold;
+}
+/* Advanced PowerSearch box */
+td#mw-search-togglebox {
+       text-align: right;
+}
+table#mw-search-powertable {
+       width: 100%;
+}
+form#powersearch {
+       clear: both;
+}
diff --git a/resources/src/mediawiki.ui/components/buttons.less b/resources/src/mediawiki.ui/components/buttons.less
new file mode 100644 (file)
index 0000000..189dae8
--- /dev/null
@@ -0,0 +1,227 @@
+@import "mediawiki.mixins";
+@import "mediawiki.ui/variables";
+@import "mediawiki.ui/mixins";
+
+// Buttons
+//
+// 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
+// the button depends on what type of element is used.
+// There are two kinds of buttons, the default is a "Call to Action" with an obvious border
+// and there is a quiet kind without a border.
+//
+// Styleguide 2.
+
+@buttonBorderRadius: 3px;
+@transitionDuration: .1s;
+@transitionFunction: ease-in-out;
+
+// Neutral button styling
+//
+// Markup:
+// <button class="mw-ui-button">.mw-ui-button</button>
+// <button class="mw-ui-button" disabled>.mw-ui-button</button>
+//
+// Styleguide 2.1.
+.mw-ui-button {
+       // Container layout
+       display: inline-block;
+       padding: .5em 1em;
+       margin: 0;
+       .box-sizing(border-box);
+
+       // Disable weird iOS styling
+       -webkit-appearance: none;
+
+       // IE6/IE7 hack
+       // http://stackoverflow.com/a/5838575/365238
+       *display: inline;
+       zoom: 1;
+
+       // Container styling
+       .button-colors(#FFF);
+       border-radius: @buttonBorderRadius;
+
+       // Ensure that buttons and inputs are nicely aligned when they have differing heights
+       vertical-align: middle;
+
+       // Content styling
+       text-align: center;
+       font-weight: bold;
+
+       // Interaction styling
+       cursor: pointer;
+
+       &:disabled {
+               text-shadow: none;
+               cursor: default;
+       }
+
+       .transition(background @transitionDuration @transitionFunction, color @transitionDuration @transitionFunction, box-shadow @transitionDuration @transitionFunction;);
+
+       // Styling for specific button types
+       // -----------------------------------------
+
+       // Big buttons
+       //
+       // Not all buttons are equal. You can emphasise certain actions over others
+       // using the mw-ui-big class.
+       //
+       // Markup:
+       // <button class="mw-ui-button mw-ui-big">.mw-ui-button</button>
+       // <button class="mw-ui-button mw-ui-progressive mw-ui-big">.mw-ui-progressive</button>
+       // <button class="mw-ui-button mw-ui-constructive mw-ui-big">.mw-ui-constructive</button>
+       // <button class="mw-ui-button mw-ui-destructive mw-ui-big">.mw-ui-destructive</button>
+       //
+       // Styleguide 2.1.6.
+       &.mw-ui-big {
+               font-size: 1.3em;
+       }
+
+       // Block buttons
+       //
+       // Some buttons might need to be stacked.
+       //
+       // Markup:
+       // <button class="mw-ui-button mw-ui-block">.mw-ui-button</button>
+       // <button class="mw-ui-button mw-ui-progressive mw-ui-block">.mw-ui-progressive</button>
+       // <button class="mw-ui-button mw-ui-constructive mw-ui-block">.mw-ui-constructive</button>
+       // <button class="mw-ui-button mw-ui-destructive mw-ui-block">.mw-ui-destructive</button>
+       //
+       // Styleguide 2.1.5.
+       &.mw-ui-block {
+               display: block;
+               width: 100%;
+       }
+
+       // Progressive buttons
+       //
+       // Use progressive buttons for actions which lead to a next step in the process.
+       // .mw-ui-primary is deprecated, kept for compatibility.
+       //
+       // Markup:
+       // <button class="mw-ui-button mw-ui-progressive">.mw-ui-progressive</button>
+       // <button class="mw-ui-button mw-ui-progressive" disabled>.mw-ui-progressive</button>
+       //
+       // Styleguide 2.1.1.
+       &.mw-ui-progressive,
+       &.mw-ui-primary {
+               .button-colors(@colorProgressive);
+
+               &.mw-ui-quiet {
+                       .button-colors-quiet(@colorProgressive);
+               }
+       }
+
+       // Constructive buttons
+       //
+       // Use constructive buttons for actions which result in a final action in the process that results
+       // in a change of state.
+       // e.g. save changes button
+       //
+       // Markup:
+       // <button class="mw-ui-button mw-ui-constructive">.mw-ui-constructive</button>
+       // <button class="mw-ui-button mw-ui-constructive" disabled>.mw-ui-constructive</button>
+       //
+       // Styleguide 2.1.2.
+       &.mw-ui-constructive {
+               .button-colors(@colorConstructive);
+
+               &.mw-ui-quiet {
+                       .button-colors-quiet(@colorConstructive);
+               }
+       }
+
+       // Destructive buttons
+       //
+       // Use destructive buttons for actions which result in the destruction of data.
+       // e.g. deleting a page.
+       // This should not be used for cancel buttons.
+       //
+       // Markup:
+       // <button class="mw-ui-button mw-ui-destructive">.mw-ui-destructive</button>
+       // <button class="mw-ui-button mw-ui-destructive" disabled>.mw-ui-destructive</button>
+       //
+       // Styleguide 2.1.3.
+       &.mw-ui-destructive {
+               .button-colors(@colorDestructive);
+
+               &.mw-ui-quiet {
+                       .button-colors-quiet(@colorDestructive);
+               }
+       }
+
+       // Quiet buttons
+       //
+       // Use quiet buttons when they are less important and alongisde other progressive/destructive/progressive buttons.
+       //
+       // Markup:
+       // <button class="mw-ui-button mw-ui-quiet">.mw-ui-button</button>
+       // <button class="mw-ui-button mw-ui-constructive mw-ui-quiet">.mw-ui-constructive</button>
+       // <button class="mw-ui-button mw-ui-constructive mw-ui-quiet" disabled>.mw-ui-constructive</button>
+       // <button class="mw-ui-button mw-ui-destructive mw-ui-quiet">.mw-ui-destructive</button>
+       // <button class="mw-ui-button mw-ui-destructive mw-ui-quiet" disabled>.mw-ui-destructive</button>
+       // <button class="mw-ui-button mw-ui-progressive mw-ui-quiet">.mw-ui-progressive</button>
+       // <button class="mw-ui-button mw-ui-progressive mw-ui-quiet" disabled>.mw-ui-progressive</button>
+       //
+       // Styleguide 2.1.4.
+       &.mw-ui-quiet {
+               background: transparent;
+               border: none;
+               text-shadow: none;
+               .button-colors-quiet(@colorButtonText);
+
+               &:hover,
+               &:focus {
+                       box-shadow: none;
+               }
+
+               &:active,
+               &:disabled {
+                       background: transparent;
+               }
+       }
+}
+
+a.mw-ui-button {
+       text-decoration: none;
+
+       // This overrides an underline declaration on a:hover and a:focus in
+       // commonElements.css, which the class alone isn't specific enough to do.
+       &:hover,
+       &:focus {
+               text-decoration: none;
+       }
+}
+
+// Button groups
+//
+// Group of buttons. Make sure you clear the floating after using a mw-ui-button-group.
+//
+// Markup:
+// <div class="mw-ui-button-group">
+//   <div class="mw-ui-button">A</div>
+//   <div class="mw-ui-button">B</div>
+//   <div class="mw-ui-button">C</div>
+//   <div class="mw-ui-button">D</div>
+// </div><div style="clear:both"></div>
+//
+// Styleguide 2.2.
+.mw-ui-button-group > * {
+       border-radius: 0;
+       float: left;
+
+       &:first-child {
+               border-top-left-radius: @buttonBorderRadius;
+               border-bottom-left-radius: @buttonBorderRadius;
+       }
+
+       &:not(:first-child) {
+               border-left: none;
+       }
+
+       &:last-child{
+               border-top-right-radius: @buttonBorderRadius;
+               border-bottom-right-radius: @buttonBorderRadius;
+       }
+}
diff --git a/resources/src/mediawiki.ui/components/default/buttons.less b/resources/src/mediawiki.ui/components/default/buttons.less
deleted file mode 100644 (file)
index dce4cd0..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-@import "mediawiki.mixins";
-@import "../../settings/typography";
-@import "../../mixins/effects";
-@import "../../mixins/utilities";
-
-// Buttons
-//
-// 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
-// the button depends on what type of element is used.
-// There are two kinds of buttons, the default is a "Call to Action" with an obvious border
-// and there is a quiet kind without a border.
-//
-// Styleguide 2.
-
-@buttonBorderRadius: 3px;
-@transitionDuration: .1s;
-@transitionFunction: ease-in-out;
-
-// Neutral button styling
-//
-// Markup:
-// <button class="mw-ui-button">.mw-ui-button</button>
-// <button class="mw-ui-button" disabled>.mw-ui-button</button>
-//
-// Styleguide 2.1.
-.mw-ui-button {
-       // Container layout
-       display: inline-block;
-       padding: .5em 1em;
-       margin: 0;
-       .box-sizing(border-box);
-
-       // Disable weird iOS styling
-       -webkit-appearance: none;
-
-       // IE6/IE7 hack
-       // http://stackoverflow.com/a/5838575/365238
-       *display: inline;
-       zoom: 1;
-
-       // Container styling
-       .button-colors(@colorWhite);
-       border-radius: @buttonBorderRadius;
-
-       // Ensure that buttons and inputs are nicely aligned when they have differing heights
-       vertical-align: middle;
-
-       // Content styling
-       text-align: center;
-       font-weight: bold;
-
-       // Interaction styling
-       cursor: pointer;
-
-       &:disabled {
-               text-shadow: none;
-               cursor: default;
-       }
-
-       .transition(background @transitionDuration @transitionFunction, color @transitionDuration @transitionFunction, box-shadow @transitionDuration @transitionFunction;);
-
-       // Styling for specific button types
-       // -----------------------------------------
-
-       // Big buttons
-       //
-       // Not all buttons are equal. You can emphasise certain actions over others
-       // using the mw-ui-big class.
-       //
-       // Markup:
-       // <button class="mw-ui-button mw-ui-big">.mw-ui-button</button>
-       // <button class="mw-ui-button mw-ui-progressive mw-ui-big">.mw-ui-progressive</button>
-       // <button class="mw-ui-button mw-ui-constructive mw-ui-big">.mw-ui-constructive</button>
-       // <button class="mw-ui-button mw-ui-destructive mw-ui-big">.mw-ui-destructive</button>
-       //
-       // Styleguide 2.1.6.
-       &.mw-ui-big {
-               font-size: @baseFontSize * 1.3;
-       }
-
-       // Block buttons
-       //
-       // Some buttons might need to be stacked.
-       //
-       // Markup:
-       // <button class="mw-ui-button mw-ui-block">.mw-ui-button</button>
-       // <button class="mw-ui-button mw-ui-progressive mw-ui-block">.mw-ui-progressive</button>
-       // <button class="mw-ui-button mw-ui-constructive mw-ui-block">.mw-ui-constructive</button>
-       // <button class="mw-ui-button mw-ui-destructive mw-ui-block">.mw-ui-destructive</button>
-       //
-       // Styleguide 2.1.5.
-       &.mw-ui-block {
-               display: block;
-               width: 100%;
-       }
-
-       // Progressive buttons
-       //
-       // Use progressive buttons for actions which lead to a next step in the process.
-       // .mw-ui-primary is deprecated, kept for compatibility.
-       //
-       // Markup:
-       // <button class="mw-ui-button mw-ui-progressive">.mw-ui-progressive</button>
-       // <button class="mw-ui-button mw-ui-progressive" disabled>.mw-ui-progressive</button>
-       //
-       // Styleguide 2.1.1.
-       &.mw-ui-progressive,
-       &.mw-ui-primary {
-               .button-colors(@colorProgressive);
-
-               &.mw-ui-quiet {
-                       .button-colors-quiet(@colorProgressive);
-               }
-       }
-
-       // Constructive buttons
-       //
-       // Use constructive buttons for actions which result in a final action in the process that results
-       // in a change of state.
-       // e.g. save changes button
-       //
-       // Markup:
-       // <button class="mw-ui-button mw-ui-constructive">.mw-ui-constructive</button>
-       // <button class="mw-ui-button mw-ui-constructive" disabled>.mw-ui-constructive</button>
-       //
-       // Styleguide 2.1.2.
-       &.mw-ui-constructive {
-               .button-colors(@colorConstructive);
-
-               &.mw-ui-quiet {
-                       .button-colors-quiet(@colorConstructive);
-               }
-       }
-
-       // Destructive buttons
-       //
-       // Use destructive buttons for actions which result in the destruction of data.
-       // e.g. deleting a page.
-       // This should not be used for cancel buttons.
-       //
-       // Markup:
-       // <button class="mw-ui-button mw-ui-destructive">.mw-ui-destructive</button>
-       // <button class="mw-ui-button mw-ui-destructive" disabled>.mw-ui-destructive</button>
-       //
-       // Styleguide 2.1.3.
-       &.mw-ui-destructive {
-               .button-colors(@colorDestructive);
-
-               &.mw-ui-quiet {
-                       .button-colors-quiet(@colorDestructive);
-               }
-       }
-
-       // Quiet buttons
-       //
-       // Use quiet buttons when they are less important and alongisde other progressive/destructive/progressive buttons.
-       //
-       // Markup:
-       // <button class="mw-ui-button mw-ui-quiet">.mw-ui-button</button>
-       // <button class="mw-ui-button mw-ui-constructive mw-ui-quiet">.mw-ui-constructive</button>
-       // <button class="mw-ui-button mw-ui-constructive mw-ui-quiet" disabled>.mw-ui-constructive</button>
-       // <button class="mw-ui-button mw-ui-destructive mw-ui-quiet">.mw-ui-destructive</button>
-       // <button class="mw-ui-button mw-ui-destructive mw-ui-quiet" disabled>.mw-ui-destructive</button>
-       // <button class="mw-ui-button mw-ui-progressive mw-ui-quiet">.mw-ui-progressive</button>
-       // <button class="mw-ui-button mw-ui-progressive mw-ui-quiet" disabled>.mw-ui-progressive</button>
-       //
-       // Styleguide 2.1.4.
-       &.mw-ui-quiet {
-               background: transparent;
-               border: none;
-               text-shadow: none;
-               .button-colors-quiet(@colorGrayDark);
-
-               &:hover,
-               &:focus {
-                       box-shadow: none;
-               }
-
-               &:active,
-               &:disabled {
-                       background: transparent;
-               }
-       }
-}
-
-a.mw-ui-button {
-       text-decoration: none;
-
-       // This overrides an underline declaration on a:hover and a:focus in
-       // commonElements.css, which the class alone isn't specific enough to do.
-       &:hover,
-       &:focus {
-               text-decoration: none;
-       }
-}
-
-// Button groups
-//
-// Group of buttons. Make sure you clear the floating after using a mw-ui-button-group.
-//
-// Markup:
-// <div class="mw-ui-button-group">
-//   <div class="mw-ui-button">A</div>
-//   <div class="mw-ui-button">B</div>
-//   <div class="mw-ui-button">C</div>
-//   <div class="mw-ui-button">D</div>
-// </div><div style="clear:both"></div>
-//
-// Styleguide 2.2.
-.mw-ui-button-group > * {
-       border-radius: 0;
-       float: left;
-
-       &:first-child {
-               border-top-left-radius: @buttonBorderRadius;
-               border-bottom-left-radius: @buttonBorderRadius;
-       }
-
-       &:not(:first-child) {
-               border-left: none;
-       }
-
-       &:last-child{
-               border-top-right-radius: @buttonBorderRadius;
-               border-bottom-right-radius: @buttonBorderRadius;
-       }
-}
diff --git a/resources/src/mediawiki.ui/components/default/forms.less b/resources/src/mediawiki.ui/components/default/forms.less
deleted file mode 100644 (file)
index 6c40c26..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-// Form elements and layouts
-
-@import "mediawiki.mixins";
-@import "../../mixins/utilities";
-@import "../../mixins/forms";
-
-// --------------------------------------------------------------------------
-// Layouts
-// --------------------------------------------------------------------------
-
-// The FancyCaptcha image CAPTCHA used on WMF wikis drives the width of the
-// 'VForm' design, the form can't be narrower than this.
-@captchaContainerWidth: 290px;
-@defaultFormWidth: @captchaContainerWidth;
-
-// Forms
-//
-// Styleguide 3.
-
-// VForm
-//
-// Style a compact vertical stacked form ("VForm") and the elements in divs
-// within it. See button section on guidance of how and when to use mw-ui-constructive.
-//
-// Markup:
-// <form class="mw-ui-vform">
-//   <div class="mw-ui-vform-field">This is a form example.</div>
-//   <div class="mw-ui-vform-field">
-//     <label>Username </label>
-//     <input value="input">
-//   </div>
-//   <div class="mw-ui-vform-field">
-//     <button class="mw-ui-button mw-ui-constructive">Button in vform</button>
-//   </div>
-// </form>
-//
-// Styleguide 3.1.
-.mw-ui-vform {
-       .box-sizing(border-box);
-
-       width: @defaultFormWidth;
-
-       // MW currently doesn't use the type attribute everywhere on inputs.
-       input,
-       select,
-       .mw-ui-button {
-               display: block;
-               .box-sizing(border-box);
-               margin: 0;
-               width: 100%;
-       }
-
-       // We exclude buttons because they'll generally use mw-ui-button.
-       // Otherwise, we'll unintentionally override that.
-       input:not([type=button]):not([type=submit]):not([type=file]) {
-               .agora-field-styling(); // mixins/forms.less
-       }
-
-       // Give dropdown lists the same spacing as input fields for consistency.
-       // Values taken from .agora-field-styling() in mixins/form.less
-       select {
-               padding: 0.35em 0.5em 0.35em 0.5em;
-               vertical-align: middle;
-       }
-
-       label {
-               display: block;
-               .box-sizing(border-box);
-               .agora-label-styling();
-               width: auto;
-               margin: 0 0 0.2em;
-               padding: 0;
-       }
-
-       // Override input styling just for checkboxes and radio inputs.
-       input[type="checkbox"],
-       input[type="radio"] {
-               display: inline;
-               .box-sizing(content-box);
-               width: auto;
-       }
-
-
-       // Styles for information boxes
-       //
-       // Regular HTMLForm uses .error class, some special pages like
-       // SpecialUserlogin (login and create account) use .errorbox.
-       //
-       // Markup:
-       // <form class="mw-ui-vform">
-       //   <div class="errorbox">An error occurred</div>
-       //   <div class="warningbox">A warning to be noted</div>
-       //   <div class="successbox">Action successful!</div>
-       //   <div class="error">A different kind of error</div>
-       //   <div class="error">
-       //     <ul><li>There are problems with some of your input.</li></ul>
-       //   </div>
-       //   <div class="mw-ui-vform-field">
-       //     <input type="text" value="input" class="mw-ui-input">
-       //   </div>
-       //   <div class="mw-ui-vform-field">
-       //     <select>
-       //       <option value="1">Option 1</option>
-       //       <option value="2">Option 2</option>
-       //     </select>
-       //     <span class="error">The value you specified is not a valid option.</span>
-       //   </div>
-       //   <div class="mw-ui-vform-field">
-       //     <button class="mw-ui-button">Button in vform</button>
-       //   </div>
-       // </form>
-       //
-       // Styleguide 3.1.
-       .error,
-       .errorbox,
-       .warningbox,
-       .successbox {
-               .box-sizing(border-box);
-               font-size: 0.9em;
-               margin: 0 0 1em 0;
-               padding: 0.5em;
-               word-wrap: break-word;
-       }
-
-       // Colours taken from those for .errorbox in skins/common/shared.css
-       .error {
-               color: #cc0000;
-               border: 1px solid #fac5c5;
-               background-color: #fae3e3;
-               text-shadow: 0 1px #fae3e3;
-       }
-
-       // This specifies styling for individual field validation error messages.
-       // Show them below the fields to prevent line break glitches, and leave
-       // some space between the field and the error message box.
-       .mw-ui-vform-div .error, /* for backwards-compatibility, remove before 1.24 */
-       .mw-ui-vform-field .error {
-               display: block;
-               margin-top: 5px;
-       }
-
-}
-
-// --------------------------------------------------------------------------
-// Elements
-// --------------------------------------------------------------------------
-
-// A wrapper for a single form field: the <input> / <select> / <button> element,
-// help text, labels, associated error/warning/success messages, and so on.
-// Elements with this class are generated by HTMLFormField in core MediaWiki.
-//
-// (We use a broad definition of 'field' here: a purely textual information
-// block is also a "field".)
-.mw-ui-vform-div, /* for backwards-compatibility, remove before 1.24 */
-.mw-ui-vform-field {
-       display: block;
-       margin: 0 0 15px;
-       padding: 0;
-       width: 100%;
-}
-
-// Apply mw-ui-input to individual input fields to style them.
-// You generally don't need to use this class if <input> is within an Agora
-// form container such as mw-ui-vform
-.mw-ui-input {
-       .agora-field-styling(); // mixins/forms.less
-}
-
-// Apply mw-ui-label to individual elements to style them.
-// You generally don't need to use this class if <label> is within an Agora
-// form container such as mw-ui-vform
-.mw-ui-label {
-       .agora-label-styling(); // mixins/forms.less
-}
-
-// Nesting an input checkbox or radio button inside a label with this class
-// improves alignment, e.g.
-//     <label class="mw-ui-checkbox-label">
-//             <input type="checkbox">The label text
-//     </label>
-.mw-ui-checkbox-label, .mw-ui-radio-label {
-       .agora-inline-label-styling();
-}
diff --git a/resources/src/mediawiki.ui/components/forms.less b/resources/src/mediawiki.ui/components/forms.less
new file mode 100644 (file)
index 0000000..2e586a6
--- /dev/null
@@ -0,0 +1,190 @@
+// Form elements and layouts
+
+@import "mediawiki.mixins";
+@import "mediawiki.ui/variables";
+@import "mediawiki.ui/mixins";
+
+// --------------------------------------------------------------------------
+// Layouts
+// --------------------------------------------------------------------------
+
+// The FancyCaptcha image CAPTCHA used on WMF wikis drives the width of the
+// 'VForm' design, the form can't be narrower than this.
+@captchaContainerWidth: 290px;
+@defaultFormWidth: @captchaContainerWidth;
+
+// Forms
+//
+// Styleguide 3.
+
+// VForm
+//
+// Style a compact vertical stacked form ("VForm") and the elements in divs
+// within it. See button section on guidance of how and when to use mw-ui-constructive.
+//
+// Markup:
+// <form class="mw-ui-vform">
+//   <div class="mw-ui-vform-field">This is a form example.</div>
+//   <div class="mw-ui-vform-field">
+//     <label>Username </label>
+//     <input value="input">
+//   </div>
+//   <div class="mw-ui-vform-field">
+//     <button class="mw-ui-button mw-ui-constructive">Button in vform</button>
+//   </div>
+// </form>
+//
+// Styleguide 3.1.
+.mw-ui-vform {
+       .box-sizing(border-box);
+
+       width: @defaultFormWidth;
+
+       // MW currently doesn't use the type attribute everywhere on inputs.
+       input,
+       select,
+       .mw-ui-button {
+               display: block;
+               .box-sizing(border-box);
+               margin: 0;
+               width: 100%;
+       }
+
+       // We exclude buttons because they'll generally use mw-ui-button.
+       // Otherwise, we'll unintentionally override that.
+       input:not([type=button]):not([type=submit]):not([type=file]) {
+               .agora-field-styling(); // mixins/forms.less
+       }
+
+       // Give dropdown lists the same spacing as input fields for consistency.
+       // Values taken from .agora-field-styling() in mixins/form.less
+       select {
+               padding: 0.35em 0.5em 0.35em 0.5em;
+               vertical-align: middle;
+       }
+
+       label {
+               display: block;
+               .box-sizing(border-box);
+               .agora-label-styling();
+               width: auto;
+               margin: 0 0 0.2em;
+               padding: 0;
+       }
+
+       // Override input styling just for checkboxes and radio inputs.
+       input[type="checkbox"],
+       input[type="radio"] {
+               display: inline;
+               .box-sizing(content-box);
+               width: auto;
+       }
+
+
+       // Styles for information boxes
+       //
+       // Regular HTMLForm uses .error class, some special pages like
+       // SpecialUserlogin (login and create account) use .errorbox.
+       //
+       // Markup:
+       // <form class="mw-ui-vform">
+       //   <div class="errorbox">An error occurred</div>
+       //   <div class="warningbox">A warning to be noted</div>
+       //   <div class="successbox">Action successful!</div>
+       //   <div class="error">A different kind of error</div>
+       //   <div class="error">
+       //     <ul><li>There are problems with some of your input.</li></ul>
+       //   </div>
+       //   <div class="mw-ui-vform-field">
+       //     <input type="text" value="input" class="mw-ui-input">
+       //   </div>
+       //   <div class="mw-ui-vform-field">
+       //     <select>
+       //       <option value="1">Option 1</option>
+       //       <option value="2">Option 2</option>
+       //     </select>
+       //     <span class="error">The value you specified is not a valid option.</span>
+       //   </div>
+       //   <div class="mw-ui-vform-field">
+       //     <button class="mw-ui-button">Button in vform</button>
+       //   </div>
+       // </form>
+       //
+       // Styleguide 3.1.
+       .error,
+       .errorbox,
+       .warningbox,
+       .successbox {
+               .box-sizing(border-box);
+               font-size: 0.9em;
+               margin: 0 0 1em 0;
+               padding: 0.5em;
+               word-wrap: break-word;
+       }
+
+       // Colours taken from those for .errorbox in skins/common/shared.css
+       .error {
+               color: #cc0000;
+               border: 1px solid #fac5c5;
+               background-color: #fae3e3;
+               text-shadow: 0 1px #fae3e3;
+       }
+
+       // This specifies styling for individual field validation error messages.
+       // Show them below the fields to prevent line break glitches, and leave
+       // some space between the field and the error message box.
+       .mw-ui-vform-div .error, /* for backwards-compatibility, remove before 1.24 */
+       .mw-ui-vform-field .error {
+               display: block;
+               margin-top: 5px;
+       }
+
+}
+
+// --------------------------------------------------------------------------
+// Elements
+// --------------------------------------------------------------------------
+
+// A wrapper for a single form field: the <input> / <select> / <button> element,
+// help text, labels, associated error/warning/success messages, and so on.
+// Elements with this class are generated by HTMLFormField in core MediaWiki.
+//
+// (We use a broad definition of 'field' here: a purely textual information
+// block is also a "field".)
+.mw-ui-vform-div, /* for backwards-compatibility, remove before 1.24 */
+.mw-ui-vform-field {
+       display: block;
+       margin: 0 0 15px;
+       padding: 0;
+       width: 100%;
+
+       input {
+               font-size: 1em;
+               line-height: 1.4;
+       }
+}
+
+// Apply mw-ui-input to individual input fields to style them.
+// You generally don't need to use this class if <input> is within an Agora
+// form container such as mw-ui-vform
+.mw-ui-input {
+       .agora-field-styling(); // mixins/forms.less
+       font-size: 1em;
+       line-height: 1.4em;
+}
+
+// Apply mw-ui-label to individual elements to style them.
+// You generally don't need to use this class if <label> is within an Agora
+// form container such as mw-ui-vform
+.mw-ui-label {
+       .agora-label-styling(); // mixins/forms.less
+}
+
+// Nesting an input checkbox or radio button inside a label with this class
+// improves alignment, e.g.
+//     <label class="mw-ui-checkbox-label">
+//             <input type="checkbox">The label text
+//     </label>
+.mw-ui-checkbox-label, .mw-ui-radio-label {
+       .agora-inline-label-styling();
+}
index 9aea429..ccfb677 100644 (file)
@@ -1,19 +1,55 @@
-// Generic helper classes that could be used in many elements/layouts
-
-// --------------------------------------------------------------------------
-// Positioning
-// --------------------------------------------------------------------------
-
-@import "../mixins/utilities";
+// Utilities
+//
+// Other things which effect the behaviour of components
+//
+// Styleguide 4.
 
+// Flush left
+//
+// Used when you want to push an element to the left of its containing element
+//
+// Markup:
+// <div class="mw-ui-vform-field">
+//   <label>Username <a href="#" class="mw-ui-flush-left">?</a></label>
+//   <input>
+// </div>
+//
+// Styleguide 4.1.
 .mw-ui-flush-left {
-       .agora-flush-left();
+       float: left;
+       margin-left: 0;
+       padding-left: 0;
 }
 
+// Flush right
+//
+// Used when you want to push an element to the right of its containing element
+//
+// Markup:
+// <div class="mw-ui-vform-field">
+//   <label>Username <a href="#" class="mw-ui-flush-right">?</a></label>
+//   <input>
+// </div>
+//
+// Styleguide 4.2.
 .mw-ui-flush-right {
-       .agora-flush-right();
+       float: right;
+       padding-right: 0;
+       margin-right: 0;
 }
 
+// Center block
+//
+// Centers the element in its containing element
+//
+// Markup:
+// <div>
+//   <button class="mw-ui-center-block">click me</button>
+// </div>
+//
+// Styleguide 4.3.
 .mw-ui-center-block {
-       .agora-center-block();
+       display: block;
+       margin-left: auto;
+       margin-right: auto;
 }
diff --git a/resources/src/mediawiki.ui/components/vector/buttons.less b/resources/src/mediawiki.ui/components/vector/buttons.less
deleted file mode 100644 (file)
index 1536338..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-@import "../default/buttons"; // Layer Vector on top of the default settings.
-@import "../../mixins/type";
-
-.mw-ui-button {
-       .vector-type();
-}
diff --git a/resources/src/mediawiki.ui/components/vector/containers.less b/resources/src/mediawiki.ui/components/vector/containers.less
deleted file mode 100644 (file)
index 1e9ec05..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// No default settings for containers yet.
-@import "../../mixins/type";
-
-.mw-ui-container {
-       .vector-type();
-}
diff --git a/resources/src/mediawiki.ui/components/vector/forms.less b/resources/src/mediawiki.ui/components/vector/forms.less
deleted file mode 100644 (file)
index 2bbd8f0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-@import "../default/forms"; // Layer Vector on top of the default settings.
-@import "../../mixins/type";
-
-.mw-ui-vform,
-.mw-ui-vform input,
-.mw-ui-input {
-       .vector-type();
-}
index e576937..d21b814 100644 (file)
@@ -1,7 +1,6 @@
 /**
- * Provide Agora appearance for mw-ui-* classes when using a skin other than
- * Vector.
+ * Provide Agora appearance for mw-ui-* classes.
  */
 
+@import "components/forms";
 @import "components/utilities";
-@import "components/default/forms";
diff --git a/resources/src/mediawiki.ui/mixins/effects.less b/resources/src/mediawiki.ui/mixins/effects.less
deleted file mode 100644 (file)
index 9759f63..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-@import "../settings/colors";
-// ----------------------------------------------------------------------------
-// Button styling
-// ----------------------------------------------------------------------------
-
-.button-colors(@bgColor) {
-       background: @bgColor;
-
-       &:hover,
-       &:focus {
-               // The inner bottom bevel should match the active background color.
-               box-shadow: 0 1px rgba(0, 0, 0, 10%), inset 0 -3px rgba(0, 0, 0, 20%);
-               border-bottom-color: mix(#000, @bgColor, 20%);
-               outline: none;
-               // remove outline in Firefox
-               &::-moz-focus-inner {
-                       border-color: transparent;
-               }
-       }
-
-       &:active,
-       &.mw-ui-checked {
-               // lessphp doesn't implement shade (https://github.com/leafo/lessphp/issues/528);
-               // it passes it through, then ResourceLoader drops it.
-               // background: shade(@bgColor, 20%);
-               background: mix(#000, @bgColor, 20%);
-               box-shadow: none;
-       }
-}
-
-.button-colors(@bgColor) when (lightness(@bgColor) >= 70%) {
-       color: @colorGrayDark;
-       border: 1px solid @colorGrayLight;
-
-       &:disabled {
-               color: @colorGrayLight;
-
-               // make sure disabled buttons don't have hover and active states
-               &:hover,
-               &:active {
-                       background: @bgColor;
-                       box-shadow: none;
-               }
-       }
-}
-
-.button-colors(@bgColor) when (lightness(@bgColor) < 70%) {
-       color: @colorWhite;
-       // border of the same color as background so that light background and
-       // dark background buttons are the same height (only top and bottom to
-       // make box shadow on hover cover the corners too)
-       border: 1px solid @bgColor;
-       border-left: none;
-       border-right: none;
-       text-shadow: 0 1px rgba(0, 0, 0, .1);
-
-       &:disabled {
-               background: @colorGrayLight;
-               border-color: @colorGrayLight;
-
-               // make sure disabled buttons don't have hover and active states
-               &:hover,
-               &:active,
-               &.mw-ui-checked {
-                       box-shadow: none;
-               }
-       }
-}
-
-.button-colors-quiet(@textColor) {
-       // Quiet buttons all start gray, and reveal
-       // constructive/progressive/destructive color on hover and active.
-       color: @colorGrayDark;
-
-       &:hover,
-       &:focus {
-               // lessphp doesn't implement tint, see above
-               // color: tint(@textColor, 20%);
-               color: mix(#fff, @textColor, 20%);
-       }
-
-       &:active,
-       &.mw-ui-checked {
-               // lessphp doesn't implement shade, see above
-               // color: shade(@textColor, 20%);
-               color: mix(#000, @textColor, 20%);
-       }
-
-       &:disabled {
-               color: @colorGrayLight;
-       }
-}
diff --git a/resources/src/mediawiki.ui/mixins/forms.less b/resources/src/mediawiki.ui/mixins/forms.less
deleted file mode 100644 (file)
index 20f42a0..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-@import "../settings/colors";
-
-// Font is not included.
-// For Vector, that should be layered on top with vector-type
-.agora-field-styling() {
-
-       border: 1px solid @colorGrayLight;
-
-       &:focus {
-               // Styling focus of native checkboxes etc on Mac is almost impossible.
-               &:not([type=checkbox]):not([type=radio]) {
-                       outline: 0; // Removes OS field focus
-               }
-
-               box-shadow: @colorProgressiveShadow 0 0 5px;
-
-               border-color: @colorProgressiveShadow;
-       }
-
-       color: @colorText;
-       padding: 0.35em 0.5em 0.35em 0.5em;
-
-       // Ensure that buttons and inputs are nicely aligned when they have differing heights
-       vertical-align: middle;
-}
-
-.agora-label-styling() {
-       //font-weight: bold;
-       font-size: 0.9em;
-       color: darken(@colorGrayLight, 50%);
-
-       * {
-               font-weight: normal;
-       }
-}
-
-.agora-inline-label-styling() {
-       margin-bottom: 0.5em;
-       cursor: pointer;
-       vertical-align: bottom;
-       line-height: normal;
-
-       font-weight: normal;
-
-       & > input[type="checkbox"],
-       & > input[type="radio"] {
-               width: auto;
-               height: auto;
-               margin: 0 0.1em 0 0;
-               padding: 0;
-               border: 1px solid @colorGrayLight;
-               cursor: pointer;
-       }
-}
diff --git a/resources/src/mediawiki.ui/mixins/type.less b/resources/src/mediawiki.ui/mixins/type.less
deleted file mode 100644 (file)
index 4a01168..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-@import "../settings/typography";
-
-.vector-type() {
-       font-size: @baseFontSize;
-       line-height: @baseLineHeight;
-}
diff --git a/resources/src/mediawiki.ui/mixins/utilities.less b/resources/src/mediawiki.ui/mixins/utilities.less
deleted file mode 100644 (file)
index 3d7b732..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-.agora-flush-left() {
-       float: left;
-       margin-left: 0;
-       padding-left: 0;
-}
-
-.agora-flush-right() {
-       float: right;
-       margin-right: 0;
-       padding-right: 0;
-}
-
-.agora-center-block() {
-       display: block;
-       margin-left: auto;
-       margin-right: auto;
-}
diff --git a/resources/src/mediawiki.ui/settings/colors.less b/resources/src/mediawiki.ui/settings/colors.less
deleted file mode 100644 (file)
index d456f86..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// FIXME: remove @colorProgressiveShadow (shadows should be generated
-// in LESS by dimming the original colors)
-@colorProgressiveShadow: #4091ed;
-
-// White; for background use, and text use on dark backgrounds
-@colorWhite: #fff;
-// Off-white; for background use on white backgrounds
-@colorOffWhite: #fafafa;
-// Dark gray; for non-text use
-@colorGrayDark: #898989;
-// Light gray; for non-text use
-@colorGrayLight: #ccc;
-// Very light gray; for non-text use
-@colorGrayLighter: #ddd;
-// Lightest gray; for non-text use
-@colorGrayLightest: #eee;
-
-// Dark gray; for body text
-@colorText: #252525;
-// Light gray; for less important body text and links
-@colorTextLight: #696969;
-
-// Blue; for contextual use of a continuing action
-@colorProgressive: #347bff;
-// Orange; for contextual use of returning to a past action
-@colorRegressive: #ff7e1e;
-// Green; for contextual use of a positive finalizing action
-@colorConstructive: #00af89;
-// Red; for contextual use of a negative finalizing action
-@colorDestructive: #d11d13;
-
-// Used in mixins to darken contextual colors by the same amount (eg. focus)
-@colorDarkenPercentage: 13.5%;
-// Used in mixins to lighten contextual colors by the same amount (eg. hover)
-@colorLightenPercentage: 13.5%;
\ No newline at end of file
diff --git a/resources/src/mediawiki.ui/settings/typography.less b/resources/src/mediawiki.ui/settings/typography.less
deleted file mode 100644 (file)
index 83651ed..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-@baseFontSize: 1em;
-@baseLineHeight: 1.4 * @baseFontSize;
-@baseFontColor: @colorText;
-
-@smallFontSize: 0.75em;
diff --git a/resources/src/mediawiki.ui/vector.less b/resources/src/mediawiki.ui/vector.less
deleted file mode 100644 (file)
index 04e88e8..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Provide Agora appearance for mw-ui-* classes when using the Vector skin.
- */
-
-// Typography
-//
-// We prefer the usage of Georgia Bold for all headings. Georgia Regular is used to place emphasis on pull-out or short quotations. This latter usage should be used sparingly. 
-//
-// We prefer the use of Helvetica Neue Regular for body copy. Helvetiva Neue Bold for sub-headers. Pull-out quotes within the body copy should use Helvetica Neue Bold. Helvetica Neue is an not open-source font. Hence, below is a list of preferred alternate choices.
-//
-// Second choice: Helvetica
-//
-// Third choice: Arial
-//
-// Wiki content is often predominantly text; hence, visual hierarchy must be clear. Use these recommended type sizes to inform and establish information hierarchy and organization.
-//
-// Unless if you plan to put extra attention and manually adjust spacing, avoid justifying texts and paragraphs as they are harder to read and create unnecessary visual distractions. Along with centered text, they convey a formal and less friendly environment. 
-//
-// It will be important to talk about other languages, scripts and writing direction - with the same level as importance, not as an afterthought.
-//
-// Styleguide 1.
-
-@import "mediawiki.mixins";
-@import "components/utilities";
-@import "components/vector/forms";
-@import "components/vector/containers";
index 6533db1..1c0d833 100644 (file)
         * dialog box. Submitting that dialog box appends its contents to a
         * wiki page that you specify, as a new section.
         *
-        * Not compatible with LiquidThreads.
+        * This feature works with classic MediaWiki pages
+        * and is not compatible with LiquidThreads or Flow.
         *
-        * Minimal example in how to use it:
+        * Minimal usage example:
         *
         *     var feedback = new mw.Feedback();
         *     $( '#myButton' ).click( function () { feedback.launch(); } );
                                                                $feedbackPageLink.clone()
                                                        )
                                                ),
-                                               $( '<div style="margin-top: 1em;"></div>' ).append(
-                                                       mw.msg( 'feedback-subject' ),
+                                               $( '<div style="margin-top: 1em;"></div>' )
+                                               .msg( 'feedback-subject' )
+                                               .append(
                                                        $( '<br>' ),
                                                        $( '<input type="text" class="feedback-subject" name="subject" maxlength="60" style="width: 100%; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;"/>' )
                                                ),
-                                               $( '<div style="margin-top: 0.4em;"></div>' ).append(
-                                                       mw.msg( 'feedback-message' ),
+                                               $( '<div style="margin-top: 0.4em;"></div>' )
+                                               .msg( 'feedback-message' )
+                                               .append(
                                                        $( '<br>' ),
                                                        $( '<textarea name="message" class="feedback-message" rows="5" cols="60"></textarea>' )
                                                )
                                        $( '<div class="feedback-mode feedback-bugs"></div>' ).append(
                                                $( '<p>' ).msg( 'feedback-bugcheck', $bugsListLink )
                                        ),
-                                       $( '<div class="feedback-mode feedback-submitting" style="text-align: center; margin: 3em 0;"></div>' ).append(
-                                               mw.msg( 'feedback-adding' ),
+                                       $( '<div class="feedback-mode feedback-submitting" style="text-align: center; margin: 3em 0;"></div>' )
+                                       .msg( 'feedback-adding' )
+                                       .append(
                                                $( '<br>' ),
                                                $( '<span class="feedback-spinner"></span>' )
                                        ),
                                        )
                                );
 
-                               // undo some damage from dialog css
-                               this.$dialog.find( 'a' ).css( {
-                                       color: '#0645ad'
-                               } );
-
-                               this.$dialog.dialog( {
-                                       width: 500,
-                                       autoOpen: false,
-                                       title: mw.msg( this.dialogTitleMessageKey ),
-                                       modal: true,
-                                       buttons: fb.buttons
-                               } );
+                       this.$dialog.dialog( {
+                               width: 500,
+                               autoOpen: false,
+                               title: mw.message( this.dialogTitleMessageKey ).escaped(),
+                               modal: true,
+                               buttons: fb.buttons
+                       } );
 
                        this.subjectInput = this.$dialog.find( 'input.feedback-subject' ).get( 0 );
                        this.messageInput = this.$dialog.find( 'textarea.feedback-message' ).get( 0 );
-
                },
 
                /**
                displayBugs: function () {
                        var fb = this,
                                bugsButtons = {};
+
                        this.display( 'bugs' );
                        bugsButtons[ mw.msg( 'feedback-bugnew' ) ] = function () {
                                window.open( fb.bugsLink, '_blank' );
                displayThanks: function () {
                        var fb = this,
                                closeButton = {};
+
                        this.display( 'thanks' );
                        closeButton[ mw.msg( 'feedback-close' ) ] = function () {
                                fb.$dialog.dialog( 'close' );
                displayForm: function ( contents ) {
                        var fb = this,
                                formButtons = {};
+
                        this.subjectInput.value = ( contents && contents.subject ) ? contents.subject : '';
                        this.messageInput.value = ( contents && contents.message ) ? contents.message : '';
 
                displayError: function ( message ) {
                        var fb = this,
                                closeButton = {};
+
                        this.display( 'error' );
                        this.$dialog.find( '.feedback-error-msg' ).msg( message );
                        closeButton[ mw.msg( 'feedback-close' ) ] = function () {
                        var subject, message,
                                fb = this;
 
-                       function ok( result ) {
+                       // Get the values to submit.
+                       subject = this.subjectInput.value;
+
+                       // We used to include "mw.html.escape( navigator.userAgent )" but there are legal issues
+                       // with posting this without their explicit consent
+                       message = this.messageInput.value;
+                       if ( message.indexOf( '~~~' ) === -1 ) {
+                               message += ' ~~~~';
+                       }
+
+                       this.displaySubmitting();
+
+                       // Post the message, resolving redirects
+                       this.api.newSection(
+                               this.title,
+                               subject,
+                               message,
+                               { redirect: true }
+                       )
+                       .done( function ( result ) {
                                if ( result.edit !== undefined ) {
                                        if ( result.edit.result === 'Success' ) {
                                                fb.displayThanks();
                                        // edit failed
                                        fb.displayError( 'feedback-error2' );
                                }
-                       }
-
-                       function err() {
+                       } )
+                       .fail( function () {
                                // ajax request failed
                                fb.displayError( 'feedback-error3' );
-                       }
-
-                       // Get the values to submit.
-                       subject = this.subjectInput.value;
-
-                       // We used to include "mw.html.escape( navigator.userAgent )" but there are legal issues
-                       // with posting this without their explicit consent
-                       message = this.messageInput.value;
-                       if ( message.indexOf( '~~~' ) === -1 ) {
-                               message += ' ~~~~';
-                       }
-
-                       this.displaySubmitting();
-
-                       this.api.newSection( this.title, subject, message ).done( ok ).fail( err );
+                       } );
                },
 
                /**
                        this.$dialog.dialog( 'open' );
                        this.subjectInput.focus();
                }
-
        };
-
 }( mediaWiki, jQuery ) );
index 8be1321..9eea492 100644 (file)
@@ -15,6 +15,7 @@
         * ending in array keys matching the given name (e.g. "baz" matches
         * "foo[bar][baz]").
         *
+        * @private
         * @param {jQuery} element
         * @param {string} name
         * @return {jQuery|null}
         * Helper function for hide-if to return a test function and list of
         * dependent fields for a hide-if specification.
         *
+        * @private
         * @param {jQuery} element
         * @param {Array} hide-if spec
-        * @return {Array} 2 elements: jQuery of dependent fields, and test function
+        * @return {Array}
+        * @return {jQuery} return.0 Dependent fields
+        * @return {Function} return.1 Test function
         */
        function hideIfParse( $el, spec ) {
                var op, i, l, v, $field, $fields, fields, func, funcs, getVal;
@@ -63,7 +67,7 @@
                                                throw new Error( op + ' parameters must be arrays' );
                                        }
                                        v = hideIfParse( $el, spec[i] );
-                                       fields.push( v[0] );
+                                       fields = fields.concat( v[0].toArray() );
                                        funcs.push( v[1] );
                                }
                                $fields = $( fields );
index c1f1844..380e4e6 100644 (file)
                         * Format:
                         *     {
                         *         'moduleName': {
+                        *             // At registry
                         *             'version': ############## (unix timestamp),
                         *             'dependencies': ['required.foo', 'bar.also', ...], (or) function () {}
                         *             'group': 'somegroup', (or) null,
                         *             'source': 'local', 'someforeignwiki', (or) null
                         *             'state': 'registered', 'loaded', 'loading', 'ready', 'error' or 'missing'
+                        *             'skip': 'return !!window.Example', (or) null
+                        *
+                        *             // Added during implementation
+                        *             'skipped': true,
                         *             'script': ...,
                         *             'style': ...,
                         *             'messages': { 'key': 'value' },
                        /* Private methods */
 
                        function getMarker() {
-                               // Cached ?
-                               if ( $marker ) {
-                                       return $marker;
-                               }
-
-                               $marker = $( 'meta[name="ResourceLoaderDynamicStyles"]' );
-                               if ( $marker.length ) {
-                                       return $marker;
+                               // Cached
+                               if ( !$marker ) {
+                                       $marker = $( 'meta[name="ResourceLoaderDynamicStyles"]' );
+                                       if ( !$marker.length ) {
+                                               mw.log( 'No <meta name="ResourceLoaderDynamicStyles"> found, inserting dynamically' );
+                                               $marker = $( '<meta>' ).attr( 'name', 'ResourceLoaderDynamicStyles' ).appendTo( 'head' );
+                                       }
                                }
-                               mw.log( 'getMarker> No <meta name="ResourceLoaderDynamicStyles"> found, inserting dynamically.' );
-                               $marker = $( '<meta>' ).attr( 'name', 'ResourceLoaderDynamicStyles' ).appendTo( 'head' );
-
                                return $marker;
                        }
 
                                        skip = new Function( registry[module].skip );
                                        registry[module].skip = null;
                                        if ( skip() ) {
+                                               registry[module].skipped = true;
                                                registry[module].dependencies = [];
                                                registry[module].state = 'ready';
                                                handlePending( module );
                                                } catch ( e ) {
                                                        // A user-defined callback raised an exception.
                                                        // Swallow it to protect our state machine!
-                                                       log( 'Exception thrown by job.error', e );
+                                                       log( 'Exception thrown by user callback', e );
                                                }
                                        }
                                }
                                                crossDomain: true,
                                                cache: true,
                                                async: true
-                                       } ).always( function () {
-                                               if ( callback  ) {
-                                                       callback();
-                                               }
-                                       } );
+                                       } ).always( callback );
                                } else {
                                        /*jshint evil:true */
                                        document.write( mw.html.element( 'script', { 'src': src }, '' ) );
index c5694b7..7933f1d 100644 (file)
         *
         * @private
         * @param {string} info One of 'groups' or 'rights'
-        * @param {Function} [callback]
         * @return {jQuery.Promise}
         */
-       function getUserInfo( info, callback ) {
+       function getUserInfo( info ) {
                var api;
                if ( !deferreds[info] ) {
 
@@ -42,7 +41,7 @@
 
                }
 
-               return deferreds[info].done( callback ).promise();
+               return deferreds[info].promise();
        }
 
        mw.user = user = {
                 * @return {jQuery.Promise}
                 */
                getGroups: function ( callback ) {
-                       return getUserInfo( 'groups', callback );
+                       return getUserInfo( 'groups' ).done( callback );
                },
 
                /**
                 * @return {jQuery.Promise}
                 */
                getRights: function ( callback ) {
-                       return getUserInfo( 'rights', callback );
+                       return getUserInfo( 'rights' ).done( callback );
                }
        };
 
index d007deb..5fadace 100644 (file)
@@ -4,6 +4,7 @@
                        "Xuacu"
                ]
        },
+       "monobook-desc": "El tema clásicu de MediaWiki dende 2004, llamáu asina pola foto en blanco y negro d'un llibru nel fondu de la páxina",
        "monobook.css": "/* Los CSS allugaos equí afeutarán a los usuarios del aspeutu Monobook */",
        "monobook.js": "/* Cualesquier JavaScript que tea equí se cargará pa los usuarios del aspeutu MonoBook */"
 }
index a3a20e5..684d3d3 100644 (file)
@@ -1,10 +1,12 @@
 {
        "@metadata": {
                "authors": [
-                       "Yury Tarasievich"
+                       "Yury Tarasievich",
+                       "Mikalai Udodau"
                ]
        },
        "skinname-monobook": "Манабук",
+       "monobook-desc": "Класічная вокладка MediaWiki з 2004 года, названая ў гонар чорна-белай фатаграфіі кнігі ў фоне старонкі",
        "monobook.css": "/* CSS, упісаны сюды, будзе дзейнічаць на браўзер кожнага чытача з актыўнай світай Monobook */",
        "monobook.js": "/* Any JavaScript here will be loaded for users using the MonoBook skin */"
 }
index 8674693..ba907dd 100644 (file)
@@ -1,8 +1,10 @@
 {
        "@metadata": {
                "authors": [
-                       "Martorell"
+                       "Martorell",
+                       "Toniher"
                ]
        },
+       "monobook-desc": "El tema clàssic de MediaWiki des del 2004, que rep el nom d'una foto en blanc i negre d'un llibre en el fons de la pàgina.",
        "monobook.css": "/* Editeu aquest fitxer per personalitzar l'aparença del monobook per a tot el lloc sencer */"
 }
index e20dbb6..bb7745e 100644 (file)
@@ -1,10 +1,12 @@
 {
        "@metadata": {
                "authors": [
-                       "Peter Alberti"
+                       "Peter Alberti",
+                       "Christian List"
                ]
        },
        "skinname-monobook": "MonoBook",
+       "monobook-desc": "Den klassiske MediaWiki hud siden 2004, opkaldt efter det sort-hvide foto af en bog i baggrunden af siderne",
        "monobook.css": "/** CSS inkluderet her vil være aktivt for brugere af Monobook-temaet . */",
        "monobook.js": "/* JavaScript i denne fil vil indlæses for brugere af udseendet MonoBook */"
 }
index 9792754..48d424c 100644 (file)
@@ -2,10 +2,12 @@
        "@metadata": {
                "authors": [
                        "Sanbec",
-                       "Vivaelcelta"
+                       "Vivaelcelta",
+                       "Fitoschido"
                ]
        },
        "skinname-monobook": "MonoBook",
+       "monobook-desc": "El tema clásico de MediaWiki desde 2004, cuyo nombre viene de la foto en blanco y negro de un libro en el fondo",
        "monobook.css": "/* El CSS colocado en esta página afectará a los usuarios que usen la apariencia \"MonoBook\" */",
        "monobook.js": "/* El código JavaScript que se ponga aquí será cargado por los usuarios de la apariencia MonoBook */"
 }
index 8e278d3..02a0185 100644 (file)
@@ -1,4 +1,10 @@
 {
+       "@metadata": {
+               "authors": [
+                       "Reza1615"
+               ]
+       },
        "skinname-monobook": "مونوبوک",
+       "monobook-desc": "پوسته کلاسیک مدیاویکی از سال ۲۰۰۴ از عکس سیاه و سفید در زمینه صفحه  کتاب نام گرفت",
        "monobook.css": "/* دستورات این بخش کاربرانی را که از پوستهٔ مونوبوک استفاده کنند تحت تاثیر قرار می‌دهند. */"
 }
index 2e61ad3..0e53e4a 100644 (file)
@@ -6,6 +6,7 @@
                ]
        },
        "skinname-monobook": "MonoBook",
+       "monobook-desc": "A aparencia clásica de MediaWiki desde 2004; recibe o seu nome pola foto en branco e negro dun libro que aparece no fondo das páxinas",
        "monobook.css": "/* O CSS que se coloque aquí afectará a quen use a aparencia Monobook */",
        "monobook.js": "/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia MonoBook */"
 }
index 33e527b..e645482 100644 (file)
@@ -5,6 +5,7 @@
                        "Siddhartha Ghai"
                ]
        },
+       "monobook-desc": "2004 से मीडियाविकि की क्लासिक त्वचा, जिसका नाम पृष्ठभूमि में पुस्तक के इकरंगा चित्र से पड़ा।",
        "monobook.css": "/* यहां रखी गई css मोनोबुक त्वचा का इस्तेमाल करने वाले सभी सदस्योंपर असर करेगी */",
        "monobook.js": "/* यहाँ पर दी गई जावास्क्रिप्ट मोनोबुक त्वचा का प्रयोग कर रहे सदस्यों के लिए लोड होगी */"
 }
index 83ce352..d87d663 100644 (file)
@@ -2,10 +2,12 @@
        "@metadata": {
                "authors": [
                        "Iwan Novirion",
-                       "Rex"
+                       "Rex",
+                       "Arifin.wijaya"
                ]
        },
        "skinname-monobook": "MonoBook",
+       "monobook-desc": "Kulit MediaWiki klasik sejak tahun 2004, dinamai foto hitam-putih dari buku di latar belakang halaman",
        "monobook.css": "/* CSS yang ada di sini akan diterapkan pada kulit Monobook. */",
        "monobook.js": "/* Semua JavaScript di sini akan dimuatkan untuk para pengguna yang menggunakan kulit MonoBook */"
 }
diff --git a/skins/MonoBook/i18n/ilo.json b/skins/MonoBook/i18n/ilo.json
new file mode 100644 (file)
index 0000000..c59ae5f
--- /dev/null
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Lam-ang"
+               ]
+       },
+       "monobook-desc": "Ti klasiko a kudil ti MediaWiki manipud idi 2004, nanaganan manipud ti nangisit-ken-puraw a retrato ti libro iti likudan ti panid"
+}
index b19d0a0..95ba71a 100644 (file)
@@ -1,4 +1,10 @@
 {
+       "@metadata": {
+               "authors": [
+                       "Robby"
+               ]
+       },
        "skinname-monobook": "MonoBook",
+       "monobook-desc": "De klassesche Look vu MediaWiki zanter 2004, benannt no der Schwaarzwäissfoto vun engem Buch am Hannergrond vun der Säit",
        "monobook.css": "/* Dës CSS huet nëmmen Afloss op de Skin ''Monobook''  */"
 }
index fa975fe..c01a8cc 100644 (file)
@@ -1,9 +1,11 @@
 {
        "@metadata": {
                "authors": [
-                       "Anakmalaysia"
+                       "Anakmalaysia",
+                       "Pizza1016"
                ]
        },
        "skinname-monobook": "MonoBook",
+       "monobook-desc": "Kulit MediaWiki yang klasik sejak tahun 2004, dinamakan selepas foto hitam-dan-putih sebuah buku dalam belakang laman.",
        "monobook.css": "/* CSS yang terletak di sini akan mempengaruhi pengguna kulit Monobook */"
 }
index 89b72e4..b08e117 100644 (file)
@@ -1,10 +1,12 @@
 {
        "@metadata": {
                "authors": [
-                       "Siebrand"
+                       "Siebrand",
+                       "Sjoerddebruin"
                ]
        },
        "skinname-monobook": "Monobook",
+       "monobook-desc": "De klassieke MediaWiki-vormgeving sinds 2004, genoemd naar de zwart-witfoto van een boek op de achtergrond van de pagina",
        "monobook.css": "/* CSS die hier wordt geplaatst heeft alleen invloed op de skin Monobook */",
        "monobook.js": "/* JavaScript die hier wordt geplaatst heeft alleen invloed op gebruikers die de skin Monobook gebruiken */"
 }
index 0f3b618..4c7031a 100644 (file)
@@ -1,10 +1,12 @@
 {
        "@metadata": {
                "authors": [
-                       "Sp5uhe"
+                       "Sp5uhe",
+                       "Matma Rex"
                ]
        },
        "skinname-monobook": "Książka",
+       "monobook-desc": "Klasyczna skórka MediaWiki, stworzona w 2004 roku, nazwana od czarno-białego zdjęcia książki w tle strony",
        "monobook.css": "/* Umieszczony tutaj kod CSS wpłynie na wygląd skórki Książka */",
        "monobook.js": "/* Umieszczony tutaj kod JavaScript zostanie załadowany wyłącznie przez użytkowników korzystających ze skórki Książka */"
 }
index 0425b83..df34886 100644 (file)
@@ -2,11 +2,12 @@
        "@metadata": {
                "authors": [
                        "Hamilton Abreu",
-                       "Fúlvio"
+                       "Fúlvio",
+                       "Vitorvicentevalente"
                ]
        },
        "skinname-monobook": "MonoBook",
-       "monobook-desc": "A clássica skin do MediaWiki desde 2004, tendo este nome devido a uma imagem em preto-e-branco de um livro no plano de fundo da página",
+       "monobook-desc": "O tema clássico do MediaWiki desde 2004, tendo este nome sido atribuído devido a uma imagem a preto-e-branco de um livro no plano de fundo da página",
        "monobook.css": "/* Código CSS colocado aqui afectará os utilizadores do tema Monobook */",
        "monobook.js": "/* Código Javascript colocado aqui será carregado para utilizadores do tema Monobook */"
 }
index 13c2ac2..c3b1d46 100644 (file)
@@ -2,9 +2,11 @@
        "@metadata": {
                "authors": [
                        "AlexSm",
-                       "Kaganer"
+                       "Kaganer",
+                       "Okras"
                ]
        },
+       "monobook-desc": "Классическая тема оформления MediaWiki, созданная в 2004 году и названая в честь чёрно-белой фотографии книги с фонового изображения страницы",
        "monobook.css": "/* Размещённый здесь CSS будет применяться к теме оформления Monobook */",
        "monobook.js": "/* Размещённый здесь код JavaScript будет загружаться пользователям, использующим тему оформления MonoBook */"
 }
index 249c1f5..289f50e 100644 (file)
@@ -2,10 +2,12 @@
        "@metadata": {
                "authors": [
                        "Dim Grits",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Ата"
                ]
        },
        "skinname-monobook": "Моно-книга",
+       "monobook-desc": "Класична тема оформлення MediaWiki з 2004 року, названа за чорно-білим фото книги на фоні сторінки",
        "monobook.css": "/* Розміщений тут CSS буде застосовуватися до всіх тем оформлення Monobook */",
        "monobook.js": "/* Розміщений тут код JavaScript буде завантажений для всіх користувачів, що використовують тему оформлення Моно-книга */"
 }
index 7813cc1..e6a6a78 100644 (file)
@@ -4,6 +4,7 @@
                        "Cwlin0416"
                ]
        },
+       "monobook-desc": "MediaWiki 自 2004 年以來的經典外觀,根據頁面背景的書本黑白照命名",
        "monobook.css": "/* 此 CSS 會影響使用 Monobook 介面外觀的使用者 */",
        "monobook.js": "/* 此 JavaScript 會用於使用 Monobook 介面外觀使用者 */"
 }
index 7dc376a..0ec031f 100644 (file)
@@ -97,7 +97,6 @@ class VectorTemplate extends BaseTemplate {
                <div id="content" class="mw-body" role="main">
                        <a id="top"></a>
 
-                       <div id="mw-js-message" style="display:none;"<?php $this->html( 'userlangattributes' ) ?>></div>
                        <?php
                        if ( $this->data['sitenotice'] ) {
                                ?>
@@ -411,25 +410,19 @@ class VectorTemplate extends BaseTemplate {
                                                echo ' emptyPortlet';
                                        }
                                        ?>" aria-labelledby="p-variants-label">
-                                               <h3 id="mw-vector-current-variant">
-                                                       <?php
-                                                       foreach ( $this->data['variant_urls'] as $link ) {
-                                                               ?>
-                                                               <?php
-                                                               if ( stripos( $link['attributes'], 'selected' ) !== false ) {
-                                                                       ?>
-                                                                       <?php
-                                                                       echo htmlspecialchars( $link['text'] )
-                                                                       ?>
-                                                               <?php
-                                                               }
-                                                               ?>
-                                                       <?php
+                                               <?php
+                                               // Replace the label with the name of currently chosen variant, if any
+                                               $variantLabel = $this->getMsg( 'variants' )->text();
+                                               foreach ( $this->data['variant_urls'] as $link ) {
+                                                       if ( stripos( $link['attributes'], 'selected' ) !== false ) {
+                                                               $variantLabel = $link['text'];
+                                                               break;
                                                        }
-                                                       ?>
-                                               </h3>
-
-                                               <h3 id="p-variants-label"><span><?php $this->msg( 'variants' ) ?></span><a href="#"></a></h3>
+                                               }
+                                               ?>
+                                               <h3 id="p-variants-label"><span
+                                                       style="display: block;" <?php /* Temporary WMF deployment hack, to be removed before 1.24 release */ ?>
+                                                       ><?php echo htmlspecialchars( $variantLabel ) ?></span><a href="#"></a></h3>
 
                                                <div class="menu">
                                                        <ul>
@@ -551,7 +544,7 @@ class VectorTemplate extends BaseTemplate {
 
                                                <form action="<?php $this->text( 'wgScript' ) ?>" id="searchform">
                                                        <?php
-                                                       if ($wgVectorUseSimpleSearch) {
+                                                       if ( $wgVectorUseSimpleSearch ) {
                                                        ?>
                                                        <div id="simpleSearch">
                                                                <?php
index f70c7a4..33cd230 100644 (file)
@@ -127,8 +127,6 @@ pre, .mw-code {
        vertical-align: text-bottom;
 }
 
-/* TODO: Remove #bodyContent selector (kept for backwards compatibility with cached html) */
-#bodyContent,
 .mw-body-content {
        position: relative;
        line-height: @content-line-height;
index 05a1e61..5bb6f1a 100644 (file)
@@ -1,5 +1,8 @@
 /* mediawiki.notification */
-.skin-vector {
+
+// This wrapper class is needed to ensure these rules have larger CSS
+// selector specificity than default styles
+.mediawiki {
        .mw-notification-area {
                font-size: 0.8em;
        }
index 9e39fbb..57fe45f 100644 (file)
@@ -144,6 +144,7 @@ div#mw-head div.vectorMenu h3 {
 }
 
 // The "Variants" menu has a really funny structure
+// Temporary WMF deployment hack, to be removed before 1.24 release
 div#mw-head div.vectorMenu#p-variants {
        #p-variants-label span {
                display: none;
index 37d5c67..97a3500 100644 (file)
@@ -4,13 +4,20 @@
                        "Icemandeaf"
                ]
        },
+       "skinname-vector": "M509x575S10e20494x425S14a20493x459S16d20492x478S1fb20494x502S17620493x525S11a20493x545",
+       "vector-skin-desc": "M535x520S19a00507x481S19a08465x481S22f14465x506S22f04509x506 M515x598S18d20494x403S17620499x432S11920493x452S17620499x482S14720500x502S17620499x528S17620499x548S14020485x568 M521x508S1f748479x493S1f740501x493 M532x517S15a16505x505S2880f468x484S20e00491x495S1821d503x492 M534x547S2ff00482x483S10001513x517S2e305488x487 S38700463x496 M535x536S20300516x521S20308470x521S26500516x502S26510470x502S14c30511x465S14c38465x465 M526x522S15a56499x510S11520503x479S20e00489x496S26a02474x489 M520x540S37606481x460S15a40508x513S28801499x491S20500488x492",
+       "vector.css": "/* M509x529S16d20492x471S20320493x495S20320493x514 M535x523S14c50508x492S14c58469x492S22520503x477S22520465x477 M525x525S10004510x475S22a04511x510S1000c476x475S22a14477x510 M534x518S2ff00482x483S15a10522x486S2b700514x458 M521x532S10609498x496S10621487x512S21100500x483S2df20479x468 M526x522S15a56499x510S11520503x479S20e00489x496S26a02474x489 M521x508S1f748479x493S1f740501x493 M509x575S10e20494x425S14a20493x459S16d20492x478S1fb20494x502S17620493x525S11a20493x545 M517x524S15a02484x477S15a20489x484S21100504x492S22a04504x509 */",
+       "vector.js": "/* M520x523S1f540480x477S2a204497x495 M519x527S19220498x489S2a20c482x473S20320498x512 M525x525S10004510x475S22a04511x510S1000c476x475S22a14477x510 M534x518S2ff00482x483S15a10522x486S2b700514x458 M524x539S14402493x485S1440a486x461S22b00508x509S22b10476x483 M536x521S2ff00482x483S10011515x491S28108515x461 M526x522S15a56499x510S11520503x479S20e00489x496S26a02474x489 M509x575S10e20494x425S14a20493x459S16d20492x478S1fb20494x502S17620493x525S11a20493x545 M517x524S15a02484x477S15a20489x484S21100504x492S22a04504x509 */",
        "vector-action-addsection": "M532x517S15a16505x505S2880f468x484S20e00491x495S1821d503x492 M522x522S15a37478x479S10041485x492S20600500x492",
        "vector-action-delete": "M527x532S1ea40473x511S1f540512x478S22a07497x504S2f700512x468",
        "vector-action-move": "M552x509S18520488x494S18528449x494S26626522x492",
        "vector-action-protect": "M512x519S15a19488x482S15a11489x482S20600488x508",
+       "vector-action-undelete": "M515x538S15a0a486x463S10050500x467S2330b485x516S20e00491x501 M527x532S1ea40473x511S1f540512x478S22a07497x504S2f700512x468",
+       "vector-action-unprotect": "M521x532S10609498x496S10621487x512S21100500x483S2df20479x468 M512x519S15a19488x482S15a11489x482S20600488x508",
        "vector-view-create": "M532x519S20302493x485S2030a489x502S21100509x504S26900516x482S26910468x501",
        "vector-view-edit": "M521x532S10609498x496S10621487x512S21100500x483S2df20479x468",
        "vector-view-history": "M525x524S2ff00482x483S10e00507x494S26500511x474 M514x523S11541487x478S22f04489x509",
        "vector-view-view": "M513x540S15a06486x459S10e50494x474S22b04493x510",
-       "vector-view-viewsource": "M525x524S2ff00482x483S10e00507x494S26500511x474 M509x545S16d20492x456S17620493x480S10120493x497S14a20494x530"
+       "vector-view-viewsource": "M525x524S2ff00482x483S10e00507x494S26500511x474 M509x545S16d20492x456S17620493x480S10120493x497S14a20494x530",
+       "vector-more-actions": "M526x508S18510501x493S18518475x493"
 }
index bd3703f..d150812 100644 (file)
@@ -5,6 +5,7 @@
                        "Xuacu"
                ]
        },
+       "vector-skin-desc": "Versión moderna de MonoBook, con un aspeutu frescu y munchos ameyoramientos d'usabilidá",
        "vector.css": "/* Los CSS allugaos equí afeutarán a los usuarios del aspeutu Vector */",
        "vector.js": "/* Cualesquier JavaScript que tea equí se cargará pa los usuarios del aspeutu Vector */",
        "vector-action-addsection": "Amestar seición",
@@ -17,5 +18,6 @@
        "vector-view-edit": "Editar",
        "vector-view-history": "Ver historial",
        "vector-view-view": "Lleer",
-       "vector-view-viewsource": "Ver fonte"
+       "vector-view-viewsource": "Ver fonte",
+       "vector-more-actions": "Más"
 }
index b84c18f..5dbc57c 100644 (file)
@@ -7,6 +7,7 @@
                        "Хомелка"
                ]
        },
+       "vector-skin-desc": "Сучасная версія вокладкі Манабук, з абноўленым відам і шматлікімі зручнымі паляпшэннямі",
        "vector-action-addsection": "Дадаць тэму",
        "vector-action-delete": "Сцерці",
        "vector-action-move": "Перанесці",
index a371374..31d5173 100644 (file)
@@ -6,9 +6,11 @@
                        "Calak",
                        "Paucabot",
                        "Ssola",
-                       "Vriullop"
+                       "Vriullop",
+                       "Toniher"
                ]
        },
+       "vector-skin-desc": "Versió moderna del MonoBook amb un nou aspesctes i moltes millores en la usabilitat",
        "vector-action-addsection": "Nova secció",
        "vector-action-delete": "Esborra",
        "vector-action-move": "Reanomena",
index ed44124..75053d7 100644 (file)
@@ -10,7 +10,7 @@
        "vector-action-delete": "ДӀаяккха",
        "vector-action-move": "ЦӀе хийца",
        "vector-action-protect": "Гlаролла дé",
-       "vector-action-undelete": "Меттахlоттадé",
+       "vector-action-undelete": "МеттахӀоттае",
        "vector-action-unprotect": "ГӀароллех къаста",
        "vector-view-create": "Кхоллар",
        "vector-view-edit": "Нисъе",
index 6d79bae..99d4dc3 100644 (file)
@@ -14,5 +14,6 @@
        "vector-view-edit": "Golygu",
        "vector-view-history": "Gweld yr hanes",
        "vector-view-view": "Darllen",
-       "vector-view-viewsource": "Dangos côd y dudalen"
+       "vector-view-viewsource": "Dangos côd y dudalen",
+       "vector-more-actions": "Rhagor"
 }
index ad56101..1651d66 100644 (file)
@@ -6,6 +6,7 @@
                        "Peter Alberti"
                ]
        },
+       "vector-skin-desc": "Moderne version af MonoBook med frisk udseende og mange forbedringer af brugervenligheden",
        "vector-action-addsection": "Nyt emne",
        "vector-action-delete": "Slet",
        "vector-action-move": "Flyt",
@@ -16,5 +17,6 @@
        "vector-view-edit": "Redigér",
        "vector-view-history": "Se historik",
        "vector-view-view": "Læs",
-       "vector-view-viewsource": "Se kilden"
+       "vector-view-viewsource": "Se kilden",
+       "vector-more-actions": "Mere"
 }
index df7b397..75352a5 100644 (file)
                ]
        },
        "skinname-vector": "Vector",
+       "vector-skin-desc": "Versión moderna de MonoBook, con un aspecto actualizado y muchas mejoras de usabilidad",
        "vector.css": "/* El CSS colocado en esta página afectará a los usuarios que usen la apariencia \"Vector\" */",
        "vector.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios que usen la apariencia Vector */",
-       "vector-action-addsection": "Nueva sección",
+       "vector-action-addsection": "Sección nueva",
        "vector-action-delete": "Borrar",
        "vector-action-move": "Trasladar",
        "vector-action-protect": "Proteger",
index 888ff1e..856742c 100644 (file)
@@ -2,7 +2,8 @@
        "@metadata": {
                "authors": [
                        "Unai Fdz. de Betoño",
-                       "Xabier Armendaritz"
+                       "Xabier Armendaritz",
+                       "Fitoschido"
                ]
        },
        "vector-action-addsection": "Gehitu atala",
@@ -15,5 +16,6 @@
        "vector-view-edit": "Aldatu",
        "vector-view-history": "Ikusi historia",
        "vector-view-view": "Irakurri",
-       "vector-view-viewsource": "Kodea ikusia"
+       "vector-view-viewsource": "Kodea ikusia",
+       "vector-more-actions": "Gehiago"
 }
index c18eba4..1d329ff 100644 (file)
@@ -9,6 +9,7 @@
                ]
        },
        "skinname-vector": "برداری",
+       "vector-skin-desc": "نسخه مدرن منوبوک با نگاه تازه و بهبود قابلیت استفاده",
        "vector-action-addsection": "افزودن بخش",
        "vector-action-delete": "حذف",
        "vector-action-move": "انتقال",
index d63223a..f9ff0a3 100644 (file)
@@ -5,6 +5,7 @@
                        "Pyt"
                ]
        },
+       "vector-skin-desc": "Modern werjuun faan Monobook mä frisk skak an föl muar mögelkhaiden",
        "vector-action-addsection": "Nei kirew began",
        "vector-action-delete": "Strik",
        "vector-action-move": "Fersküüw",
@@ -15,5 +16,6 @@
        "vector-view-edit": "Bewerke",
        "vector-view-history": "Ferluup uunluke",
        "vector-view-view": "Lees",
-       "vector-view-viewsource": "Kweltekst uunluke"
+       "vector-view-viewsource": "Kweltekst uunluke",
+       "vector-more-actions": "Muar"
 }
index de19c39..455b9bd 100644 (file)
@@ -6,6 +6,7 @@
                        "Vivaelcelta"
                ]
        },
+       "vector-skin-desc": "Versión moderna da aparencia MonoBook, cun aspecto fresco e moitas melloras na usabilidade",
        "vector.css": "/* O CSS que se coloque aquí afectará a quen use a aparencia Vector */",
        "vector.js": "/* Calquera JavaScript que haxa aquí será cargado para os usuarios que usen a aparencia Vector */",
        "vector-action-addsection": "Nova sección",
index 5b5f56b..6b68d3e 100644 (file)
@@ -16,5 +16,6 @@
        "vector-view-edit": "सम्पादन",
        "vector-view-history": "इतिहास देखें",
        "vector-view-view": "पढ़ें",
-       "vector-view-viewsource": "स्रोत देखें"
+       "vector-view-viewsource": "स्रोत देखें",
+       "vector-more-actions": "अधिक"
 }
index 3116632..ef439a3 100644 (file)
@@ -9,6 +9,7 @@
                ]
        },
        "skinname-vector": "Vektor",
+       "vector-skin-desc": "Versi modern dari MonoBook dengan tampilan segar dan banyak perbaikan kegunaan",
        "vector.css": "/* CSS nan ado di siko diterapkan pado kulik Vektor. */",
        "vector.js": "/* Semua JavaScript di sini akan dimuatkan untuk para pengguna yang menggunakan kulit Vector */",
        "vector-action-addsection": "Bagian baru",
index 817c75f..d83586d 100644 (file)
@@ -5,6 +5,7 @@
                        "Saluyot"
                ]
        },
+       "vector-skin-desc": "Modernno a bersion ti MonoBook nga addaan iti baro a langa ken adu kadagiti naserbi a panagpasayaat",
        "vector-action-addsection": "Agnayon ti topiko",
        "vector-action-delete": "Ikkaten",
        "vector-action-move": "Iyalis",
index 1970fa0..3593350 100644 (file)
@@ -12,7 +12,7 @@
        "vector-action-move": "Атауын өзгерту",
        "vector-action-protect": "Қорғау",
        "vector-action-undelete": "Жоймау",
-       "vector-action-unprotect": "Ò\9aоÑ\80Ò\93анÑ\8bÑ\81Ñ\82Ñ\8b өзгерту",
+       "vector-action-unprotect": "Ò\9aоÑ\80Ò\93анÑ\8bÑ\81Ñ\8bн өзгерту",
        "vector-view-create": "Бастау",
        "vector-view-edit": "Өңдеу",
        "vector-view-history": "Өңделу тарихы",
index 77c512d..cb26439 100644 (file)
@@ -4,6 +4,7 @@
                        "Robby"
                ]
        },
+       "vector-skin-desc": "Modern Versioun vu Monobook mat frëschem Look a ville Verbesserunge vun der Benotzerfrëndlechkeet",
        "vector-action-addsection": "Sujet derbäisetzen",
        "vector-action-delete": "Läschen",
        "vector-action-move": "Réckelen",
index 8f6f09a..2f756b5 100644 (file)
@@ -5,7 +5,7 @@
                ]
        },
        "vector-action-addsection": "موضوع اضاف بكيد",
-       "vector-action-delete": "حذف بكيد",
+       "vector-action-delete": "پاکسا کردن",
        "vector-action-move": "جاوه جا بوئيت",
        "vector-action-protect": "حمايت بكيد",
        "vector-action-undelete": "حذف نبيئني",
index 697d1eb..ccd43c5 100644 (file)
@@ -15,5 +15,6 @@
        "vector-view-edit": "Labot",
        "vector-view-history": "Hronoloģija",
        "vector-view-view": "Skatīt",
-       "vector-view-viewsource": "Aplūkot kodu"
+       "vector-view-viewsource": "Aplūkot kodu",
+       "vector-more-actions": "Vairāk"
 }
index 2795e44..73c8e05 100644 (file)
@@ -7,7 +7,9 @@
                ]
        },
        "skinname-vector": "Vector",
+       "vector-skin-desc": "Versi MonoBook yang moden dengan rupa yang segar dan banyak pembaikan kepada kegunaan.",
        "vector.css": "/* CSS yang terletak di sini akan mempengaruhi pengguna kulit Vector */",
+       "vector.js": "/ * Sebarang JavaScript di sini akan dimuatkan untuk pengguna-pengguna yang menggunakan kulit Vector * /",
        "vector-action-addsection": "Buka topik",
        "vector-action-delete": "Hapus",
        "vector-action-move": "Pindah",
@@ -18,5 +20,6 @@
        "vector-view-edit": "Sunting",
        "vector-view-history": "Lihat sejarah",
        "vector-view-view": "Baca",
-       "vector-view-viewsource": "Lihat sumber"
+       "vector-view-viewsource": "Lihat sumber",
+       "vector-more-actions": "Lain"
 }
index 32c9f1a..3fab17f 100644 (file)
@@ -1,7 +1,8 @@
 {
        "@metadata": {
                "authors": [
-                       "Chrisportelli"
+                       "Chrisportelli",
+                       "Leli Forte"
                ]
        },
        "vector-action-addsection": "Żid diskussjoni",
@@ -14,5 +15,6 @@
        "vector-view-edit": "Editja",
        "vector-view-history": "Ara l-kronoloġija",
        "vector-view-view": "Aqra",
-       "vector-view-viewsource": "Ara s-sors"
+       "vector-view-viewsource": "Ara s-sors",
+       "vector-more-actions": "Aktar"
 }
index bae61b5..0ef82e0 100644 (file)
@@ -6,6 +6,7 @@
                        "Nghtwlkr"
                ]
        },
+       "vector-skin-desc": "Moderne versjon av MonoBook med et friskt utseende og mange bruksforbedringer",
        "vector-action-addsection": "Nytt emne",
        "vector-action-delete": "Slett",
        "vector-action-move": "Flytt",
index 5e8ad90..07c18d9 100644 (file)
@@ -5,10 +5,12 @@
                        "Romaine",
                        "SPQRobin",
                        "Siebrand",
-                       "Troefkaart"
+                       "Troefkaart",
+                       "Sjoerddebruin"
                ]
        },
        "skinname-vector": "Vector",
+       "vector-skin-desc": "Moderne versie van MonoBook met een fris uiterlijk en verbeteringen op het gebied van gebruiksvriendelijkheid",
        "vector.css": "/* CSS die hier wordt geplaatst heeft alleen invloed op de skin Vector */",
        "vector.js": "/* JavaScript die hier wordt geplaatst heeft alleen invloed op gebruikers die de skin Vector gebruiken */",
        "vector-action-addsection": "Kopje toevoegen",
index d0faf4d..5cf2082 100644 (file)
@@ -6,6 +6,7 @@
                ]
        },
        "skinname-vector": "Wektor",
+       "vector-skin-desc": "Odświeżona wersja skórki Książka, z nowym wyglądem i usprawnieniami",
        "vector.css": "/* Umieszczony tutaj kod CSS wpłynie na wygląd skórki Wektor */",
        "vector.js": "/* Umieszczony tutaj kod JavaScript zostanie załadowany wyłącznie przez użytkowników korzystających ze skórki Wektor */",
        "vector-action-addsection": "Dodaj temat",
index 5bf9d24..7bd2fd1 100644 (file)
@@ -8,10 +8,12 @@
                        "Dim Grits",
                        "NickK",
                        "Prima klasy4na",
-                       "Тест"
+                       "Тест",
+                       "Ата"
                ]
        },
        "skinname-vector": "Векторне",
+       "vector-skin-desc": "Сучасна версія MonoBook зі свіжим виглядом і багатьма зручними покращеннями",
        "vector.css": "/* Розміщений тут CSS-код буде використаний в темі оформлення Векторне */",
        "vector.js": "/* Розміщений тут код JavaScript буде завантажений для всіх користувачів, що використовують векторну тему оформлення */",
        "vector-action-addsection": "Додати тему",
@@ -25,5 +27,5 @@
        "vector-view-history": "Переглянути історію",
        "vector-view-view": "Читати",
        "vector-view-viewsource": "Переглянути код",
-       "vector-more-actions": "Ð\91Ñ\96лÑ\8cÑ\88е"
+       "vector-more-actions": "Ще"
 }
index 3e67c21..0036c34 100644 (file)
@@ -7,6 +7,7 @@
                        "Mark85296341"
                ]
        },
+       "vector-skin-desc": "現代版的 MonoBook,有著較新穎的外觀與許多使用性的改進",
        "vector.css": "/* 此 CSS 會影響使用 Vector 介面外觀的使用者 */",
        "vector.js": "/* 此 JavaScript 會用於使用 Vector 介面外觀使用者 */",
        "vector-action-addsection": "加入主題",
index aedb6a9..17b2039 100644 (file)
        margin-left: 10em;
 }
 
+.config-skins-item {
+       /* Clearfix */
+       clear: left;
+       overflow: hidden;
+}
+
+.config-skins-item .config-input-check {
+       margin-left: 10em;
+       width: 20em;
+       float: left;
+}
+
+.config-skins-item .config-skins-use-as-default {
+       float: left;
+}
+
 .error {
        color: red;
        background-color: #fff;
diff --git a/skins/common/images/icons/fileicon-xcf.png b/skins/common/images/icons/fileicon-xcf.png
new file mode 100644 (file)
index 0000000..1037b50
Binary files /dev/null and b/skins/common/images/icons/fileicon-xcf.png differ
diff --git a/skins/common/images/tipsy-arrow.gif b/skins/common/images/tipsy-arrow.gif
deleted file mode 100644 (file)
index 9f1a15b..0000000
Binary files a/skins/common/images/tipsy-arrow.gif and /dev/null differ
index a5612e2..5a8335d 100644 (file)
@@ -372,12 +372,16 @@ input#wpSummary {
        display: none;
 }
 
-/* Convenience links to edit block, delete and protect reasons */
+/**
+ * Convenience links to edit block, delete and protect reasons
+ * and upload licenses
+ */
 p.mw-ipb-conveniencelinks,
 p.mw-protect-editreasons,
 p.mw-filedelete-editreasons,
 p.mw-delete-editreasons,
-p.mw-revdel-editreasons {
+p.mw-revdel-editreasons,
+p.mw-upload-editlicenses {
        font-size: 90%;
        text-align: right;
 }
@@ -1128,37 +1132,6 @@ ol:lang(or) li {
        margin-left: 20px;
 }
 
-.tipsy {
-       padding: 5px 5px 10px;
-       font-size: 12px;
-       position: absolute;
-       z-index: 100000;
-       overflow: visible;
-}
-
-.tipsy-inner {
-       padding: 5px 8px 4px 8px;
-       background-color: #d6f3ff;
-       color: black;
-       border: 1px solid #5dc9f4;
-       max-width: 300px;
-       text-align: left;
-}
-
-.tipsy-arrow {
-       position: absolute;
-       /* @embed */
-       background: url(images/tipsy-arrow.gif) no-repeat top left;
-       width: 13px;
-       height: 13px;
-}
-
-.tipsy-se .tipsy-arrow {
-       bottom: -2px;
-       right: 10px;
-       background-position: 0% 100%;
-}
-
 #mw-clearyourcache,
 #mw-sitecsspreview,
 #mw-sitejspreview,
index fdfca0a..b6689f9 100644 (file)
@@ -8,15 +8,6 @@
                isIE6 = ( /msie ([0-9]{1,}[\.0-9]{0,})/.exec( ua ) && parseFloat( RegExp.$1 ) <= 6.0 ),
                onloadFuncts = [];
 
-if ( mw.config.get( 'wgBreakFrames' ) ) {
-       // Note: In IE < 9 strict comparison to window is non-standard (the standard didn't exist yet)
-       // it works only comparing to window.self or window.window (http://stackoverflow.com/q/4850978/319266)
-       if ( win.top !== win.self ) {
-               // Un-trap us from framesets
-               win.top.location = win.location;
-       }
-}
-
 /**
  * User-agent sniffing.
  *
index 3c28d7a..3be33b7 100755 (executable)
@@ -3,6 +3,5 @@
 
 source "https://rubygems.org"
 
-gem "chunky_png"
 gem "mediawiki_api"
 gem "mediawiki_selenium"
index 6ec2493..92784bf 100644 (file)
@@ -4,7 +4,6 @@ GEM
     builder (3.2.2)
     childprocess (0.5.3)
       ffi (~> 1.0, >= 1.0.11)
-    chunky_png (1.3.1)
     cucumber (1.3.15)
       builder (>= 2.1.2)
       diff-lcs (>= 1.1.3)
@@ -32,7 +31,7 @@ GEM
       domain_name (~> 0.5)
     i18n (0.6.9)
     json (1.8.1)
-    mediawiki_api (0.1.2)
+    mediawiki_api (0.1.3)
       faraday (~> 0.9, >= 0.9.0)
       faraday-cookie_jar (~> 0.0, >= 0.0.6)
     mediawiki_selenium (0.2.25)
@@ -57,7 +56,7 @@ GEM
       mime-types (>= 1.16)
     rspec-expectations (2.99.1)
       diff-lcs (>= 1.1.3, < 2.0)
-    rubyzip (1.1.4)
+    rubyzip (1.1.5)
     selenium-webdriver (2.42.0)
       childprocess (>= 0.5.0)
       multi_json (~> 1.0)
@@ -76,6 +75,5 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
-  chunky_png
   mediawiki_api
   mediawiki_selenium
index 90e062d..29dd1c1 100644 (file)
@@ -1,4 +1,4 @@
-@chrome @clean @en.wikipedia.beta.wmflabs.org @firefox @phantomjs @test2.wikipedia.org
+@chrome @clean @en.wikipedia.beta.wmflabs.org @firefox @login @phantomjs @test2.wikipedia.org
 Feature: Create Page With Wiki Link
 
   Scenario: Create Page With Wiki Link
@@ -6,4 +6,4 @@ Feature: Create Page With Wiki Link
       And I go to the "Link Source Test Page" page with content "This is a [[Link Target Test Page|link to the test target page]] right here."
     When I click the Link Target link
     Then I should be on the Link Target Test Page
-      And the page content should contain "Link Target Test Page"
\ No newline at end of file
+      And the page content should contain "Link Target Test Page"
index ef9991a..c190a78 100644 (file)
@@ -1,9 +1,11 @@
-@chrome @clean @en.wikipedia.beta.wmflabs.org @firefox @phantomjs @test2.wikipedia.org
+@chrome @clean @en.wikipedia.beta.wmflabs.org @firefox @login @phantomjs @test2.wikipedia.org
 Feature: Edit Page
 
   Scenario: Create and edit page
     Given I go to the "Editing Test Page" page with content "This is a page to test editing"
     When I click Edit
       And I edit the page with "Edited and a random string"
+      And I click Preview
+      And I click Show Changes
       And I save the edit
     Then the edited page content should contain "Edited and a random string"
diff --git a/tests/browser/features/file.feature b/tests/browser/features/file.feature
new file mode 100644 (file)
index 0000000..2d3b708
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# This file is subject to the license terms in the LICENSE file found in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of
+# qa-browsertests, including this file, may be copied, modified, propagated, or
+# distributed except according to the terms contained in the LICENSE file.
+#
+# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS
+#
+@chrome @en.wikipedia.beta.wmflabs.org @firefox @internet_explorer_6 @internet_explorer_7 @internet_explorer_8 @internet_explorer_9 @internet_explorer_10 @phantomjs @test2.wikipedia.org
+Feature: File
+
+ Scenario: Anonymous goes to file that does not exist
+   Given I am at file that does not exist
+   Then page should show that no such file exists
+
+ @login
+ Scenario: Logged-in user goes to file that does not exist
+   Given I am logged in
+     And I am at file that does not exist
+   Then page should show that no such file exists
\ No newline at end of file
diff --git a/tests/browser/features/login.feature b/tests/browser/features/login.feature
new file mode 100644 (file)
index 0000000..9ff2a2a
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# This file is subject to the license terms in the LICENSE file found in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of
+# qa-browsertests, including this file, may be copied, modified, propagated, or
+# distributed except according to the terms contained in the LICENSE file.
+#
+# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS
+#
+@chrome @en.wikipedia.beta.wmflabs.org @firefox @internet_explorer_6 @internet_explorer_7 @internet_explorer_8 @internet_explorer_9 @internet_explorer_10 @phantomjs @test2.wikipedia.org
+Feature: Log in
+
+  Background:
+    Given I am at Log in page
+
+  Scenario: Go to Log in page
+    Then Username element should be there
+      And Password element should be there
+      And Log in element should be there
+
+  Scenario: Log in without entering credentials
+    When I log in without entering credentials
+    Then error box should be visible
+
+  Scenario: Log in without entering password
+    When I log in without entering password
+    Then error box should be visible
+
+  Scenario: Log in with incorrect username
+    When I log in with incorrect username
+    Then error box should be visible
+
+  Scenario: Log in with incorrect password
+    When I log in with incorrect password
+    Then error box should be visible
+
+  @login
+  Scenario: Log in with valid credentials
+    When I am logged in
+    Then error box should not be visible
\ No newline at end of file
index 5af097b..5ab02be 100644 (file)
@@ -2,6 +2,14 @@ When(/^I click Edit$/) do
   on(MainPage).edit_link
 end
 
+When(/^I click Preview$/) do
+  on(EditPage).preview_button
+end
+
+When(/^I click Show Changes$/) do
+  on(EditPage).show_changes_button
+end
+
 When(/^I edit the page with "(.*?)"$/) do |edit_content|
   on(EditPage).edit_page_content_element.send_keys(edit_content + @random_string)
 end
diff --git a/tests/browser/features/step_definitions/file_steps.rb b/tests/browser/features/step_definitions/file_steps.rb
new file mode 100644 (file)
index 0000000..a2ed1bf
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# This file is subject to the license terms in the LICENSE file found in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of
+# qa-browsertests, including this file, may be copied, modified, propagated, or
+# distributed except according to the terms contained in the LICENSE file.
+#
+# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS
+#
+Given(/^I am at file that does not exist$/) do
+  visit(FileDoesNotExistPage, using_params: {page_name: @random_string})
+end
+
+Then(/^page should show that no such file exists$/) do
+  on(FileDoesNotExistPage).file_does_not_exist_message_element.should be_visible
+end
diff --git a/tests/browser/features/step_definitions/login_steps.rb b/tests/browser/features/step_definitions/login_steps.rb
new file mode 100644 (file)
index 0000000..b654b2d
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# This file is subject to the license terms in the LICENSE file found in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of
+# qa-browsertests, including this file, may be copied, modified, propagated, or
+# distributed except according to the terms contained in the LICENSE file.
+#
+# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS
+#
+Given(/^I am at Log in page$/) do
+  visit LoginPage
+end
+
+When(/^I log in with incorrect password$/) do
+  on(LoginPage).login_with(ENV["MEDIAWIKI_USER"], "incorrect password", false)
+end
+
+When(/^I log in with incorrect username$/) do
+  on(LoginPage).login_with("incorrect username", ENV["MEDIAWIKI_PASSWORD"], false)
+end
+
+When(/^I log in without entering credentials$/) do
+  on(LoginPage).login_with("", "", false)
+end
+
+When(/^I log in without entering password$/) do
+  on(LoginPage).login_with(ENV["MEDIAWIKI_USER"], "", false)
+end
+
+Then(/^error box should be visible$/) do
+  on(LoginErrorPage).error_box_element.should be_visible
+end
+
+Then(/^error box should not be visible$/) do
+  on(LoginErrorPage).error_box_element.should_not be_visible
+end
+
+Then(/^feedback should be (.+)$/) do |feedback|
+  on(LoginPage) do |page|
+    page.feedback_element.when_present.click
+    page.feedback.should match Regexp.escape(feedback)
+  end
+end
+
+Then(/^Log in element should be there$/) do
+  on(LoginPage).login_element.should exist
+end
+
+Then(/^main page should open$/) do
+  @browser.url.should == on(MainPage).class.url
+end
+
+Then(/^Password element should be there$/) do
+  on(LoginPage).password_element.should exist
+end
+
+Then(/^there should be a link to (.+)$/) do |text|
+  on(LoginPage).username_displayed_element.when_present.text.should == text
+end
+
+Then(/^Username element should be there$/) do
+  on(LoginPage).username_element.should exist
+end
index 4ffef5e..7c12236 100644 (file)
@@ -1,2 +1,2 @@
-require "mediawiki_selenium"
 require "mediawiki_api"
+require "mediawiki_selenium"
index 594ac73..b619c34 100644 (file)
@@ -2,6 +2,7 @@ class EditPage
   include PageObject
 
   text_area(:edit_page_content, id: "wpTextbox1")
+  button(:preview_button, id: "wpPreview")
+  button(:show_changes_button, id: "wpDiff")
   button(:save_button, id: "wpSave")
-
 end
\ No newline at end of file
diff --git a/tests/browser/features/support/pages/file_does_not_exist_page.rb b/tests/browser/features/support/pages/file_does_not_exist_page.rb
new file mode 100644 (file)
index 0000000..c8491f3
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# This file is subject to the license terms in the LICENSE file found in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of
+# qa-browsertests, including this file, may be copied, modified, propagated, or
+# distributed except according to the terms contained in the LICENSE file.
+#
+# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the
+# qa-browsertests top-level directory and at
+# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS
+#
+class FileDoesNotExistPage
+  include PageObject
+
+  include URL
+  page_url URL.url("File:<%=params[:page_name]%>")
+
+  div(:file_does_not_exist_message, id: "mw-imagepage-nofile")
+end
diff --git a/tests/browser/features/support/pages/login_error_page.rb b/tests/browser/features/support/pages/login_error_page.rb
new file mode 100644 (file)
index 0000000..4fc9ca7
--- /dev/null
@@ -0,0 +1,5 @@
+class LoginErrorPage
+  include PageObject
+
+  div(:error_box, class: "errorbox")
+end
\ No newline at end of file
index 69fda8d..59c18a8 100644 (file)
@@ -7,7 +7,7 @@ module.exports = function ( grunt ) {
        grunt.loadNpmTasks( 'grunt-contrib-jshint' );
        grunt.loadNpmTasks( 'grunt-contrib-watch' );
        grunt.loadNpmTasks( 'grunt-banana-checker' );
-       grunt.loadNpmTasks( 'grunt-jscs-checker' );
+       grunt.loadNpmTasks( 'grunt-jscs' );
        grunt.loadNpmTasks( 'grunt-jsonlint' );
 
        grunt.file.setBase(  __dirname + '/../..' );
index a398596..386f488 100644 (file)
@@ -9,7 +9,7 @@
     "grunt-contrib-jshint": "0.10.0",
     "grunt-contrib-watch": "0.6.1",
     "grunt-banana-checker": "0.1.0",
-    "grunt-jscs-checker": "0.4.4",
+    "grunt-jscs": "0.6.1",
     "grunt-jsonlint": "1.0.4"
   }
 }
index 6c8a401..5d05ca0 100644 (file)
@@ -69,11 +69,6 @@ class ParserTest {
         */
        private $djVuSupport;
 
-       /**
-        * @var string $oldTablePrefix Original table prefix
-        */
-       private $oldTablePrefix;
-
        private $maxFuzzTestLength = 300;
        private $fuzzSeed = 0;
        private $memoryLimit = 50;
@@ -153,7 +148,7 @@ class ParserTest {
                global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc,
                        $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
                        $wgExtraNamespaces, $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
-                       $wgExtraInterlanguageLinkPrefixes,
+                       $wgExtraInterlanguageLinkPrefixes, $wgLocalInterwikis,
                        $parserMemc, $wgThumbnailScriptPath, $wgScriptPath,
                        $wgArticlePath, $wgScript, $wgStylePath, $wgExtensionAssetsPath,
                        $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType, $wgLockManagers;
@@ -213,7 +208,6 @@ class ParserTest {
                $messageMemc = wfGetMessageCacheStorage();
                $parserMemc = wfGetParserCacheStorage();
 
-               // $wgContLang = new StubContLang;
                $wgUser = new User;
                $context = new RequestContext;
                $wgLang = $context->getLanguage();
@@ -224,11 +218,12 @@ class ParserTest {
                if ( $wgStyleDirectory === false ) {
                        $wgStyleDirectory = "$IP/skins";
                }
+
+               self::setupInterwikis();
+               $wgLocalInterwikis = array( 'local', 'mi' );
                // "extra language links"
                // see https://gerrit.wikimedia.org/r/111390
                array_push( $wgExtraInterlanguageLinkPrefixes, 'mul' );
-
-               self::setupInterwikis();
        }
 
        /**
@@ -245,6 +240,11 @@ class ParserTest {
                # for testing inter-language links
                Hooks::register( 'InterwikiLoadPrefix', function ( $prefix, &$iwData ) {
                        static $testInterwikis = array(
+                               'local' => array(
+                                       'iw_url' => 'http://doesnt.matter.org/$1',
+                                       'iw_api' => '',
+                                       'iw_wikiid' => '',
+                                       'iw_local' => 0 ),
                                'wikipedia' => array(
                                        'iw_url' => 'http://en.wikipedia.org/wiki/$1',
                                        'iw_api' => '',
@@ -280,6 +280,11 @@ class ParserTest {
                                        'iw_api' => '',
                                        'iw_wikiid' => '',
                                        'iw_local' => 1 ),
+                               'mi' => array(
+                                       'iw_url' => 'http://mi.wikipedia.org/wiki/$1',
+                                       'iw_api' => '',
+                                       'iw_wikiid' => '',
+                                       'iw_local' => 1 ),
                                'mul' => array(
                                        'iw_url' => 'http://wikisource.org/wiki/$1',
                                        'iw_api' => '',
@@ -942,7 +947,6 @@ class ParserTest {
                }
 
                $this->databaseSetupDone = true;
-               $this->oldTablePrefix = $wgDBprefix;
 
                # SqlBagOStuff broke when using temporary tables on r40209 (bug 15892).
                # It seems to have been fixed since (r55079?), but regressed at some point before r85701.
index e4d9324..62e160b 100644 (file)
@@ -1087,7 +1087,7 @@ Non-html5 tags should be accepted
 </p>
 !! end
 
-## a,rtc not permitted
+## a not permitted
 ## i,b,br omitted
 !! test
 Text-level semantic html elements in wikitext
@@ -1109,7 +1109,7 @@ Text-level semantic html elements in wikitext
 <sub>text</sub>
 <u>text</u>
 <mark>text</mark>
-<ruby><rb>明日<rp>(</rp><rt>Ashita</rt><rp>)</rp></rb></ruby>
+<ruby><rb>明日</rb><rp>(</rp><rt>Ashita</rt><rp> </rp><rtc>あした</rtc><rp>)</rp></ruby>
 <bdi>text</bdi>
 <bdo>text</bdo>
 <span>text</span>
@@ -1132,7 +1132,7 @@ Text-level semantic html elements in wikitext
 <sub>text</sub>
 <u>text</u>
 <mark>text</mark>
-<ruby><rb>明日<rp>(</rp><rt>Ashita</rt><rp>)</rp></rb></ruby>
+<ruby><rb>明日</rb><rp>(</rp><rt>Ashita</rt><rp> </rp><rtc>あした</rtc><rp>)</rp></ruby>
 <bdi>text</bdi>
 <bdo>text</bdo>
 <span>text</span>
@@ -1140,6 +1140,45 @@ Text-level semantic html elements in wikitext
 </p>
 !! end
 
+# test cases taken from
+# http://www.w3.org/TR/html5/text-level-semantics.html#the-ruby-element
+!! test
+Ruby markup (W3C-style)
+!! wikitext
+; Mono-ruby for individual base characters
+: <ruby>日<rt>に</rt>本<rt>ほん</rt>語<rt>ご</rt></ruby>
+; Group ruby
+: <ruby>今日<rt>きょう</rt></ruby>
+; Jukugo ruby
+: <ruby>法<rb>華</rb><rb>経</rb><rt>ほ</rt><rt>け</rt><rt>きょう</rt></ruby>
+; Inline ruby
+: <ruby>東<rb>京</rb><rp>(</rp><rt>とう</rt><rt>きょう</rt><rp>)</rp></ruby>
+; Double-sided ruby
+: <ruby><rb>旧</rb><rb>金</rb><rb>山</rb><rt>jiù</rt><rt>jīn</rt><rt>shān</rt><rtc>San Francisco</rtc></ruby>
+<ruby>
+<rb>♥</rb><rtc><rt>Heart</rt></rtc><rtc lang="fr"><rt>Cœur</rt></rtc>
+<rb>☘</rb><rtc><rt>Shamrock</rt></rtc><rtc lang="fr"><rt>Trèfle</rt></rtc>
+<rb>✶</rb><rtc><rt>Star</rt></rtc><rtc lang="fr"><rt>Étoile</rt></rtc>
+</ruby>
+!! html
+<dl><dt> Mono-ruby for individual base characters</dt>
+<dd> <ruby>日<rt>に</rt>本<rt>ほん</rt>語<rt>ご</rt></ruby></dd>
+<dt> Group ruby</dt>
+<dd> <ruby>今日<rt>きょう</rt></ruby></dd>
+<dt> Jukugo ruby</dt>
+<dd> <ruby>法<rb>華</rb><rb>経</rb><rt>ほ</rt><rt>け</rt><rt>きょう</rt></ruby></dd>
+<dt> Inline ruby</dt>
+<dd> <ruby>東<rb>京</rb><rp>(</rp><rt>とう</rt><rt>きょう</rt><rp>)</rp></ruby></dd>
+<dt> Double-sided ruby</dt>
+<dd> <ruby><rb>旧</rb><rb>金</rb><rb>山</rb><rt>jiù</rt><rt>jīn</rt><rt>shān</rt><rtc>San Francisco</rtc></ruby></dd></dl>
+<p><ruby>
+<rb>♥</rb><rtc><rt>Heart</rt></rtc><rtc lang="fr"><rt>Cœur</rt></rtc>
+<rb>☘</rb><rtc><rt>Shamrock</rt></rtc><rtc lang="fr"><rt>Trèfle</rt></rtc>
+<rb>✶</rb><rtc><rt>Star</rt></rtc><rtc lang="fr"><rt>Étoile</rt></rtc>
+</ruby>
+</p>
+!! end
+
 !! test
 Non-word characters don't terminate tag names (bug 17663, 40670, 52022)
 !! wikitext
@@ -2583,41 +2622,28 @@ File:foobar.jpg
 !!end
 
 !! test
-Leading pipes outside of tables
-!! options
-parsoid
-!! wikitext
-| foo
-!! html
-<p>| foo</p>
-!! end
-
-!! test
-Leading pipes outside of tables 2
-!! options
-parsoid
-!! wikitext
-a
-| foo
-b
-!! html
-<p>a
-| foo
-b</p>
-!! end
-
-!! test
-Leading pipes outside of tables 3
-!! options
-parsoid
+Table wikitext syntax outside wiki-tables
 !! wikitext
 a
+! not a table heading
+|- not a table row
+| not a table cell
 | class="foo bar" | baz
 b
+|}
+|-
+c
 !! html
 <p>a
+! not a table heading
+|- not a table row
+| not a table cell
 | class="foo bar" | baz
-b</p>
+b
+|}
+|-
+c
+</p>
 !! end
 
 !!test
@@ -6129,6 +6155,16 @@ Link with multiple ":" in a subpage-supporting namespace (bug 63636)
 <p><a rel="mw:WikiLink" href="./User:Foo/Test/63636:Bar">Test</a></p>
 !! end
 
+!! test
+Purely hash wikilink
+!! options
+title=[[User:test/123]]
+!! wikitext
+[[#a|b]]
+!! html/parsoid
+<p data-parsoid='{}'><a rel="mw:WikiLink" href="../User:Test/123#a" data-parsoid='{"stx":"piped","a":{"href":"../User:Test/123#a"},"sa":{"href":"#a"}}'>b</a></p>
+!! end
+
 !! test
 1. Interaction of linktrail and template encapsulation
 !! options
@@ -6356,6 +6392,44 @@ parsoid
 <p data-parsoid='{}'><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"piped","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":"wikipedia:Foo"},"isIW":true,"tail":"r"}'>Bar</a></p>
 !! end
 
+!! test
+Local interwiki link
+!! wikitext
+[[local:Template:Foo]]
+!! html
+<p><a href="/wiki/Template:Foo" title="Template:Foo">local:Template:Foo</a>
+</p>
+!! end
+
+!! test
+Local interwiki link: self-link to current page
+!! options
+title=[[Main Page]]
+!! wikitext
+[[local:Main Page]]
+!! html
+<p><strong class="selflink">local:Main Page</strong>
+</p>
+!! end
+
+!! test
+Local interwiki link: prefix only (bug 64167)
+!! wikitext
+[[local:]]
+!! html
+<p><a href="/wiki/Main_Page" title="Main Page">local:</a>
+</p>
+!! end
+
+!! test
+Local interwiki link: with additional interwiki prefix (bug 61357)
+!! wikitext
+[[local:meatball:Hello]]
+!! html
+<p><a href="http://www.usemod.com/cgi-bin/mb.pl?Hello" class="extiw" title="meatball:Hello">local:meatball:Hello</a>
+</p>
+!! end
+
 ###
 ### Interlanguage links
 ### Language links (so that searching for '### language' matches..)
@@ -6366,9 +6440,25 @@ Interlanguage link
 !! wikitext
 Blah blah blah
 [[zh:Chinese]]
-!! html
+!! html/php
+<p>Blah blah blah
+</p>
+!! html/parsoid
+<p>Blah blah blah
+<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p>
+!! end
+
+!! test
+Interlanguage link with spacing
+!! wikitext
+Blah blah blah
+[[   zh  :    Chinese     ]]
+!! html/php
 <p>Blah blah blah
 </p>
+!! html/parsoid
+<p>Blah blah blah
+<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p>
 !! end
 
 !! test
@@ -6377,9 +6467,13 @@ Double interlanguage link
 Blah blah blah
 [[es:Spanish]]
 [[zh:Chinese]]
-!! html
+!! html/php
 <p>Blah blah blah
 </p>
+!! html/parsoid
+<p>Blah blah blah
+<link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/Spanish"/>
+<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p>
 !! end
 
 !! test
@@ -6389,9 +6483,12 @@ language=ln
 !! wikitext
 Blah blah blah
 [[zh:Chinese]]
-!! html
+!! html/php
 <p>Blah blah blah
 </p>
+!! html/parsoid
+<p>Blah blah blah
+<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p>
 !! end
 
 !! test
@@ -6402,19 +6499,26 @@ language=ln
 Blah blah blah
 [[es:Spanish]]
 [[zh:Chinese]]
-!! html
+!! html/php
 <p>Blah blah blah
 </p>
+!! html/parsoid
+<p>Blah blah blah
+<link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/Spanish"/>
+<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p>
 !! end
 
 !! test
 "Extra" interlanguage links (bug 32189 / gerrit 111390)
 !! wikitext
 Blah blah blah
-[[mul:Multilingual]]
-!! html
+[[mul:Article]]
+!! html/php
 <p>Blah blah blah
 </p>
+!! html/parsoid
+<p>Blah blah blah
+<link rel="mw:PageProp/Language" title="Multilingual" href="//wikisource.org/wiki/Article"/></p>
 !! end
 
 !! test
@@ -6485,6 +6589,28 @@ parsoid
 <p><a rel="mw:WikiLink" href="./Foo" data-parsoid='{"stx":"simple","a":{"href":"./Foo"},"sa":{"href":"en:Foo"}}'>Foo</a></p>
 !! end
 
+!! test
+Interlanguage link with preceding local interwiki link (bug 68085)
+!! wikitext
+Blah blah blah
+[[local:es:Spanish]]
+!! html
+<p>Blah blah blah
+<a href="http://es.wikipedia.org/wiki/Spanish" class="extiw" title="es:Spanish">local:es:Spanish</a>
+</p>
+!! end
+
+!! test
+Looks like an interlanguage link, but is actually a local interwiki
+!! wikitext
+Blah blah blah
+[[mi:Template:Foo]]
+!! html
+<p>Blah blah blah
+<a href="/wiki/Template:Foo" title="Template:Foo">mi:Template:Foo</a>
+</p>
+!! end
+
 ###
 ### Redirects, Parsoid-only
 ###
@@ -8674,6 +8800,42 @@ Un-closed <includeonly>
 !! html
 !! end
 
+!! test
+Includes and comments at SOL
+!! wikitext
+<!-- comment --><noinclude><!-- comment --></noinclude><!-- comment -->== hu ==
+
+<noinclude>
+some
+</noinclude>* stuff
+* here
+
+<includeonly>can have stuff</includeonly>=== here ===
+
+!! html/php
+<h2><span class="mw-headline" id="hu">hu</span></h2>
+<p>some
+</p>
+<ul><li> stuff</li>
+<li> here</li></ul>
+<h3><span class="mw-headline" id="here">here</span></h3>
+
+!! html/parsoid
+<!-- comment --><meta typeof="mw:Includes/NoInclude" data-parsoid='{"src":"&lt;noinclude>"}'/><!-- comment --><meta typeof="mw:Includes/NoInclude/End" data-parsoid='{"src":"&lt;/noinclude>"}'/><!-- comment -->
+<h2 data-parsoid='{}'> hu </h2>
+
+<meta typeof="mw:Includes/NoInclude" data-parsoid='{"src":"&lt;noinclude>"}'/>
+
+<p data-parsoid='{}'>some</p>
+<meta typeof="mw:Includes/NoInclude/End" data-parsoid='{"src":"&lt;/noinclude>"}'/>
+<ul data-parsoid='{}'>
+<li data-parsoid='{}'> stuff</li>
+
+<li data-parsoid='{}'> here</li></ul>
+
+<h3 data-parsoid='{}'> here </h3>
+!! end
+
 # TODO: test with DOM fragment reuse!
 !! test
 Parsoid: DOM fragment reuse
@@ -8843,9 +9005,10 @@ parsoid=wt2html,wt2wt
 |c
 |}
 !!html/parsoid
-<meta typeof="mw:Includes/IncludeOnly" data-parsoid='{"src":"&lt;includeonly>a&lt;/includeonly>"}'/><meta typeof="mw:Includes/IncludeOnly/End" data-parsoid='{"src":"&lt;/includeonly>"}'/><span data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true}'>{{{b}}}</span><table about="#mwt1" typeof="mw:Param" data-parsoid='{"a":{" ":null},"sa":{" ":""},"src":"{| {{{b}}}\n|c\n|}"}'>
+<meta typeof="mw:Includes/IncludeOnly" data-parsoid='{"src":"&lt;includeonly>a&lt;/includeonly>"'/><meta typeof="mw:Includes/IncludeOnly/End" data-parsoid='{"src":""}'/><table about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"{{{b}}}","html":"&lt;span about=\"#mwt1\" typeof=\"mw:Param\" data-parsoid=\"{&amp;quot;dsr&amp;quot;:[31,38,null,null],&amp;quot;src&amp;quot;:&amp;quot;{{{b}}}&amp;quot;}\">{{{b}}}&lt;/span>"},{"html":""}]]}' data-parsoid='{"a":{"{{{b}}}":null},"sa":{"{{{b}}}":""}}'>
 <tbody><tr><td>c</td></tr>
 </tbody></table>
+
 !!end
 
 ###
@@ -11886,15 +12049,19 @@ parsoid
 ### Inter-language links
 ###
 !! test
-Inter-language links
+Interlanguage links
 !! options
 ill
 !! wikitext
 [[es:Alimento]]
 [[fr:Nourriture]]
-[[zh:&#39135;&#21697;]]
-!! html
+[[zh:食品]]
+!! html/php
 es:Alimento fr:Nourriture zh:食品
+!! html/parsoid
+<p><link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/Alimento"/>
+<link rel="mw:PageProp/Language" href="//fr.wikipedia.org/wiki/Nourriture"/>
+<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/食品"/></p>
 !! end
 
 !! test
@@ -11906,8 +12073,13 @@ ill
 [[es:2]]
 [[fr:1]]
 [[fr:2]]
-!! html
+!! html/php
 es:1 fr:1
+!! html/parsoid
+<p><link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/1"/>
+<link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/2"/>
+<link rel="mw:PageProp/Language" href="//fr.wikipedia.org/wiki/1"/>
+<link rel="mw:PageProp/Language" href="//fr.wikipedia.org/wiki/2"/></p>
 !! end
 
 ###
@@ -18436,12 +18608,12 @@ B <ref group="X" name="b" />
 <ref name="b">foo</ref>
 </references>
 !! html
-<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo bar for a"},"attrs":{}}' id="cite_ref-2-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"&lt;ref>foo bar for a&lt;/ref>"}'><a href="#cite_note-2" data-parsoid="{}">[2]</a></span>
-B <span about="#mwt4" class="reference" data-mw='{"name":"ref","attrs":{"group":"X","name":"b"}}' id="cite_ref-b-3-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"&lt;ref name=\"b\" group=\"X\" />"}'><a href="#cite_note-b-3" data-parsoid="{}">[X 1]</a></span></p>
+<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo bar for a"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"&lt;ref>foo bar for a&lt;/ref>"}'><a href="#cite_note-1" data-parsoid="{}">[1]</a></span>
+B <span about="#mwt4" class="reference" data-mw='{"name":"ref","attrs":{"group":"X","name":"b"}}' id="cite_ref-b-2-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"&lt;ref group=\"X\" name=\"b\" />"}'><a href="#cite_note-b-2" data-parsoid="{}">[X 1]</a></span></p>
 
-<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-parsoid='{"src":"&lt;references />"}' data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-b-1" id="cite_note-b-1" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}">↑</span> foo</li><li about="#cite_note-2" id="cite_note-2" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}"><a href="#cite_ref-2-0" data-parsoid="{}">↑</a></span> foo bar for a</li></ol>
+<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-parsoid='{"src":"&lt;references />"}' data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}"><a href="#cite_ref-1-0" data-parsoid="{}">↑</a></span> foo bar for a</li></ol>
 
-<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-parsoid='{"src":"&lt;references group=\"X\">\n&lt;ref name=\"b\">foo&lt;/ref>\n&lt;/references>","group":"X"}' data-mw='{"name":"references","body":{"extsrc":"&lt;ref name=\"b\">foo&lt;/ref>","html":"\n&lt;span about=\"#mwt10\" class=\"reference\" data-mw=&#39;{\"name\":\"ref\",\"body\":{\"html\":\"foo\"},\"attrs\":{\"name\":\"b\"}}&#39; rel=\"dc:references\" typeof=\"mw:Extension/ref\">&lt;a href=\"#cite_note-b-1\">[1]&lt;/a>&lt;/span>\n"},"attrs":{"group":"X"}}'><li about="#cite_note-b-3" id="cite_note-b-3" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}"><a href="#cite_ref-b-3-0" data-parsoid="{}">↑</a></span> </li></ol>
+<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-parsoid='{"src":"&lt;references group=\"X\">\n&lt;ref name=\"b\">foo&lt;/ref>\n&lt;/references>","group":"X"}' data-mw='{"name":"references","body":{"extsrc":"&lt;ref name=\"b\">foo&lt;/ref>","html":"\n&lt;span about=\"#mwt10\" class=\"reference\" data-mw=&#39;{\"name\":\"ref\",\"body\":{\"html\":\"foo\"},\"attrs\":{\"name\":\"b\"}}&#39; rel=\"dc:references\" typeof=\"mw:Extension/ref\">&lt;a href=\"#cite_note-b-2\">[X 1]&lt;/a>&lt;/span>\n"},"attrs":{"group":"X"}}'><li about="#cite_note-b-2" id="cite_note-b-2" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}"><a href="#cite_ref-b-2-0" data-parsoid="{}">↑</a></span> foo</li></ol>
 !! end
 
 !! test
@@ -19582,6 +19754,16 @@ parsoid
  <figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure>
 !! end
 
+!! test
+5. Nowiki escaping should account for indent-pres
+!! options
+parsoid=html2wt
+!! html
+<pre>==foo==</pre>
+!! wikitext
+ ==foo==
+!! end
+
 #### --------------- Behavior Switches --------------------
 !! test
 1. Valid behavior switches should be escaped
@@ -20374,6 +20556,17 @@ parsoid=html2wt
 # All these tests are marked Parsoid html2wt and html2html only
 # ----------------------------------------------------------------
 
+!! test
+Serialize interwiki links pointing to the current wiki as plain wiki links (bug 65869)
+!! options
+parsoid=html2wt
+language=es
+!! wikitext
+[[Foo]]
+!! html
+<p><a rel="mw:ExtLink" href="http://es.wikipedia.org/wiki/Foo">Foo</a></p>
+!! end
+
 !! test
 Image: Modifying size of an image (1)
 !! options
index f67fe02..6ebbcb2 100644 (file)
@@ -23,14 +23,8 @@ class LessFileCompilationTest extends MediaWikiTestCase {
         * @param string $file
         * @param ResourceLoaderModule $module The ResourceLoader module that
         *   contains the file
-        * @throws PHPUnit_Framework_Exception When the file parameter isn't a
-        *   string or readable file
         */
        public function __construct( $file, ResourceLoaderModule $module ) {
-               if ( !is_string( $file ) || !is_file( $file ) || !is_readable( $file ) ) {
-                       throw PHPUnit_Util_InvalidArgumentHelper::factory( 1, 'readable file' );
-               }
-
                parent::__construct( 'testLessFileCompilation' );
 
                $this->file = $file;
@@ -38,6 +32,12 @@ class LessFileCompilationTest extends MediaWikiTestCase {
        }
 
        public function testLessFileCompilation() {
+               $thisString = $this->toString();
+               $this->assertTrue(
+                       is_string( $this->file ) && is_file( $this->file ) && is_readable( $this->file ),
+                       "$thisString must refer to a readable file"
+               );
+
                $compiler = ResourceLoader::getLessCompiler();
                $this->assertNotNull( $compiler->compileFile( $this->file ) );
        }
index c9184e8..3015895 100644 (file)
@@ -246,6 +246,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                }
                $this->mwGlobals = array();
                RequestContext::resetMain();
+               MediaHandler::resetCache();
 
                $phpErrorLevel = intval( ini_get( 'error_reporting' ) );
 
index daf4bd9..f316f56 100644 (file)
@@ -43,6 +43,8 @@ class ResourceLoaderTestModule extends ResourceLoaderModule {
        protected $dependencies = array();
        protected $group = null;
        protected $source = 'local';
+       protected $script = '';
+       protected $styles = '';
        protected $skipFunction = null;
        protected $targets = array( 'test' );
 
@@ -52,6 +54,14 @@ class ResourceLoaderTestModule extends ResourceLoaderModule {
                }
        }
 
+       public function getScript( ResourceLoaderContext $context ) {
+               return $this->script;
+       }
+
+       public function getStyles( ResourceLoaderContext $context ) {
+               return array( '' => $this->styles );
+       }
+
        public function getDependencies() {
                return $this->dependencies;
        }
index ca132a4..9913f68 100644 (file)
@@ -55,3 +55,7 @@ Bishzilla_blink.gif
 https://commons.wikimedia.org/wiki/File:Bishzilla_blink.gif
 Public domain
 Bishonen
+
+say-test.ogg
+Public domain
+Brian Wolff
diff --git a/tests/phpunit/data/media/say-test.ogg b/tests/phpunit/data/media/say-test.ogg
new file mode 100644 (file)
index 0000000..5d814fb
Binary files /dev/null and b/tests/phpunit/data/media/say-test.ogg differ
index 3e5ebb7..7bdb1ca 100644 (file)
@@ -24,14 +24,14 @@ class ArrayUtilsTest extends MediaWikiTestCase {
 
        function provideFindLowerBound() {
                $self = $this;
-               $indexValueCallback = function( $size ) use ( $self ) {
-                       return function( $val ) use ( $self, $size ) {
+               $indexValueCallback = function ( $size ) use ( $self ) {
+                       return function ( $val ) use ( $self, $size ) {
                                $self->assertTrue( $val >= 0 );
                                $self->assertTrue( $val < $size );
                                return $val;
                        };
                };
-               $comparisonCallback = function( $a, $b ) {
+               $comparisonCallback = function ( $a, $b ) {
                        return $a - $b;
                };
 
index 3c653b4..28c35b3 100644 (file)
@@ -82,7 +82,7 @@ class EditPageTest extends MediaWikiLangTestCase {
         *              * wpMinorEdit: mark as minor edit
         *              * wpWatchthis: whether to watch the page
         * @param int|null $expectedCode The expected result code (EditPage::AS_XXX constants).
-        *                  Set to null to skip the check. Defaults to EditPage::AS_OK.
+        *                  Set to null to skip the check.
         * @param string|null $expectedText The text expected to be on the page after the edit.
         *                  Set to null to skip the check.
         * @param string|null $message An optional message to show along with any error message.
@@ -90,12 +90,13 @@ class EditPageTest extends MediaWikiLangTestCase {
         * @return WikiPage The page that was just edited, useful for getting the edit's rev_id, etc.
         */
        protected function assertEdit( $title, $baseText, $user = null, array $edit,
-               $expectedCode = EditPage::AS_OK, $expectedText = null, $message = null
+               $expectedCode = null, $expectedText = null, $message = null
        ) {
                if ( is_string( $title ) ) {
                        $ns = $this->getDefaultWikitextNS();
                        $title = Title::newFromText( $title, $ns );
                }
+               $this->assertNotNull( $title );
 
                if ( is_string( $user ) ) {
                        $user = User::newFromName( $user );
@@ -141,7 +142,9 @@ class EditPageTest extends MediaWikiLangTestCase {
 
                $req = new FauxRequest( $edit, true ); // session ??
 
-               $ep = new EditPage( new Article( $title ) );
+               $article = new Article( $title );
+               $article->getContext()->setTitle( $title );
+               $ep = new EditPage( $article );
                $ep->setContextTitle( $title );
                $ep->importFormData( $req );
 
index 7c684d5..e22f505 100644 (file)
@@ -6,7 +6,7 @@ class GitInfoTest extends MediaWikiTestCase {
 
        protected function setUp() {
                parent::setUp();
-               $this->setMwGlobals( 'wgCacheDirectory', __DIR__ . '/../data' );
+               $this->setMwGlobals( 'wgGitInfoCacheDirectory', __DIR__ . '/../data/gitinfo' );
        }
 
        public function testValidJsonData() {
index 06b512d..84799ff 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group GlobalFunctions
+ */
 class GlobalTest extends MediaWikiTestCase {
        protected function setUp() {
                parent::setUp();
@@ -369,6 +372,8 @@ class GlobalTest extends MediaWikiTestCase {
         * @covers ::swap
         */
        public function testSwapVarsTest() {
+               $this->hideDeprecated( 'swap' );
+
                $var1 = 1;
                $var2 = 2;
 
@@ -716,5 +721,5 @@ class GlobalTest extends MediaWikiTestCase {
                        ),
                );
        }
-       /* @TODO many more! */
+       /* @todo many more! */
 }
index cf891e7..9588ffd 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @group GlobalFunctions
  * @group Database
  */
 class GlobalWithDBTest extends MediaWikiTestCase {
index 9bb7487..13f49f7 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 /**
+ * @group GlobalFunctions
  * @covers ::wfAssembleUrl
  */
 class WfAssembleUrlTest extends MediaWikiTestCase {
index a01c0d4..041adb8 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 /**
+ * @group GlobalFunctions
  * @covers ::wfBCP47
  */
 class WfBCP47Test extends MediaWikiTestCase {
index 79dd91d..dd4f9cc 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 /**
+ * @group GlobalFunctions
  * @covers ::wfBaseConvert
  */
 class WfBaseConvertTest extends MediaWikiTestCase {
index 516c1b9..705730a 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 /**
+ * @group GlobalFunctions
  * @covers ::wfBaseName
  */
 class WfBaseNameTest extends MediaWikiTestCase {
index 9effc30..a69defb 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 /**
+ * @group GlobalFunctions
  * @covers ::wfExpandUrl
  */
 class WfExpandUrlTest extends MediaWikiTestCase {
index bdb3044..bb2b33f 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @group GlobalFunctions
  * @covers ::wfGetCaller
  */
 class WfGetCallerTest extends MediaWikiTestCase {
index af834f8..232fa92 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 /**
+ * @group GlobalFunctions
  * @covers ::wfParseUrl
  */
 class WfParseUrlTest extends MediaWikiTestCase {
index 238a2c9..05155db 100644 (file)
@@ -1,5 +1,7 @@
 <?php
+
 /**
+ * @group GlobalFunctions
  *@covers ::wfRemoveDotSegments
  */
 class WfRemoveDotSegmentsTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/GlobalFunctions/wfShellExecTest.php b/tests/phpunit/includes/GlobalFunctions/wfShellExecTest.php
new file mode 100644 (file)
index 0000000..fcd26f5
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @group GlobalFunctions
+ * @covers ::wfShellExec
+ */
+class WfShellExecTest extends MediaWikiTestCase {
+       public function testBug67870() {
+               $command = wfIsWindows()
+                       // 333 = 331 + CRLF
+                       ? ( 'for /l %i in (1, 1, 1001) do @echo ' . str_repeat( '*', 331 ) )
+                       : 'printf "%-333333s" "*"';
+
+               // Test several times because it involves a race condition that may randomly succeed or fail
+               for ( $i = 0; $i < 10; $i++ ) {
+                       $output = wfShellExec( $command );
+                       $this->assertEquals( 333333, strlen( $output ) );
+               }
+       }
+}
index aadec87..67284d2 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @group GlobalFunctions
  * @covers ::wfShorthandToInteger
  */
 class WfShorthandToIntegerTest extends MediaWikiTestCase {
index fac9b88..bea496c 100644 (file)
@@ -1,5 +1,7 @@
 <?php
-/*
+
+/**
+ * @group GlobalFunctions
  * @covers ::wfTimestamp
  */
 class WfTimestampTest extends MediaWikiTestCase {
@@ -92,7 +94,7 @@ class WfTimestampTest extends MediaWikiTestCase {
                if ( substr( $output, 0, 1 ) === '/' ) {
                        // Bug 64946: Day of the week calculations for very old
                        // timestamps varies from system to system.
-                       $this->assertRegExp(  $output, $timestamp, $message );
+                       $this->assertRegExp( $output, $timestamp, $message );
                } else {
                        $this->assertEquals( $output, $timestamp, $message );
                }
index 783b985..d11668b 100644 (file)
@@ -1,6 +1,9 @@
 <?php
+
 /**
  * The function only need a string parameter and might react to IIS7.0
+ *
+ * @group GlobalFunctions
  * @covers ::wfUrlencode
  */
 class WfUrlencodeTest extends MediaWikiTestCase {
index c1b637b..ae5c9c4 100644 (file)
@@ -40,16 +40,16 @@ class HtmlFormatterTest extends MediaWikiTestCase {
        }
 
        public function getHtmlData() {
-               $removeImages = function( HtmlFormatter $f ) {
+               $removeImages = function ( HtmlFormatter $f ) {
                        $f->setRemoveMedia();
                };
-               $removeTags = function( HtmlFormatter $f ) {
+               $removeTags = function ( HtmlFormatter $f ) {
                        $f->remove( array( 'table', '.foo', '#bar', 'div.baz' ) );
                };
-               $flattenSomeStuff = function( HtmlFormatter $f ) {
+               $flattenSomeStuff = function ( HtmlFormatter $f ) {
                        $f->flatten( array( 's', 'div' ) );
                };
-               $flattenEverything = function( HtmlFormatter $f ) {
+               $flattenEverything = function ( HtmlFormatter $f ) {
                        $f->flattenAllTags();
                };
                return array(
index e934965..c561e70 100644 (file)
@@ -112,7 +112,8 @@ class HtmlTest extends MediaWikiTestCase {
                        Html::expandAttributes( array( 'foo' => false ) ),
                        'skip keys with false value'
                );
-               $this->assertNotEmpty(
+               $this->assertEquals(
+                       ' foo=""',
                        Html::expandAttributes( array( 'foo' => '' ) ),
                        'keep keys with an empty string'
                );
@@ -153,6 +154,33 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers HTML::expandAttributes
+        */
+       public function testExpandAttributesForNumbers() {
+               $this->assertEquals(
+                       ' value=1',
+                       Html::expandAttributes( array( 'value' => 1 ) ),
+                       'Integer value is cast to a string'
+               );
+               $this->assertEquals(
+                       ' value=1.1',
+                       Html::expandAttributes( array( 'value' => 1.1 ) ),
+                       'Float value is cast to a string'
+               );
+       }
+
+       /**
+        * @covers HTML::expandAttributes
+        */
+       public function testExpandAttributesForObjects() {
+               $this->assertEquals(
+                       ' value=stringValue',
+                       Html::expandAttributes( array( 'value' => new HtmlTestValue() ) ),
+                       'Object value is converted to a string'
+               );
+       }
+
        /**
         * Test for Html::expandAttributes()
         * Please note it output a string prefixed with a space!
@@ -299,6 +327,21 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers Html::expandAttributes
+        * @expectedException MWException
+        */
+       public function testExpandAttributes_ArrayOnNonListValueAttribute_ThrowsException() {
+               // Real-life test case found in the Popups extension (see Gerrit cf0fd64),
+               // when used with an outdated BetaFeatures extension (see Gerrit deda1e7)
+               Html::expandAttributes( array(
+                       'src' => array(
+                               'ltr' => 'ltr.svg',
+                               'rtl' => 'rtl.svg'
+                       )
+               ) );
+       }
+
        /**
         * @covers Html::namespaceSelector
         */
@@ -665,3 +708,9 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 }
+
+class HtmlTestValue {
+       function __toString() {
+               return 'stringValue';
+       }
+}
diff --git a/tests/phpunit/includes/ImagePage404Test.php b/tests/phpunit/includes/ImagePage404Test.php
new file mode 100644 (file)
index 0000000..3660456
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**
+ * For doing Image Page tests that rely on 404 thumb handling
+ */
+class ImagePage404Test extends MediaWikiMediaTestCase {
+
+       protected function getRepoOptions() {
+               return parent::getRepoOptions() + array( 'transformVia404' => true );
+       }
+
+       function setUp() {
+               $this->setMwGlobals( 'wgImageLimits', array(
+                       array( 320, 240 ),
+                       array( 640, 480 ),
+                       array( 800, 600 ),
+                       array( 1024, 768 ),
+                       array( 1280, 1024 )
+               ) );
+               parent::setUp();
+       }
+
+       function getImagePage( $filename ) {
+               $title = Title::makeTitleSafe( NS_FILE, $filename );
+               $file = $this->dataFile( $filename );
+               $iPage = new ImagePage( $title );
+               $iPage->setFile( $file );
+               return $iPage;
+       }
+
+       /**
+        * @dataProvider providerGetThumbSizes
+        * @param $filename String
+        * @param $expectedNumberThumbs integer How many thumbnails to show
+        */
+       function testGetThumbSizes( $filename, $expectedNumberThumbs ) {
+               $iPage = $this->getImagePage( $filename );
+               $reflection = new ReflectionClass( $iPage );
+               $reflMethod = $reflection->getMethod( 'getThumbSizes' );
+               $reflMethod->setAccessible( true );
+
+               $actual = $reflMethod->invoke( $iPage, 545, 700 );
+               $this->assertEquals( count( $actual ), $expectedNumberThumbs );
+       }
+
+       function providerGetThumbSizes() {
+               return array(
+                       array( 'animated.gif', 6 ),
+                       array( 'Toll_Texas_1.svg', 6 ),
+                       array( '80x60-Greyscale.xcf', 6 ),
+                       array( 'jpeg-comment-binary.jpg', 6 ),
+               );
+       }
+}
diff --git a/tests/phpunit/includes/ImagePageTest.php b/tests/phpunit/includes/ImagePageTest.php
new file mode 100644 (file)
index 0000000..d5ecb95
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+class ImagePageTest extends MediaWikiMediaTestCase {
+
+       function setUp() {
+               $this->setMwGlobals( 'wgImageLimits', array(
+                       array( 320, 240 ),
+                       array( 640, 480 ),
+                       array( 800, 600 ),
+                       array( 1024, 768 ),
+                       array( 1280, 1024 )
+               ) );
+               parent::setUp();
+       }
+
+       function getImagePage( $filename ) {
+               $title = Title::makeTitleSafe( NS_FILE, $filename );
+               $file = $this->dataFile( $filename );
+               $iPage = new ImagePage( $title );
+               $iPage->setFile( $file );
+               return $iPage;
+       }
+
+       /**
+        * @dataProvider providerGetDisplayWidthHeight
+        * @param $dimensions Array [maxWidth, maxHeight, width, height]
+        * @param $expected Array [width, height] The width and height we expect to display at
+        */
+       function testGetDisplayWidthHeight( $dim, $expected ) {
+               $iPage = $this->getImagePage( 'animated.gif' );
+               $reflection = new ReflectionClass( $iPage );
+               $reflMethod = $reflection->getMethod( 'getDisplayWidthHeight' );
+               $reflMethod->setAccessible( true );
+
+               $actual = $reflMethod->invoke( $iPage, $dim[0], $dim[1], $dim[2], $dim[3] );
+               $this->assertEquals( $actual, $expected );
+       }
+
+       function providerGetDisplayWidthHeight() {
+               return array(
+                       array(
+                               array( 1024.0, 768.0, 600.0, 600.0 ),
+                               array( 600.0, 600.0 )
+                       ),
+                       array(
+                               array( 1024.0, 768.0, 1600.0, 600.0 ),
+                               array( 1024.0, 384.0 )
+                       ),
+                       array(
+                               array( 1024.0, 768.0, 1024.0, 768.0 ),
+                               array( 1024.0, 768.0 )
+                       ),
+                       array(
+                               array( 1024.0, 768.0, 800.0, 1000.0 ),
+                               array( 614.0, 768.0 )
+                       ),
+                       array(
+                               array( 1024.0, 768.0, 0, 1000 ),
+                               array( 0, 0 )
+                       ),
+                       array(
+                               array( 1024.0, 768.0, 2000, 0 ),
+                               array( 0, 0 )
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider providerGetThumbSizes
+        * @param $filename String
+        * @param $expectedNumberThumbs integer How many thumbnails to show
+        */
+       function testGetThumbSizes( $filename, $expectedNumberThumbs ) {
+               $iPage = $this->getImagePage( $filename );
+               $reflection = new ReflectionClass( $iPage );
+               $reflMethod = $reflection->getMethod( 'getThumbSizes' );
+               $reflMethod->setAccessible( true );
+
+               $actual = $reflMethod->invoke( $iPage, 545, 700 );
+               $this->assertEquals( count( $actual ), $expectedNumberThumbs );
+       }
+
+       function providerGetThumbSizes() {
+               return array(
+                       array( 'animated.gif', 2 ),
+                       array( 'Toll_Texas_1.svg', 1 ),
+                       array( '80x60-Greyscale.xcf', 1 ),
+                       array( 'jpeg-comment-binary.jpg', 2 ),
+               );
+       }
+}
index 8895403..f82a756 100644 (file)
@@ -26,8 +26,8 @@ class ImportTest extends MediaWikiLangTestCase {
        public function testHandlePageContainsRedirect( $xml, $redirectTitle ) {
                $source = $this->getInputStreamSource( $xml );
 
-               $redirect = NULL;
-               $callback = function( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) use ( &$redirect ) {
+               $redirect = null;
+               $callback = function ( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) use ( &$redirect ) {
                        if ( array_key_exists( 'redirect', $pageInfo ) ) {
                                $redirect = $pageInfo['redirect'];
                        }
@@ -92,7 +92,7 @@ EOF
 </mediawiki>
 EOF
                        ,
-                               NULL
+                               null
                        ),
                );
        }
index 4d62cc7..72114e9 100644 (file)
@@ -94,6 +94,7 @@ class LinkerTest extends MediaWikiLangTestCase {
                        'wgScript' => '/wiki/index.php',
                        'wgArticlePath' => '/wiki/$1',
                        'wgWellFormedXml' => true,
+                       'wgCapitalLinks' => true,
                ) );
 
                if ( $title === false ) {
index 9ff547c..02f6b2a 100644 (file)
@@ -186,6 +186,10 @@ class LinksUpdateTest extends MediaWikiTestCase {
         * @covers ParserOutput::addLanguageLink
         */
        public function testUpdate_langlinks() {
+               $this->setMwGlobals( array(
+                       'wgCapitalLinks' => true,
+               ) );
+
                /** @var ParserOutput $po */
                list( $t, $po ) = $this->makeTitleAndParserOutput( "Testing", 111 );
 
@@ -211,8 +215,8 @@ class LinksUpdateTest extends MediaWikiTestCase {
                $po->setProperty( "bool", true );
                $expected[] = array( "bool", true );
 
-               $po->setProperty( "float", 4.0 + 1.0/4.0 );
-               $expected[] = array( "float", 4.0 + 1.0/4.0 );
+               $po->setProperty( "float", 4.0 + 1.0 / 4.0 );
+               $expected[] = array( "float", 4.0 + 1.0 / 4.0 );
 
                $po->setProperty( "int", -7 );
                $expected[] = array( "int", -7 );
index 350e83f..311350b 100644 (file)
@@ -9,7 +9,7 @@
  * Test class for MWNamespace.
  * Generated by PHPUnit on 2011-02-20 at 21:01:55.
  * @todo covers tags
- * @FIXME this test file is a mess
+ * @todo FIXME: this test file is a mess
  *
  */
 class MWNamespaceTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/MimeMagicTest.php b/tests/phpunit/includes/MimeMagicTest.php
new file mode 100644 (file)
index 0000000..a164ff9
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+class MimeMagicTest extends MediaWikiTestCase {
+
+       /** @var MimeMagic */
+       private $mimeMagic;
+
+       function setUp() {
+               $this->mimeMagic = MimeMagic::singleton();
+               parent::setUp();
+       }
+
+       /**
+        * @dataProvider providerImproveTypeFromExtension
+        * @param $ext String File extension (no leading dot)
+        * @param $oldMime String Initially detected mime
+        * @param $expectedMime String Mime type after taking extension into account
+        */
+       function testImproveTypeFromExtension( $ext, $oldMime, $expectedMime ) {
+               $actualMime = $this->mimeMagic->improveTypeFromExtension( $oldMime, $ext );
+               $this->assertEquals( $expectedMime, $actualMime );
+       }
+
+       function providerImproveTypeFromExtension() {
+               return array(
+                       array( 'gif', 'image/gif', 'image/gif' ),
+                       array( 'gif', 'unknown/unknown', 'unknown/unknown' ),
+                       array( 'wrl', 'unknown/unknown', 'model/vrml' ),
+                       array( 'txt', 'text/plain', 'text/plain' ),
+                       array( 'csv', 'text/plain', 'text/csv' ),
+                       array( 'tsv', 'text/plain', 'text/tab-separated-values' ),
+                       array( 'json', 'text/plain', 'application/json' ),
+                       array( 'foo', 'application/x-opc+zip', 'application/zip' ),
+                       array( 'docx', 'application/x-opc+zip', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ),
+                       array( 'djvu', 'image/x-djvu', 'image/vnd.djvu' ),
+                       array( 'wav', 'audio/wav', 'audio/wav' ),
+               );
+       }
+
+       /**
+        * Test to make sure that encoder=ffmpeg2theora doesn't trigger
+        * MEDIATYPE_VIDEO (bug 63584)
+        */
+       function testOggRecognize() {
+               $oggFile = __DIR__ . '/../data/media/say-test.ogg';
+               $actualType = $this->mimeMagic->getMediaType( $oggFile, 'application/ogg' );
+               $this->assertEquals( $actualType, MEDIATYPE_AUDIO );
+       }
+}
index 385cee5..f68b3b1 100644 (file)
@@ -38,7 +38,7 @@ class OutputPageTest extends MediaWikiTestCase {
                }
 
                $fauxRequest = new FauxRequest( $queryData, false );
-               $this->setMWGlobals( array(
+               $this->setMwGlobals( array(
                        'wgRequest' => $fauxRequest,
                ) );
 
@@ -135,4 +135,89 @@ class OutputPageTest extends MediaWikiTestCase {
                        'message' => 'On request with handheld querystring and media is screen, returns null'
                ) );
        }
+
+       public static function provideMakeResourceLoaderLink() {
+               return array(
+                       // Load module script only
+                       array(
+                               array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ),
+                               '<script src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.foo&amp;only=scripts&amp;skin=vector&amp;*"></script>
+'
+                       ),
+                       // Load module styles only
+                       // This also tests the order the modules are put into the url
+                       array(
+                               array( array( 'test.baz', 'test.foo', 'test.bar' ), ResourceLoaderModule::TYPE_STYLES ),
+                               '<link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.bar%2Cbaz%2Cfoo&amp;only=styles&amp;skin=vector&amp;*">
+'
+                       ),
+                       // Load private module (combined)
+                       array(
+                               array( 'test.quux', ResourceLoaderModule::TYPE_COMBINED ),
+                               '<script>if(window.mw){
+mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"css":[".mw-icon{transition:none}\n/* cache key: wiki:resourceloader:filter:minify-css:7:fd8ea20b3336b2bfb230c789d430067a */"]},{});
+/* cache key: wiki:resourceloader:filter:minify-js:7:274ccee17be73cd5f4dda5dc2a819188 */
+}</script>
+'
+                       ),
+                       // Load module script with with ESI
+                       array(
+                               array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS, true ),
+                               '<script><esi:include src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.foo&amp;only=scripts&amp;skin=vector&amp;*" /></script>
+'
+                       ),
+                       // Load module styles with with ESI
+                       array(
+                               array( 'test.foo', ResourceLoaderModule::TYPE_STYLES, true ),
+                               '<style><esi:include src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.foo&amp;only=styles&amp;skin=vector&amp;*" /></style>
+',
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider provideMakeResourceLoaderLink
+        * @covers OutputPage::makeResourceLoaderLink
+        */
+       public function testMakeResourceLoaderLink( $args, $expectedHtml ) {
+               $this->setMwGlobals( array(
+                       'wgResourceLoaderDebug' => false,
+                       'wgResourceLoaderUseESI' => true,
+                       'wgLoadScript' => 'http://127.0.0.1:8080/w/load.php',
+                       // Affects whether CDATA is inserted
+                       'wgWellFormedXml' => false,
+                       // Cache key is based on database name, and affects output;
+                       // this test should not touch the database anyways.
+                       'wgDBname' => 'wiki',
+                       'wgDBprefix' => '',
+               ) );
+               $class = new ReflectionClass( 'OutputPage' );
+               $method = $class->getMethod( 'makeResourceLoaderLink' );
+               $method->setAccessible( true );
+               $ctx = new RequestContext();
+               $ctx->setLanguage( 'en' );
+               $out = new OutputPage( $ctx );
+               $rl = $out->getResourceLoader();
+               $rl->register( array(
+                       'test.foo' => new ResourceLoaderTestModule( array(
+                               'script' => 'mw.test.foo( { a: true } );',
+                               'styles' => '.mw-test-foo { content: "style"; }',
+                       )),
+                       'test.bar' => new ResourceLoaderTestModule( array(
+                               'script' => 'mw.test.bar( { a: true } );',
+                               'styles' => '.mw-test-bar { content: "style"; }',
+                       )),
+                       'test.baz' => new ResourceLoaderTestModule( array(
+                               'script' => 'mw.test.baz( { a: true } );',
+                               'styles' => '.mw-test-baz { content: "style"; }',
+                       )),
+                       'test.quux' => new ResourceLoaderTestModule( array(
+                               'script' => 'mw.test.baz( { token: 123 } );',
+                               'styles' => '/* pref-animate=off */ .mw-icon { transition: none; }',
+                               'group' => 'private',
+                       )),
+               ) );
+               $links = $method->invokeArgs( $out, $args );
+               $this->assertEquals( $expectedHtml, $links['html'] );
+       }
 }
index 758c2e2..6fdc239 100644 (file)
@@ -16,6 +16,7 @@ class TestSample extends MediaWikiLangTestCase {
                $this->setMwGlobals( array(
                        'wgContLang' => Language::factory( 'en' ),
                        'wgLanguageCode' => 'en',
+                       'wgCapitalLinks' => true,
                ) );
        }
 
index f13e838..14911f0 100644 (file)
@@ -2,7 +2,7 @@
 
 /**
  * @covers Sanitizer::validateEmail
- * @TODO all test methods in this class should be refactored and...
+ * @todo all test methods in this class should be refactored and...
  *    use a single test method and a single data provider...
  */
 class SanitizerValidateEmailTest extends MediaWikiTestCase {
index 3829f90..9e2f5b8 100644 (file)
@@ -286,7 +286,7 @@ class StatusTest extends MediaWikiLangTestCase {
        }
 
        public static function provideCleanParams() {
-               $cleanCallback = function( $value ) {
+               $cleanCallback = function ( $value ) {
                        return '-' . $value . '-';
                };
 
@@ -538,7 +538,7 @@ class StatusTest extends MediaWikiLangTestCase {
         */
        public function testWakeUpSanitizesCallback() {
                $status = new Status();
-               $status->cleanCallback = function( $value ) {
+               $status->cleanCallback = function ( $value ) {
                        return '-' . $value . '-';
                };
                $status->__wakeup();
index f0d4c4d..ae82bc4 100644 (file)
@@ -26,7 +26,7 @@ class TimeAdjustTest extends MediaWikiLangTestCase {
                return array(
                        array( '20061231235959', 0, '20061231235959' ),
                        array( '20061231235959', 5, '20070101000459' ),
-                       array( '20061231235959', 15,'20070101001459' ),
+                       array( '20061231235959', 15, '20070101001459' ),
                        array( '20061231235959', 60, '20070101005959' ),
                        array( '20061231235959', 90, '20070101012959' ),
                        array( '20061231235959', 120, '20070101015959' ),
index ac80a9a..988a4a4 100644 (file)
@@ -41,6 +41,9 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
                                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';
index 1c7b662..6871582 100644 (file)
@@ -87,6 +87,7 @@ class TitleTest extends MediaWikiTestCase {
                        str_repeat( 'x', 252 ),
                        // interwiki prefix
                        'localtestiw: #anchor',
+                       'localtestiw:',
                        'localtestiw:foo',
                        'localtestiw: foo # anchor',
                        'localtestiw: Talk: Sandbox # anchor',
@@ -147,7 +148,6 @@ class TitleTest extends MediaWikiTestCase {
                        'Category: ',
                        'Category: #bar',
                        // interwiki prefix
-                       'localtestiw:',
                        'localtestiw: Talk: # anchor',
                        'localtestiw: Talk:'
                ) as $text ) {
index a19d035..36de114 100644 (file)
@@ -125,6 +125,31 @@ class UserTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @dataProvider provideIPs
+        * @covers User::isIP
+        */
+       public function testIsIP( $value, $result, $message ) {
+               $this->assertEquals( $this->user->isIP( $value ), $result, $message );
+       }
+
+       public static function provideIPs() {
+               return array(
+                       array( '', false, 'Empty string' ),
+                       array( ' ', false, 'Blank space' ),
+                       array( '10.0.0.0', true, 'IPv4 private 10/8' ),
+                       array( '10.255.255.255', true, 'IPv4 private 10/8' ),
+                       array( '192.168.1.1', true, 'IPv4 private 192.168/16' ),
+                       array( '203.0.113.0', true, 'IPv4 example' ),
+                       array( '2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff', true, 'IPv6 example' ),
+                       // Not valid IPs but classified as such by MediaWiki for negated asserting
+                       // of whether this might be the identifier of a logged-out user or whether
+                       // to allow usernames like it.
+                       array( '300.300.300.300', true, 'Looks too much like an IPv4 address' ),
+                       array( '203.0.113.xxx', true, 'Assigned by UseMod to cloaked logged-out users' ),
+               );
+       }
+
        /**
         * @dataProvider provideUserNames
         * @covers User::isValidUserName
@@ -148,6 +173,9 @@ class UserTest extends MediaWikiTestCase {
                        array( 'Abcdകഖഗഘ', true, ' Mixed scripts' ),
                        array( 'ജോസ്‌തോമസ്', false, 'ZWNJ- Format control character' ),
                        array( 'Ab cd', false, ' Ideographic space' ),
+                       array( '300.300.300.300', false, 'Looks too much like an IPv4 address' ),
+                       array( '302.113.311.900', false, 'Looks too much like an IPv4 address' ),
+                       array( '203.0.113.xxx', false, 'Reserved for usage by UseMod for cloaked logged-out users' ),
                );
        }
 
@@ -157,7 +185,7 @@ class UserTest extends MediaWikiTestCase {
         * Extensions and core
         */
        public function testAllRightsWithMessage() {
-               //Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
+               // Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
                $allRights = User::getAllRights();
                $allMessageKeys = Language::getMessageKeysFor( 'en' );
 
index 7b12a4a..12d7d2a 100644 (file)
@@ -115,7 +115,7 @@ class WebRequestTest extends MediaWikiTestCase {
                        'wgUsePrivateIPs' => $private,
                        'wgHooks' => array(
                                'IsTrustedProxy' => array(
-                                       function( &$ip, &$trusted ) use ( $xffList ) {
+                                       function ( &$ip, &$trusted ) use ( $xffList ) {
                                                $trusted = $trusted || in_array( $ip, $xffList );
                                                return true;
                                        }
index 78457d2..7f7945b 100644 (file)
@@ -499,6 +499,10 @@ class WikiPageTest extends MediaWikiLangTestCase {
         * @covers WikiPage::getRedirectTarget
         */
        public function testGetRedirectTarget( $title, $model, $text, $target ) {
+               $this->setMwGlobals( array(
+                       'wgCapitalLinks' => true,
+               ) );
+
                $page = $this->createPage( $title, $text, $model );
 
                # sanity check, because this test seems to fail for no reason for some people.
diff --git a/tests/phpunit/includes/actions/ActionTest.php b/tests/phpunit/includes/actions/ActionTest.php
new file mode 100644 (file)
index 0000000..eb370d9
--- /dev/null
@@ -0,0 +1,198 @@
+<?php
+
+/**
+ * @covers Action
+ *
+ * @licence GNU GPL v2+
+ * @author Thiemo Mättig
+ *
+ * @group Action
+ */
+class ActionTest extends MediaWikiTestCase {
+
+       protected function setUp() {
+               parent::setUp();
+
+               $context = $this->getContext();
+               $this->setMwGlobals( 'wgActions', array(
+                       'null' => null,
+                       'disabled' => false,
+                       'view' => true,
+                       'edit' => true,
+                       'revisiondelete' => true,
+                       'dummy' => true,
+                       'string' => 'NamedDummyAction',
+                       'declared' => 'NonExistingClassName',
+                       'callable' => array( $this, 'dummyActionCallback' ),
+                       'object' => new InstantiatedDummyAction( $context->getWikiPage(), $context ),
+               ) );
+       }
+
+       private function getPage() {
+               return WikiPage::factory( Title::makeTitle( 0, 'Title' ) );
+       }
+
+       private function getContext( $requestedAction = null ) {
+               $request = new FauxRequest( array( 'action' => $requestedAction ) );
+
+               $context = new DerivativeContext( RequestContext::getMain() );
+               $context->setRequest( $request );
+               $context->setWikiPage( $this->getPage() );
+
+               return $context;
+       }
+
+       public function actionProvider() {
+               return array(
+                       array( 'dummy', 'DummyAction' ),
+                       array( 'string', 'NamedDummyAction' ),
+                       array( 'callable', 'CalledDummyAction' ),
+                       array( 'object', 'InstantiatedDummyAction' ),
+
+                       // Capitalization is ignored
+                       array( 'DUMMY', 'DummyAction' ),
+                       array( 'STRING', 'NamedDummyAction' ),
+
+                       // Null and non-existing values
+                       array( 'null', null ),
+                       array( 'undeclared', null ),
+                       array( '', null ),
+                       array( false, null ),
+               );
+       }
+
+       /**
+        * @dataProvider actionProvider
+        * @param string $requestedAction
+        * @param string|null $expected
+        */
+       public function testActionExists( $requestedAction, $expected ) {
+               $exists = Action::exists( $requestedAction );
+
+               $this->assertSame( $expected !== null, $exists );
+       }
+
+       public function testActionExists_doesNotRequireInstantiation() {
+               // The method is not supposed to check if the action can be instantiated.
+               $exists = Action::exists( 'declared' );
+
+               $this->assertTrue( $exists );
+       }
+
+       /**
+        * @dataProvider actionProvider
+        * @param string $requestedAction
+        * @param string|null $expected
+        */
+       public function testGetActionName( $requestedAction, $expected ) {
+               $context = $this->getContext( $requestedAction );
+               $actionName = Action::getActionName( $context );
+
+               $this->assertEquals( $expected ?: 'nosuchaction', $actionName );
+       }
+
+       public function testGetActionName_editredlinkWorkaround() {
+               // See https://bugzilla.wikimedia.org/show_bug.cgi?id=20966
+               $context = $this->getContext( 'editredlink' );
+               $actionName = Action::getActionName( $context );
+
+               $this->assertEquals( 'edit', $actionName );
+       }
+
+       public function testGetActionName_historysubmitWorkaround() {
+               // See https://bugzilla.wikimedia.org/show_bug.cgi?id=20966
+               $context = $this->getContext( 'historysubmit' );
+               $actionName = Action::getActionName( $context );
+
+               $this->assertEquals( 'view', $actionName );
+       }
+
+       public function testGetActionName_revisiondeleteWorkaround() {
+               // See https://bugzilla.wikimedia.org/show_bug.cgi?id=20966
+               $context = $this->getContext( 'historysubmit' );
+               $context->getRequest()->setVal( 'revisiondelete', true );
+               $actionName = Action::getActionName( $context );
+
+               $this->assertEquals( 'revisiondelete', $actionName );
+       }
+
+       /**
+        * @dataProvider actionProvider
+        * @param string $requestedAction
+        * @param string|null $expected
+        */
+       public function testActionFactory( $requestedAction, $expected ) {
+               $context = $this->getContext();
+               $action = Action::factory( $requestedAction, $context->getWikiPage(), $context );
+
+               $this->assertType( $expected ?: 'null', $action );
+       }
+
+       public function testNull_doesNotExist() {
+               $exists = Action::exists( null );
+
+               $this->assertFalse( $exists );
+       }
+
+       public function testNull_defaultsToView() {
+               $context = $this->getContext( null );
+               $actionName = Action::getActionName( $context );
+
+               $this->assertEquals( 'view', $actionName );
+       }
+
+       public function testNull_canNotBeInstantiated() {
+               $page = $this->getPage();
+               $action = Action::factory( null, $page );
+
+               $this->assertNull( $action );
+       }
+
+       public function testDisabledAction_exists() {
+               $exists = Action::exists( 'disabled' );
+
+               $this->assertTrue( $exists );
+       }
+
+       public function testDisabledAction_isNotResolved() {
+               $context = $this->getContext( 'disabled' );
+               $actionName = Action::getActionName( $context );
+
+               $this->assertEquals( 'nosuchaction', $actionName );
+       }
+
+       public function testDisabledAction_factoryReturnsFalse() {
+               $page = $this->getPage();
+               $action = Action::factory( 'disabled', $page );
+
+               $this->assertFalse( $action );
+       }
+
+       public function dummyActionCallback() {
+               $context = $this->getContext();
+               return new CalledDummyAction( $context->getWikiPage(), $context );
+       }
+
+}
+
+class DummyAction extends Action {
+
+       public function getName() {
+               return get_called_class();
+       }
+
+       public function show() {
+       }
+
+       public function execute() {
+       }
+}
+
+class NamedDummyAction extends DummyAction {
+}
+
+class CalledDummyAction extends DummyAction {
+}
+
+class InstantiatedDummyAction extends DummyAction {
+}
index e031ce3..5f955bb 100644 (file)
@@ -17,7 +17,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
        /** @var DerivativeContext */
        private $mContext;
 
-       private $mOldGetPreferencesHooks = false;
+       private $mOldGetPreferencesHooks;
 
        private static $Success = array( 'options' => 'success' );
 
@@ -61,10 +61,8 @@ class ApiOptionsTest extends MediaWikiLangTestCase {
        protected function tearDown() {
                global $wgHooks;
 
-               if ( $this->mOldGetPreferencesHooks !== false ) {
-                       $wgHooks['GetPreferences'] = $this->mOldGetPreferencesHooks;
-                       $this->mOldGetPreferencesHooks = false;
-               }
+               $wgHooks['GetPreferences'] = $this->mOldGetPreferencesHooks;
+               $this->mOldGetPreferencesHooks = false;
 
                parent::tearDown();
        }
index ea0b323..7b686a3 100644 (file)
@@ -36,9 +36,12 @@ class ApiQueryTest extends ApiTestCase {
        }
 
        public function testTitlesGetNormalized() {
-
                global $wgMetaNamespace;
 
+               $this->setMwGlobals( array(
+                       'wgCapitalLinks' => true,
+               ) );
+
                $data = $this->doApiRequest( array(
                        'action' => 'query',
                        'titles' => 'Project:articleA|article_B' ) );
@@ -97,6 +100,10 @@ class ApiQueryTest extends ApiTestCase {
         * @dataProvider provideTestTitlePartToKey
         */
        function testTitlePartToKey( $titlePart, $namespace, $expected, $expectException ) {
+               $this->setMwGlobals( array(
+                       'wgCapitalLinks' => true,
+               ) );
+
                $api = new MockApiQueryBase();
                $exceptionCaught = false;
                try {
index 0a6bf72..611d304 100644 (file)
@@ -8,7 +8,7 @@ class ConfigFactoryTest extends MediaWikiTestCase {
        public function testRegister() {
                $factory = new ConfigFactory();
                $factory->register( 'unittest', 'GlobalVarConfig::newInstance' );
-               $this->assertTrue( True ); // No exception thrown
+               $this->assertTrue( true ); // No exception thrown
                $this->setExpectedException( 'InvalidArgumentException' );
                $factory->register( 'invalid', 'Invalid callback' );
        }
@@ -37,9 +37,9 @@ class ConfigFactoryTest extends MediaWikiTestCase {
         */
        public function testMakeConfigWithInvalidCallback() {
                $factory = new ConfigFactory();
-               $factory->register( 'unittest', function() {
+               $factory->register( 'unittest', function () {
                        return true; // Not a Config object
-               });
+               } );
                $this->setExpectedException( 'UnexpectedValueException' );
                $factory->makeConfig( 'unittest' );
        }
index 03cbbc0..2f81109 100644 (file)
@@ -31,6 +31,7 @@ class TextContentTest extends MediaWikiLangTestCase {
                        ),
                        'wgUseTidy' => false,
                        'wgAlwaysUseTidy' => false,
+                       'wgCapitalLinks' => true,
                ) );
 
                // bypass hooks that force custom rendering
index 88bf7d9..1db6fae 100644 (file)
@@ -440,12 +440,12 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
 
                $databaseCreation = $db->query( 'CREATE TABLE a ( a_1 )', __METHOD__ );
                $this->assertInstanceOf( 'ResultWrapper', $databaseCreation, "Failed to create table a" );
-               $res = $db->select( 'a' , '*');
-               $this->assertEquals( 0,  $db->numFields($res), "expects to get 0 fields for an empty table" );
+               $res = $db->select( 'a', '*' );
+               $this->assertEquals( 0, $db->numFields( $res ), "expects to get 0 fields for an empty table" );
                $insertion = $db->insert( 'a', array( 'a_1' => 10 ), __METHOD__ );
                $this->assertTrue( $insertion, "Insertion failed" );
-               $res = $db->select( 'a' , '*');
-               $this->assertEquals( 1,  $db->numFields($res), "wrong number of fields" );
+               $res = $db->select( 'a', '*' );
+               $this->assertEquals( 1, $db->numFields( $res ), "wrong number of fields" );
 
                $this->assertTrue( $db->close(), "closing database" );
        }
index e642177..17c6224 100644 (file)
@@ -107,7 +107,7 @@ class MWDebugTest extends MediaWikiTestCase {
                        'gitViewUrl', 'time', 'log', 'debugLog', 'queries', 'request', 'memory',
                        'memoryPeak', 'includes', 'profile', '_element' );
 
-               foreach( $expectedKeys as $expectedKey ) {
+               foreach ( $expectedKeys as $expectedKey ) {
                        $this->assertArrayHasKey( $expectedKey, $data['debuginfo'], "debuginfo has $expectedKey" );
                }
 
index e914c72..188ad3f 100644 (file)
@@ -44,7 +44,7 @@ class ArrayDiffFormatterTest extends MediaWikiTestCase {
                        $diffOp->expects( $this->any() )
                                ->method( 'getClosing' )
                                ->with( $this->isType( 'integer' ) )
-                               ->will( $this->returnCallback( function() {
+                               ->will( $this->returnCallback( function () {
                                        return 'mockLine';
                                } ) );
                } else {
diff --git a/tests/phpunit/includes/filerepo/RepoGroupTest.php b/tests/phpunit/includes/filerepo/RepoGroupTest.php
new file mode 100644 (file)
index 0000000..f9b4ad5
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+class RepoGroupTest extends MediaWikiTestCase {
+
+       function testHasForeignRepoNegative() {
+               $this->setMwGlobals( 'wgForeignFileRepos', array() );
+               RepoGroup::destroySingleton();
+               FileBackendGroup::destroySingleton();
+               $this->assertFalse( RepoGroup::singleton()->hasForeignRepos() );
+       }
+
+       function testHasForeignRepoPositive() {
+               $this->setUpForeignRepo();
+               $this->assertTrue( RepoGroup::singleton()->hasForeignRepos() );
+       }
+
+       function testForEachForeignRepo() {
+               $this->setUpForeignRepo();
+               $fakeCallback = $this->getMock( 'RepoGroupTestHelper' );
+               $fakeCallback->expects( $this->once() )->method( 'callback' );
+               RepoGroup::singleton()->forEachForeignRepo( array( $fakeCallback, 'callback' ), array( array() ) );
+       }
+
+       function testForEachForeignRepoNone() {
+               $this->setMwGlobals( 'wgForeignFileRepos', array() );
+               RepoGroup::destroySingleton();
+               FileBackendGroup::destroySingleton();
+               $fakeCallback = $this->getMock( 'RepoGroupTestHelper' );
+               $fakeCallback->expects( $this->never() )->method( 'callback' );
+               RepoGroup::singleton()->forEachForeignRepo( array( $fakeCallback, 'callback' ), array( array() ) );
+       }
+
+       private function setUpForeignRepo() {
+               global $wgUploadDirectory;
+               $this->setMwGlobals( 'wgForeignFileRepos', array( array(
+                       'class' => 'ForeignAPIRepo',
+                       'name' => 'wikimediacommons',
+                       'backend' => 'wikimediacommons-backend',
+                       'apibase' => 'https://commons.wikimedia.org/w/api.php',
+                       'hashLevels' => 2,
+                       'fetchDescription' => true,
+                       'descriptionCacheExpiry' => 43200,
+                       'apiThumbCacheExpiry' => 86400,
+                       'directory' => $wgUploadDirectory
+               ) ) );
+               RepoGroup::destroySingleton();
+               FileBackendGroup::destroySingleton();
+       }
+}
+
+/**
+ * Quick helper class to use as a mock callback for RepoGroup::singleton()->forEachForeignRepo.
+ */
+class RepoGroupTestHelper {
+       function callback( FileRepo $repo, array $foo ) {
+               return true;
+       }
+}
diff --git a/tests/phpunit/includes/filerepo/file/FileTest.php b/tests/phpunit/includes/filerepo/file/FileTest.php
new file mode 100644 (file)
index 0000000..ffa9876
--- /dev/null
@@ -0,0 +1,386 @@
+<?php
+
+class FileTest extends MediaWikiMediaTestCase {
+
+       /**
+        * @param $filename String
+        * @param $expected boolean
+        * @dataProvider providerCanAnimate
+        */
+       function testCanAnimateThumbIfAppropriate( $filename, $expected ) {
+               $this->setMwGlobals( 'wgMaxAnimatedGifArea', 9000 );
+               $file = $this->dataFile( $filename );
+               $this->assertEquals( $file->canAnimateThumbIfAppropriate(), $expected );
+       }
+
+       function providerCanAnimate() {
+               return array(
+                       array( 'nonanimated.gif', true ),
+                       array( 'jpeg-comment-utf.jpg', true ),
+                       array( 'test.tiff', true ),
+                       array( 'Animated_PNG_example_bouncing_beach_ball.png', false ),
+                       array( 'greyscale-png.png', true ),
+                       array( 'Toll_Texas_1.svg', true ),
+                       array( 'LoremIpsum.djvu', true ),
+                       array( '80x60-2layers.xcf', true ),
+                       array( 'Soccer_ball_animated.svg', false ),
+                       array( 'Bishzilla_blink.gif', false ),
+                       array( 'animated.gif', true ),
+               );
+       }
+
+       /**
+        * @dataProvider getThumbnailBucketProvider
+        * @covers File::getThumbnailBucket
+        */
+       public function testGetThumbnailBucket( $data ) {
+               $this->setMwGlobals( 'wgThumbnailBuckets', $data['buckets'] );
+               $this->setMwGlobals( 'wgThumbnailMinimumBucketDistance', $data['minimumBucketDistance'] );
+
+               $fileMock = $this->getMockBuilder( 'File' )
+                       ->setConstructorArgs( array( 'fileMock', false ) )
+                       ->setMethods( array( 'getWidth' ) )
+                       ->getMockForAbstractClass();
+
+               $fileMock->expects( $this->any() )
+                       ->method( 'getWidth' )
+                       ->will( $this->returnValue( $data['width'] ) );
+
+               $this->assertEquals(
+                       $data['expectedBucket'],
+                       $fileMock->getThumbnailBucket( $data['requestedWidth'] ),
+                       $data['message'] );
+       }
+
+       public function getThumbnailBucketProvider() {
+               $defaultBuckets = array( 256, 512, 1024, 2048, 4096 );
+
+               return array(
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'minimumBucketDistance' => 0,
+                               'width' => 3000,
+                               'requestedWidth' => 120,
+                               'expectedBucket' => 256,
+                               'message' => 'Picking bucket bigger than requested size'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'minimumBucketDistance' => 0,
+                               'width' => 3000,
+                               'requestedWidth' => 300,
+                               'expectedBucket' => 512,
+                               'message' => 'Picking bucket bigger than requested size'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'minimumBucketDistance' => 0,
+                               'width' => 3000,
+                               'requestedWidth' => 1024,
+                               'expectedBucket' => 2048,
+                               'message' => 'Picking bucket bigger than requested size'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'minimumBucketDistance' => 0,
+                               'width' => 3000,
+                               'requestedWidth' => 2048,
+                               'expectedBucket' => false,
+                               'message' => 'Picking no bucket because none is bigger than the requested size'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'minimumBucketDistance' => 0,
+                               'width' => 3000,
+                               'requestedWidth' => 3500,
+                               'expectedBucket' => false,
+                               'message' => 'Picking no bucket because requested size is bigger than original'
+                       ) ),
+                       array( array(
+                               'buckets' => array( 1024 ),
+                               'minimumBucketDistance' => 0,
+                               'width' => 3000,
+                               'requestedWidth' => 1024,
+                               'expectedBucket' => false,
+                               'message' => 'Picking no bucket because requested size equals biggest bucket'
+                       ) ),
+                       array( array(
+                               'buckets' => null,
+                               'minimumBucketDistance' => 0,
+                               'width' => 3000,
+                               'requestedWidth' => 1024,
+                               'expectedBucket' => false,
+                               'message' => 'Picking no bucket because no buckets have been specified'
+                       ) ),
+                       array( array(
+                               'buckets' => array( 256, 512 ),
+                               'minimumBucketDistance' => 10,
+                               'width' => 3000,
+                               'requestedWidth' => 245,
+                               'expectedBucket' => 256,
+                               'message' => 'Requested width is distant enough from next bucket for it to be picked'
+                       ) ),
+                       array( array(
+                               'buckets' => array( 256, 512 ),
+                               'minimumBucketDistance' => 10,
+                               'width' => 3000,
+                               'requestedWidth' => 246,
+                               'expectedBucket' => 512,
+                               'message' => 'Requested width is too close to next bucket, picking next one'
+                       ) ),
+               );
+       }
+
+       /**
+        * @dataProvider getThumbnailSourceProvider
+        * @covers File::getThumbnailSource
+        */
+       public function testGetThumbnailSource( $data ) {
+               $backendMock = $this->getMockBuilder( 'FSFileBackend' )
+                       ->setConstructorArgs( array( array( 'name' => 'backendMock', 'wikiId' => wfWikiId() ) ) )
+                       ->getMock();
+
+               $repoMock = $this->getMockBuilder( 'FileRepo' )
+                       ->setConstructorArgs( array( array( 'name' => 'repoMock', 'backend' => $backendMock ) ) )
+                       ->setMethods( array( 'fileExists', 'getLocalReference' ) )
+                       ->getMock();
+
+               $fsFile = new FSFile( 'fsFilePath' );
+
+               $repoMock->expects( $this->any() )
+                       ->method( 'fileExists' )
+                       ->will( $this->returnValue( true ) );
+
+               $repoMock->expects( $this->any() )
+                       ->method( 'getLocalReference' )
+                       ->will( $this->returnValue( $fsFile ) );
+
+               $handlerMock = $this->getMock( 'BitmapHandler', array( 'supportsBucketing' ) );
+               $handlerMock->expects( $this->any() )
+                       ->method( 'supportsBucketing' )
+                       ->will( $this->returnValue( $data['supportsBucketing'] ) );
+
+               $fileMock = $this->getMockBuilder( 'File' )
+                       ->setConstructorArgs( array( 'fileMock', $repoMock ) )
+                       ->setMethods( array( 'getThumbnailBucket', 'getLocalRefPath', 'getHandler' ) )
+                       ->getMockForAbstractClass();
+
+               $fileMock->expects( $this->any() )
+                       ->method( 'getThumbnailBucket' )
+                       ->will( $this->returnValue( $data['thumbnailBucket'] ) );
+
+               $fileMock->expects( $this->any() )
+                       ->method( 'getLocalRefPath' )
+                       ->will( $this->returnValue( 'localRefPath' ) );
+
+               $fileMock->expects( $this->any() )
+                       ->method( 'getHandler' )
+                       ->will( $this->returnValue( $handlerMock ) );
+
+               $reflection = new ReflectionClass( $fileMock );
+               $reflection_property = $reflection->getProperty( 'handler' );
+               $reflection_property->setAccessible( true );
+               $reflection_property->setValue( $fileMock, $handlerMock );
+
+               if ( !is_null( $data['tmpBucketedThumbCache'] ) ) {
+                       $reflection_property = $reflection->getProperty( 'tmpBucketedThumbCache' );
+                       $reflection_property->setAccessible( true );
+                       $reflection_property->setValue( $fileMock, $data['tmpBucketedThumbCache'] );
+               }
+
+               $result = $fileMock->getThumbnailSource(
+                       array( 'physicalWidth' => $data['physicalWidth'] ) );
+
+               $this->assertEquals( $data['expectedPath'], $result['path'], $data['message'] );
+       }
+
+       public function getThumbnailSourceProvider() {
+               return array(
+                       array( array(
+                               'supportsBucketing' => true,
+                               'tmpBucketedThumbCache' => null,
+                               'thumbnailBucket' => 1024,
+                               'physicalWidth' => 2048,
+                               'expectedPath' => 'fsFilePath',
+                               'message' => 'Path downloaded from storage'
+                       ) ),
+                       array( array(
+                               'supportsBucketing' => true,
+                               'tmpBucketedThumbCache' => array( 1024 => '/tmp/shouldnotexist' + rand() ),
+                               'thumbnailBucket' => 1024,
+                               'physicalWidth' => 2048,
+                               'expectedPath' => 'fsFilePath',
+                               'message' => 'Path downloaded from storage because temp file is missing'
+                       ) ),
+                       array( array(
+                               'supportsBucketing' => true,
+                               'tmpBucketedThumbCache' => array( 1024 => '/tmp' ),
+                               'thumbnailBucket' => 1024,
+                               'physicalWidth' => 2048,
+                               'expectedPath' => '/tmp',
+                               'message' => 'Temporary path because temp file was found'
+                       ) ),
+                       array( array(
+                               'supportsBucketing' => false,
+                               'tmpBucketedThumbCache' => null,
+                               'thumbnailBucket' => 1024,
+                               'physicalWidth' => 2048,
+                               'expectedPath' => 'localRefPath',
+                               'message' => 'Original file path because bucketing is unsupported by handler'
+                       ) ),
+                       array( array(
+                               'supportsBucketing' => true,
+                               'tmpBucketedThumbCache' => null,
+                               'thumbnailBucket' => false,
+                               'physicalWidth' => 2048,
+                               'expectedPath' => 'localRefPath',
+                               'message' => 'Original file path because no width provided'
+                       ) ),
+               );
+       }
+
+       /**
+        * @dataProvider generateBucketsIfNeededProvider
+        * @covers File::generateBucketsIfNeeded
+        */
+       public function testGenerateBucketsIfNeeded( $data ) {
+               $this->setMwGlobals( 'wgThumbnailBuckets', $data['buckets'] );
+
+               $backendMock = $this->getMockBuilder( 'FSFileBackend' )
+                       ->setConstructorArgs( array( array( 'name' => 'backendMock', 'wikiId' => wfWikiId() ) ) )
+                       ->getMock();
+
+               $repoMock = $this->getMockBuilder( 'FileRepo' )
+                       ->setConstructorArgs( array( array( 'name' => 'repoMock', 'backend' => $backendMock ) ) )
+                       ->setMethods( array( 'fileExists', 'getLocalReference' ) )
+                       ->getMock();
+
+               $fileMock = $this->getMockBuilder( 'File' )
+                       ->setConstructorArgs( array( 'fileMock', $repoMock ) )
+                       ->setMethods( array( 'getWidth', 'getBucketThumbPath', 'makeTransformTmpFile',
+                               'generateAndSaveThumb', 'getHandler' ) )
+                       ->getMockForAbstractClass();
+
+               $handlerMock = $this->getMock( 'JpegHandler', array( 'supportsBucketing' ) );
+               $handlerMock->expects( $this->any() )
+                       ->method( 'supportsBucketing' )
+                       ->will( $this->returnValue( true ) );
+
+               $fileMock->expects( $this->any() )
+                       ->method( 'getHandler' )
+                       ->will( $this->returnValue( $handlerMock ) );
+
+               $reflectionMethod = new ReflectionMethod( 'File', 'generateBucketsIfNeeded' );
+               $reflectionMethod->setAccessible( true );
+
+               $fileMock->expects( $this->any() )
+                       ->method( 'getWidth' )
+                       ->will( $this->returnValue( $data['width'] ) );
+
+               $fileMock->expects( $data['expectedGetBucketThumbPathCalls'] )
+                       ->method( 'getBucketThumbPath' );
+
+               $repoMock->expects( $data['expectedFileExistsCalls'] )
+                       ->method( 'fileExists' )
+                       ->will( $this->returnValue( $data['fileExistsReturn'] ) );
+
+               $fileMock->expects( $data['expectedMakeTransformTmpFile'] )
+                       ->method( 'makeTransformTmpFile' )
+                       ->will( $this->returnValue( $data['makeTransformTmpFileReturn'] ) );
+
+               $fileMock->expects( $data['expectedGenerateAndSaveThumb'] )
+                       ->method( 'generateAndSaveThumb' )
+                       ->will( $this->returnValue( $data['generateAndSaveThumbReturn'] ) );
+
+               $this->assertEquals( $data['expectedResult'],
+                       $reflectionMethod->invoke(
+                               $fileMock,
+                               array(
+                                       'physicalWidth' => $data['physicalWidth'],
+                                       'physicalHeight' => $data['physicalHeight'] )
+                               ),
+                               $data['message'] );
+       }
+
+       public function generateBucketsIfNeededProvider() {
+               $defaultBuckets = array( 256, 512, 1024, 2048, 4096 );
+
+               return array(
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'width' => 256,
+                               'physicalWidth' => 256,
+                               'physicalHeight' => 100,
+                               'expectedGetBucketThumbPathCalls' => $this->never(),
+                               'expectedFileExistsCalls' => $this->never(),
+                               'fileExistsReturn' => null,
+                               'expectedMakeTransformTmpFile' => $this->never(),
+                               'makeTransformTmpFileReturn' => false,
+                               'expectedGenerateAndSaveThumb' => $this->never(),
+                               'generateAndSaveThumbReturn' => false,
+                               'expectedResult' => false,
+                               'message' => 'No bucket found, nothing to generate'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'width' => 5000,
+                               'physicalWidth' => 300,
+                               'physicalHeight' => 200,
+                               'expectedGetBucketThumbPathCalls' => $this->once(),
+                               'expectedFileExistsCalls' => $this->once(),
+                               'fileExistsReturn' => true,
+                               'expectedMakeTransformTmpFile' => $this->never(),
+                               'makeTransformTmpFileReturn' => false,
+                               'expectedGenerateAndSaveThumb' => $this->never(),
+                               'generateAndSaveThumbReturn' => false,
+                               'expectedResult' => false,
+                               'message' => 'File already exists, no reason to generate buckets'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'width' => 5000,
+                               'physicalWidth' => 300,
+                               'physicalHeight' => 200,
+                               'expectedGetBucketThumbPathCalls' => $this->once(),
+                               'expectedFileExistsCalls' => $this->once(),
+                               'fileExistsReturn' => false,
+                               'expectedMakeTransformTmpFile' => $this->once(),
+                               'makeTransformTmpFileReturn' => false,
+                               'expectedGenerateAndSaveThumb' => $this->never(),
+                               'generateAndSaveThumbReturn' => false,
+                               'expectedResult' => false,
+                               'message' => 'Cannot generate temp file for bucket'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'width' => 5000,
+                               'physicalWidth' => 300,
+                               'physicalHeight' => 200,
+                               'expectedGetBucketThumbPathCalls' => $this->once(),
+                               'expectedFileExistsCalls' => $this->once(),
+                               'fileExistsReturn' => false,
+                               'expectedMakeTransformTmpFile' => $this->once(),
+                               'makeTransformTmpFileReturn' => new TempFSFile( '/tmp/foo' ),
+                               'expectedGenerateAndSaveThumb' => $this->once(),
+                               'generateAndSaveThumbReturn' => false,
+                               'expectedResult' => false,
+                               'message' => 'Bucket image could not be generated'
+                       ) ),
+                       array( array(
+                               'buckets' => $defaultBuckets,
+                               'width' => 5000,
+                               'physicalWidth' => 300,
+                               'physicalHeight' => 200,
+                               'expectedGetBucketThumbPathCalls' => $this->once(),
+                               'expectedFileExistsCalls' => $this->once(),
+                               'fileExistsReturn' => false,
+                               'expectedMakeTransformTmpFile' => $this->once(),
+                               'makeTransformTmpFileReturn' => new TempFSFile( '/tmp/foo' ),
+                               'expectedGenerateAndSaveThumb' => $this->once(),
+                               'generateAndSaveThumbReturn' => new ThumbnailImage( false, 'bar', false, false ),
+                               'expectedResult' => true,
+                               'message' => 'Bucket image could not be generated'
+                       ) ),
+               );
+       }
+}
diff --git a/tests/phpunit/includes/filerepo/files/FileTest.php b/tests/phpunit/includes/filerepo/files/FileTest.php
deleted file mode 100644 (file)
index 36b95ea..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-class FileTest extends MediaWikiMediaTestCase {
-
-       function setUp() {
-               $this->setMWGlobals( 'wgMaxAnimatedGifArea', 9000 );
-               parent::setUp();
-       }
-
-       /**
-        * @param $filename String
-        * @param $expected boolean
-        * @dataProvider providerCanAnimate
-        */
-       function testCanAnimateThumbIfAppropriate( $filename, $expected ) {
-               $file = $this->dataFile( $filename );
-               $this->assertEquals( $file->canAnimateThumbIfAppropriate(), $expected );
-       }
-
-       function providerCanAnimate() {
-               return array(
-                       array( 'nonanimated.gif', true ),
-                       array( 'jpeg-comment-utf.jpg', true ),
-                       array( 'test.tiff', true ),
-                       array( 'Animated_PNG_example_bouncing_beach_ball.png', false ),
-                       array( 'greyscale-png.png', true ),
-                       array( 'Toll_Texas_1.svg', true ),
-                       array( 'LoremIpsum.djvu', true ),
-                       array( '80x60-2layers.xcf', true ),
-                       array( 'Soccer_ball_animated.svg', false ),
-                       array( 'Bishzilla_blink.gif', false ),
-                       array( 'animated.gif', true ),
-               );
-       }
-}
index b99ef86..334d5b5 100644 (file)
@@ -14,7 +14,7 @@ class MWMessagePackTest extends MediaWikiTestCase {
         * serialization function.
         */
        public function provider() {
-               return array(
+               $tests = array(
                        array( 'nil', null, 'c0' ),
                        array( 'bool', true, 'c3' ),
                        array( 'bool', false, 'c2' ),
@@ -25,16 +25,12 @@ class MWMessagePackTest extends MediaWikiTestCase {
                        array( 'uint 8', 128, 'cc80' ),
                        array( 'uint 16', 1000, 'cd03e8' ),
                        array( 'uint 32', 100000, 'ce000186a0' ),
-                       array( 'uint 64', 10000000000, 'cf00000002540be400' ),
                        array( 'negative fixnum', -1, 'ff' ),
                        array( 'negative fixnum', -2, 'fe' ),
                        array( 'int 8', -128, 'd080' ),
                        array( 'int 8', -35, 'd0dd' ),
                        array( 'int 16', -1000, 'd1fc18' ),
                        array( 'int 32', -100000, 'd2fffe7960' ),
-                       array( 'int 64', -10000000000, 'd3fffffffdabf41c00' ),
-                       array( 'int 64', -223372036854775807, 'd3fce66c50e2840001' ),
-                       array( 'int 64', -9223372036854775807, 'd38000000000000001' ),
                        array( 'double', 0.1, 'cb3fb999999999999a' ),
                        array( 'double', 1.1, 'cb3ff199999999999a' ),
                        array( 'double', 123.456, 'cb405edd2f1a9fbe77' ),
@@ -56,6 +52,15 @@ class MWMessagePackTest extends MediaWikiTestCase {
                                '82a36f6e6501a374776f02'
                        ),
                );
+
+               if ( PHP_INT_SIZE > 4 ) {
+                       $tests[] = array( 'uint 64', 10000000000, 'cf00000002540be400' );
+                       $tests[] = array( 'int 64', -10000000000, 'd3fffffffdabf41c00' );
+                       $tests[] = array( 'int 64', -223372036854775807, 'd3fce66c50e2840001' );
+                       $tests[] = array( 'int 64', -9223372036854775807, 'd38000000000000001' );
+               }
+
+               return $tests;
        }
 
        /**
@@ -65,6 +70,6 @@ class MWMessagePackTest extends MediaWikiTestCase {
         */
        public function testPack( $type, $value, $expected ) {
                $actual = bin2hex( MWMessagePack::pack( $value ) );
-               $this->assertEquals( $actual, $expected, $type );
+               $this->assertEquals( $expected, $actual, $type );
        }
 }
index 8402522..c720d7b 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @group Media
+ */
 class BitmapMetadataHandlerTest extends MediaWikiTestCase {
 
        protected function setUp() {
index 9395b66..1972c96 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group Media
+ */
 class BitmapScalingTest extends MediaWikiTestCase {
 
        protected function setUp() {
index 76cefe5..d779207 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 /**
+ * @group Media
  * @covers DjVuHandler
  */
 class DjVuTest extends MediaWikiMediaTestCase {
@@ -34,8 +35,8 @@ class DjVuTest extends MediaWikiMediaTestCase {
        public function testInvalidFile() {
                $this->assertEquals(
                        'a:1:{s:5:"error";s:25:"Error extracting metadata";}',
-                       $this->handler->getMetadata( null, $this->filePath . '/README' ),
-                       'Getting Metadata for an inexistent file should returns false'
+                       $this->handler->getMetadata( null, $this->filePath . '/some-nonexistent-file' ),
+                       'Getting metadata for an inexistent file should return false'
                );
        }
 
index 44b2070..41330f4 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group Media
+ */
 class ExifBitmapTest extends MediaWikiTestCase {
 
        /**
index 6a1e422..247e352 100644 (file)
@@ -2,6 +2,7 @@
 /**
  * Tests related to auto rotation.
  *
+ * @group Media
  * @group medium
  *
  * @todo covers tags
index 735663c..f3c05fb 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @group Media
  * @covers Exif
  */
 class ExifTest extends MediaWikiTestCase {
index 7bc785e..4b8f213 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group Media
+ */
 class FakeDimensionFile extends File {
        public $mustRender = false;
 
index daaefc0..002e2cb 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group Media
+ */
 class FormatMetadataTest extends MediaWikiMediaTestCase {
 
        protected function setUp() {
index 3491112..6aecd8b 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @group Media
+ */
 class GIFMetadataExtractorTest extends MediaWikiTestCase {
 
        protected function setUp() {
index 17b2964..52a51cc 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @group Media
+ */
 class GIFHandlerTest extends MediaWikiMediaTestCase {
 
        /** @var GIFHandler */
index b556a75..06542cf 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group Media
+ */
 class IPTCTest extends MediaWikiTestCase {
 
        /**
index b10f55c..80e03cc 100644 (file)
@@ -6,6 +6,7 @@
  * but it costs money). The implementation of it currently in MediaWiki is based
  * solely on reading the standard, without any real world test files.
  *
+ * @group Media
  * @covers JpegMetadataExtractor
  */
 class JpegMetadataExtractorTest extends MediaWikiTestCase {
index c856b1c..2436e7d 100644 (file)
@@ -1,5 +1,7 @@
 <?php
+
 /**
+ * @group Media
  * @covers JpegHandler
  */
 class JpegTest extends MediaWikiMediaTestCase {
index c28898b..d8cfcc4 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group Media
+ */
 class MediaHandlerTest extends MediaWikiTestCase {
 
        /**
index 96347d9..1b8ecf2 100644 (file)
@@ -29,11 +29,18 @@ abstract class MediaWikiMediaTestCase extends MediaWikiTestCase {
                        'wikiId' => wfWikiId(),
                        'containerPaths' => $containers
                ) );
-               $this->repo = new FSRepo( array(
+               $this->repo = new FSRepo( $this->getRepoOptions() );
+       }
+
+       /**
+        * @return Array Argument for FSRepo constructor
+        */
+       protected function getRepoOptions() {
+               return array(
                        'name' => 'temp',
                        'url' => 'http://localhost/thumbtest',
                        'backend' => $this->backend
-               ) );
+               );
        }
 
        /**
@@ -71,7 +78,7 @@ abstract class MediaWikiMediaTestCase extends MediaWikiTestCase {
                        // Autodetect by file extension for the lazy.
                        $magic = MimeMagic::singleton();
                        $parts = explode( $name, '.' );
-                       $type = $magic->guessTypesForExtension( $parts[count( $parts ) - 1]  );
+                       $type = $magic->guessTypesForExtension( $parts[count( $parts ) - 1] );
                }
                return new UnregisteredLocalFile( false, $this->repo,
                        "mwstore://localtesting/data/$name", $type );
index 84deb1b..a9eaa9e 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @group Media
  * @covers PNGMetadataExtractor
  */
 class PNGMetadataExtractorTest extends MediaWikiTestCase {
index 14e4d57..9a4826c 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @group Media
+ */
 class PNGHandlerTest extends MediaWikiMediaTestCase {
 
        /** @var PNGHandler */
index f06bd6f..ab33d1c 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @group Media
  * @covers SVGMetadataExtractor
  */
 class SVGMetadataExtractorTest extends MediaWikiTestCase {
index e3bb05e..1361a92 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @group Media
+ */
 class SvgTest extends MediaWikiMediaTestCase {
 
        protected function setUp() {
index 26d7204..d114820 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @group Media
+ */
 class TiffTest extends MediaWikiTestCase {
 
        /** @var TiffHandler */
diff --git a/tests/phpunit/includes/media/XCFTest.php b/tests/phpunit/includes/media/XCFTest.php
new file mode 100644 (file)
index 0000000..7fc3275
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @group Media
+ */
+class XCFHandlerTest extends MediaWikiMediaTestCase {
+
+       /** @var XCFHandler */
+       protected $handler;
+
+       protected function setUp() {
+               parent::setUp();
+               $this->handler = new XCFHandler();
+       }
+
+
+       /**
+        * @param string $filename
+        * @param int $expectedWidth width
+        * @param int $expectedHeigh height
+        * @dataProvider provideGetImageSize
+        * @covers XCFHandler::getImageSize
+        */
+       public function testGetImageSize( $filename, $expectedWidth, $expectedHeight ) {
+               $file = $this->dataFile( $filename, 'image/x-xcf' );
+               $actual = $this->handler->getImageSize( $file, $file->getLocalRefPath() );
+               $this->assertEquals( $expectedWidth, $actual[0] );
+               $this->assertEquals( $expectedHeight, $actual[1] );
+       }
+
+       public static function provideGetImageSize() {
+               return array(
+                       array( '80x60-2layers.xcf', 80, 60 ),
+                       array( '80x60-RGB.xcf', 80, 60 ),
+                       array( '80x60-Greyscale.xcf', 80, 60 ),
+               );
+       }
+
+       /**
+        * @param string $metadata Serialized metadata
+        * @param int $expected One of the class constants of XCFHandler
+        * @dataProvider provideIsMetadataValid
+        * @covers XCFHandler::isMetadataValid
+        */
+       public function testIsMetadataValid( $metadata, $expected ) {
+               $actual = $this->handler->isMetadataValid( null, $metadata );
+               $this->assertEquals( $expected, $actual );
+       }
+
+       public static function provideIsMetadataValid() {
+               return array(
+                       array( '', XCFHandler::METADATA_BAD ),
+                       array( serialize( array( 'error' => true ) ), XCFHandler::METADATA_GOOD ),
+                       array( false, XCFHandler::METADATA_BAD ),
+                       array( serialize( array( 'colorType' => 'greyscale-alpha' ) ), XCFHandler::METADATA_GOOD ),
+               );
+       }
+
+       /**
+        * @param string $filename
+        * @param string $expected Serialized array
+        * @dataProvider provideGetMetadata
+        * @covers XCFHandler::getMetadata
+        */
+       public function testGetMetadata( $filename, $expected ) {
+               $file = $this->dataFile( $filename, 'image/png' );
+               $actual = $this->handler->getMetadata( $file, "$this->filePath/$filename" );
+               $this->assertEquals( $expected, $actual );
+       }
+
+       public static function provideGetMetadata() {
+               return array(
+                       array( '80x60-2layers.xcf', 'a:1:{s:9:"colorType";s:16:"truecolour-alpha";}' ),
+                       array( '80x60-RGB.xcf', 'a:1:{s:9:"colorType";s:16:"truecolour-alpha";}' ),
+                       array( '80x60-Greyscale.xcf', 'a:1:{s:9:"colorType";s:15:"greyscale-alpha";}' ),
+               );
+       }
+}
index 25ae1e6..798e492 100644 (file)
@@ -1,7 +1,8 @@
 <?php
 
 /**
- * @todo covers tags
+ * @group Media
+ * @covers XMPReader
  */
 class XMPTest extends MediaWikiTestCase {
 
index 96bf5e4..ebec8f6 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @group Media
+ */
 class XMPValidateTest extends MediaWikiTestCase {
 
        /**
index dff31c1..97b76fe 100644 (file)
@@ -110,15 +110,20 @@ class CleanUpTest extends MediaWikiTestCase {
        }
 
        /** @todo document */
-       public function testAllBytes() {
-               $this->doTestBytes( '', '' );
-               $this->doTestBytes( 'x', '' );
-               $this->doTestBytes( '', 'x' );
-               $this->doTestBytes( 'x', 'x' );
+       public function provideAllBytes() {
+               return array(
+                       array( '', '' ),
+                       array( 'x', '' ),
+                       array( '', 'x' ),
+                       array( 'x', 'x' ),
+               );
        }
 
-       /** @todo document */
-       function doTestBytes( $head, $tail ) {
+       /**
+        * @dataProvider provideAllBytes
+        * @todo document
+        */
+       function testBytes( $head, $tail ) {
                for ( $i = 0x0; $i < 256; $i++ ) {
                        $char = $head . chr( $i ) . $tail;
                        $clean = UtfNormal::cleanUp( $char );
@@ -149,18 +154,11 @@ class CleanUpTest extends MediaWikiTestCase {
                }
        }
 
-       /** @todo document */
-       public function testDoubleBytes() {
-               $this->doTestDoubleBytes( '', '' );
-               $this->doTestDoubleBytes( 'x', '' );
-               $this->doTestDoubleBytes( '', 'x' );
-               $this->doTestDoubleBytes( 'x', 'x' );
-       }
-
        /**
+        * @dataProvider provideAllBytes
         * @todo document
         */
-       function doTestDoubleBytes( $head, $tail ) {
+       function testDoubleBytes( $head, $tail ) {
                for ( $first = 0xc0; $first < 0x100; $first += 2 ) {
                        for ( $second = 0x80; $second < 0x100; $second += 2 ) {
                                $char = $head . chr( $first ) . chr( $second ) . $tail;
@@ -202,16 +200,11 @@ class CleanUpTest extends MediaWikiTestCase {
                }
        }
 
-       /** @todo document */
-       public function testTripleBytes() {
-               $this->doTestTripleBytes( '', '' );
-               $this->doTestTripleBytes( 'x', '' );
-               $this->doTestTripleBytes( '', 'x' );
-               $this->doTestTripleBytes( 'x', 'x' );
-       }
-
-       /** @todo document */
-       function doTestTripleBytes( $head, $tail ) {
+       /**
+        * @dataProvider provideAllBytes
+        * @todo document
+        */
+       function testTripleBytes( $head, $tail ) {
                for ( $first = 0xc0; $first < 0x100; $first += 2 ) {
                        for ( $second = 0x80; $second < 0x100; $second += 2 ) {
                                #for( $third = 0x80; $third < 0x100; $third++ ) {
index 4c72d1c..253c10b 100644 (file)
@@ -148,6 +148,7 @@ class NewParserTest extends MediaWikiTestCase {
                # proper precedence when resolving links. (bug 51680)
                $tmpGlobals['wgExtraNamespaces'] = array( 100 => 'MemoryAlpha' );
 
+               $tmpGlobals['wgLocalInterwikis'] = array( 'local', 'mi' );
                # "extra language links"
                # see https://gerrit.wikimedia.org/r/111390
                $tmpGlobals['wgExtraInterlanguageLinkPrefixes'] = array( 'mul' );
index 29af2c2..cbf4803 100644 (file)
@@ -78,7 +78,7 @@ class ParserMethodsTest extends MediaWikiLangTestCase {
                $wgParser->parse( '<recursivecallparser>baz</recursivecallparser>', $title, $po );
        }
 
-       public function helperParserFunc( $input, $args, $parser) {
+       public function helperParserFunc( $input, $args, $parser ) {
                $title = Title::newFromText( 'foo' );
                $po = new ParserOptions;
                $parser->parse( $input, $title, $po );
index 2d31d08..d9cd57e 100644 (file)
@@ -50,10 +50,9 @@ class PoolCounterTest extends MediaWikiTestCase {
                        ->disableOriginalConstructor()
                        ->getMockForAbstractClass();
 
-               $hashKeyIntoSlots = new ReflectionMethod($poolCounter, 'hashKeyIntoSlots' );
+               $hashKeyIntoSlots = new ReflectionMethod( $poolCounter, 'hashKeyIntoSlots' );
                $hashKeyIntoSlots->setAccessible( true );
 
-
                $keysWithTwoSlots = $keysWithFiveSlots = array();
                foreach ( range( 1, 100 ) as $i ) {
                        $keysWithTwoSlots[] = $hashKeyIntoSlots->invoke( $poolCounter, 'key ' . $i, 2 );
index d3736f5..bd6b3f2 100644 (file)
@@ -130,6 +130,39 @@ class ResourceLoaderTest extends ResourceLoaderTestCase {
                        ),
                );
        }
+
+       public static function fakeSources() {
+               return array(
+                       'examplewiki' => array(
+                               'loadScript' => '//example.org/w/load.php',
+                               'apiScript' => '//example.org/w/api.php',
+                       ),
+                       'example2wiki' => array(
+                               'loadScript' => '//example.com/w/load.php',
+                               'apiScript' => '//example.com/w/api.php',
+                       ),
+               );
+       }
+
+       /**
+        * @covers ResourceLoader::getLoadScript
+        */
+       public function testGetLoadScript() {
+               $this->setMwGlobals( 'wgResourceLoaderSources', array() );
+               $rl = new ResourceLoader();
+               $sources = self::fakeSources();
+               $rl->addSource( $sources );
+               foreach ( array( 'examplewiki', 'example2wiki' ) as $name ) {
+                       $this->assertEquals( $rl->getLoadScript( $name ), $sources[$name]['loadScript'] );
+               }
+
+               try {
+                       $rl->getLoadScript( 'thiswasneverreigstered' );
+                       $this->assertTrue( false, 'ResourceLoader::getLoadScript should have thrown an exception' );
+               } catch ( MWException $e ) {
+                       $this->assertTrue( true );
+               }
+       }
 }
 
 /* Hooks */
index 15b8865..c3fd155 100644 (file)
 class MediaWikiSiteTest extends SiteTest {
 
        public function testNormalizePageTitle() {
+               $this->setMwGlobals( array(
+                       'wgCapitalLinks' => true,
+               ) );
+
                $site = new MediaWikiSite();
                $site->setGlobalId( 'enwiki' );
 
index dbebeb7..1f1d750 100644 (file)
@@ -114,6 +114,9 @@ class SpecialSearchTest extends MediaWikiTestCase {
         * https://gerrit.wikimedia.org/r/4841
         */
        public function testSearchTermIsNotExpanded() {
+               $this->setMwGlobals( array(
+                       'wgSearchType' => null,
+               ) );
 
                # Initialize [[Special::Search]]
                $search = new SpecialSearch();
index 73d7ff9..f1425ef 100644 (file)
  */
 class MediaWikiPageLinkRendererTest extends MediaWikiTestCase {
 
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( array(
+                       'wgContLang' => Language::factory( 'en' ),
+               ) );
+       }
+
        /**
         * Returns a mock GenderCache that will return "female" always.
         *
@@ -147,7 +155,7 @@ class MediaWikiPageLinkRendererTest extends MediaWikiTestCase {
                $formatter->expects( $this->any() )
                        ->method( 'getFullText' )
                        ->will( $this->returnCallback(
-                               function( TitleValue $title ) {
+                               function ( TitleValue $title ) {
                                        return str_replace( '_', ' ', "$title" );
                                }
                        ));
index 1e5aca9..bf06e3b 100644 (file)
@@ -40,6 +40,7 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
                        'wgAllowUserJs' => false,
                        'wgDefaultLanguageVariant' => false,
                        'wgLocalInterwikis' => array( 'localtestiw' ),
+                       'wgCapitalLinks' => true,
 
                        // NOTE: this is why global state is evil.
                        // TODO: refactor access to the interwiki codes so it can be injected.
@@ -71,7 +72,7 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase {
 
                $genderCache->expects( $this->any() )
                        ->method( 'getGenderOf' )
-                       ->will( $this->returnCallback( function( $userName ) {
+                       ->will( $this->returnCallback( function ( $userName ) {
                                return preg_match( '/^[^- _]+a( |_|$)/u', $userName ) ? 'female' : 'male';
                        } ) );
 
index 792cf72..f64fc72 100644 (file)
@@ -95,6 +95,16 @@ class LanguageRuTest extends LanguageClassesTestCase {
                                'Викитека',
                                'prepositional',
                        ),
+                       array(
+                               'Викисклада',
+                               'Викисклад',
+                               'genitive',
+                       ),
+                       array(
+                               'Викискладе',
+                               'Викисклад',
+                               'prepositional',
+                       ),
                        array(
                                'Викиданных',
                                'Викиданные',
index ef670df..ec51441 100644 (file)
@@ -457,32 +457,22 @@ class LanguageTest extends LanguageClassesTestCase {
         * @dataProvider provideLanguageCodes
         * @covers Language::isValidBuiltInCode
         */
-       public function testBuiltInCodeValidation( $code, $message = '' ) {
-               $this->assertTrue(
+       public function testBuiltInCodeValidation( $code, $expected, $message = '' ) {
+               $this->assertEquals( $expected,
                        (bool)Language::isValidBuiltInCode( $code ),
                        "validating code $code $message"
                );
        }
 
-       /**
-        * @covers Language::isValidBuiltInCode
-        */
-       public function testBuiltInCodeValidationRejectUnderscore() {
-               $this->assertFalse(
-                       (bool)Language::isValidBuiltInCode( 'be_tarask' ),
-                       "reject underscore in language code"
-               );
-       }
-
        public static function provideLanguageCodes() {
                return array(
-                       array( 'fr', 'Two letters, minor case' ),
-                       array( 'EN', 'Two letters, upper case' ),
-                       array( 'tyv', 'Three letters' ),
-                       array( 'tokipona', 'long language code' ),
-                       array( 'be-tarask', 'With dash' ),
-                       array( 'Zh-classical', 'Begin with upper case, dash' ),
-                       array( 'Be-x-old', 'With extension (two dashes)' ),
+                       array( 'fr', true, 'Two letters, minor case' ),
+                       array( 'EN', false, 'Two letters, upper case' ),
+                       array( 'tyv', true, 'Three letters' ),
+                       array( 'tokipona', true, 'long language code' ),
+                       array( 'be-tarask', true, 'With dash' ),
+                       array( 'be-x-old', true, 'With extension (two dashes)' ),
+                       array( 'be_tarask', false, 'Reject underscores' ),
                );
        }
 
diff --git a/tests/phpunit/maintenance/getSlaveServerTest.php b/tests/phpunit/maintenance/getSlaveServerTest.php
deleted file mode 100644 (file)
index 165dc55..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-require_once __DIR__ . "/../../../maintenance/getSlaveServer.php";
-
-/**
- * Tests for getSlaveServer
- *
- * @group Database
- * @covers GetSlaveServer
- */
-class GetSlaveServerTest extends MediaWikiTestCase {
-
-       /**
-        * Yields a regular expression that matches a good DB server name
-        *
-        * It matches IPs or hostnames, both optionally followed by a
-        * port specification
-        *
-        * @return string The regular expression
-        */
-       private function getServerRE() {
-               if ( $this->db->getType() === 'sqlite' ) {
-                       // for SQLite, only the empty string is a good server name
-                       return '';
-               }
-
-               $octet = '([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])';
-               $ip = "(($octet\.){3}$octet)";
-
-               $label = '([a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)';
-               $hostname = "($label(\.$label)*)";
-
-               return "($ip|$hostname)(:[0-9]{1,5})?";
-       }
-
-       function testPlain() {
-               $gss = new GetSlaveServer();
-               $gss->execute();
-
-               $this->expectOutputRegex( "/^" . self::getServerRE() . "\n$/D" );
-       }
-
-       function testXmlDumpsBackupUseCase() {
-               global $wgDBprefix;
-
-               global $argv;
-               $argv = array( null, "--globals" );
-
-               $gss = new GetSlaveServer();
-               $gss->loadParamsAndArgs();
-               $gss->execute();
-               $gss->globals();
-
-               // The main answer
-               $output = $this->getActualOutput();
-               $firstLineEndPos = strpos( $output, "\n" );
-               if ( $firstLineEndPos === false ) {
-                       $this->fail( "Could not find end of first line of output" );
-               }
-               $firstLine = substr( $output, 0, $firstLineEndPos );
-               $this->assertRegExp( "/^" . self::getServerRE() . "$/D",
-                       $firstLine, "DB Server" );
-
-               // xmldumps-backup relies on the wgDBprefix in the output.
-               $this->expectOutputRegex( "/^[[:space:]]*\[wgDBprefix\][[:space:]]*=> "
-                       . $wgDBprefix . "$/m" );
-       }
-}
index d2a4132..c7491d3 100755 (executable)
@@ -105,7 +105,7 @@ class PHPUnitMaintClass extends Maintenance {
                        # The below code injects a parameter just like if the user called
                        # Probably fix bug 29226
                        $key = array_search( '--colors', $_SERVER['argv'] );
-                       if( $key === false ) {
+                       if ( $key === false ) {
                                array_splice( $_SERVER['argv'], 1, 0, '--colors' );
                        }
                }
@@ -115,7 +115,7 @@ class PHPUnitMaintClass extends Maintenance {
                # PHPUnit uses stream_resolve_include_path() internally
                # See bug 32022
                $key = array_search( '--include-path', $_SERVER['argv'] );
-               if( $key === false ) {
+               if ( $key === false ) {
                        array_splice( $_SERVER['argv'], 1, 0,
                                __DIR__
                                . PATH_SEPARATOR
@@ -151,7 +151,7 @@ if ( !class_exists( 'PHPUnit_TextUI_Command' ) ) {
 if ( version_compare( PHP_VERSION, '5.4.0', '<' )
        && version_compare( PHP_VERSION, '5.3.0', '>=' )
 ) {
-       register_shutdown_function( function() {
+       register_shutdown_function( function () {
                gc_collect_cycles();
                gc_disable();
        } );
index 12f147e..2bdc9c9 100644 (file)
@@ -74,13 +74,23 @@ class AutoLoaderTest extends MediaWikiTestCase {
                                )
                        /imx', $contents, $matches, PREG_SET_ORDER );
 
+                       $namespaceMatch = array();
+                       preg_match( '/
+                               ^ [\t ]*
+                                       namespace \s+
+                                               ([a-zA-Z0-9_]+(\\\\[a-zA-Z0-9_]+)*)
+                                       \s* ;
+                       /imx', $contents, $namespaceMatch );
+                       $fileNamespace = $namespaceMatch ? $namespaceMatch[1] . '\\' : '';
+
                        $classesInFile = array();
                        $aliasesInFile = array();
 
                        foreach ( $matches as $match ) {
                                if ( !empty( $match['class'] ) ) {
-                                       $actual[$match['class']] = $file;
-                                       $classesInFile[$match['class']] = true;
+                                       $class = $fileNamespace . $match['class'];
+                                       $actual[$class] = $file;
+                                       $classesInFile[$class] = true;
                                } else {
                                        $aliasesInFile[$match['alias']] = $match['original'];
                                }
index b27337b..bd82d21 100644 (file)
@@ -62,7 +62,6 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
                $messageMemc = wfGetMessageCacheStorage();
                $parserMemc = wfGetParserCacheStorage();
 
-               // $wgContLang = new StubContLang;
                $wgUser = new User;
                $context = new RequestContext;
                $wgLang = $context->getLanguage();
index b2b5322..34007ed 100644 (file)
@@ -8,14 +8,14 @@ return array(
 
        'test.sinonjs' => array(
                'scripts' => array(
-                       'resources/lib/sinonjs/sinon-1.9.0.js',
+                       'resources/lib/sinonjs/sinon-1.10.3.js',
                        // We want tests to work in IE, but can't include this as it
                        // will break the placeholders in Sinon because the hack it uses
                        // to hijack IE globals relies on running in the global scope
                        // and in ResourceLoader this won't be running in the global scope.
                        // Including it results (among other things) in sandboxed timers
                        // being broken due to Date inheritance being undefined.
-                       // 'resources/lib/sinonjs/sinon-ie-1.9.0.js',
+                       // 'resources/lib/sinonjs/sinon-ie-1.10.3.js',
                ),
                'targets' => array( 'desktop', 'mobile' ),
        ),
index 50e89da..2eda8f1 100644 (file)
                                        // As a convenience feature, automatically restore warnings if they're
                                        // still suppressed by the end of the test.
                                        restoreWarnings();
+
+                                       // Check for incomplete animations/requests/etc and throw
+                                       // error if there are any.
+                                       if ( $.timers && $.timers.length !== 0 ) {
+                                               // Test may need to use fake timers, wait for animations or
+                                               // call $.fx.stop().
+                                               throw new Error( 'Unfinished animations: ' + $.timers.length );
+                                       }
+                                       if ( $.active !== undefined && $.active !== 0 ) {
+                                               // Test may need to use fake XHR, wait for requests or
+                                               // call abort().
+                                               throw new Error( 'Unfinished AJAX requests: ' + $.active );
+                                       }
                                }
                        };
                };
index df800bc..c6dd91c 100644 (file)
@@ -4,7 +4,6 @@
 
        var uacount = 0,
                // Object keyed by userAgent. Value is an array (human-readable name, client-profile object, navigator.platform value)
-               // Info based on results from http://toolserver.org/~krinkle/testswarm/job/174/
                uas = {
                        // Internet Explorer 6
                        // Internet Explorer 7
index 9ca434f..3bfabe4 100644 (file)
                                expected: 'доводах',
                                description: 'Grammar test for prepositional case, доводы -> доводах'
                        },
+                       {
+                               word: 'Викисклад',
+                               grammarForm: 'prepositional',
+                               expected: 'Викискладе',
+                               description: 'Grammar test for prepositional case, Викисклад -> Викискладе'
+                       },
+                       {
+                               word: 'Викисклад',
+                               grammarForm: 'genitive',
+                               expected: 'Викисклада',
+                               description: 'Grammar test for genitive case, Викисклад -> Викисклада'
+                       },
                        {
                                word: 'песчаник',
                                grammarForm: 'prepositional',
index d2e7f6e..8c24f39 100644 (file)
@@ -318,7 +318,7 @@ class DbTestRecorder extends DbTestPreviewer {
                        array(
                                'tr_date' => $this->db->timestamp(),
                                'tr_mw_version' => $this->version,
-                               'tr_php_version' => phpversion(),
+                               'tr_php_version' => PHP_VERSION,
                                'tr_db_version' => $this->db->getServerVersion(),
                                'tr_uname' => php_uname()
                        ),
index c611dc3..9a4b332 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -118,7 +118,7 @@ function wfStreamThumb( array $params ) {
        }
        if ( isset( $params['width'] ) && substr( $params['width'], -2 ) == 'px' ) {
                // strip the px (pixel) suffix, if found
-               $params['width'] = substr( $width, 0, strlen( $width ) - 2 );
+               $params['width'] = substr( $params['width'], 0, -2 );
        }
        if ( isset( $params['p'] ) ) {
                $params['page'] = $params['p'];
@@ -367,7 +367,7 @@ function wfGenerateThumbnail( File $file, array $params, $thumbName, $thumbPath
        global $wgMemc, $wgAttemptFailureEpoch;
 
        $key = wfMemcKey( 'attempt-failures', $wgAttemptFailureEpoch,
-               $file->getRepo()->getName(), md5( $file->getName() ), md5( $thumbName ) );
+               $file->getRepo()->getName(), $file->getSha1(), md5( $thumbName ) );
 
        // Check if this file keeps failing to render
        if ( $wgMemc->get( $key ) >= 4 ) {
@@ -376,7 +376,7 @@ function wfGenerateThumbnail( File $file, array $params, $thumbName, $thumbPath
 
        $done = false;
        // Record failures on PHP fatals in addition to caching exceptions
-       register_shutdown_function( function() use ( &$done, $key ) {
+       register_shutdown_function( function () use ( &$done, $key ) {
                if ( !$done ) { // transform() gave a fatal
                        global $wgMemc;
                        // Randomize TTL to reduce stampedes
@@ -399,17 +399,17 @@ function wfGenerateThumbnail( File $file, array $params, $thumbName, $thumbPath
        try {
                $work = new PoolCounterWorkViaCallback( $poolCounterType, sha1( $file->getName() ),
                        array(
-                               'doWork' => function() use ( $file, $params ) {
+                               'doWork' => function () use ( $file, $params ) {
                                        return $file->transform( $params, File::RENDER_NOW );
                                },
-                               'getCachedWork' => function() use ( $file, $params, $thumbPath ) {
+                               'getCachedWork' => function () use ( $file, $params, $thumbPath ) {
                                        // If the worker that finished made this thumbnail then use it.
                                        // Otherwise, it probably made a different thumbnail for this file.
                                        return $file->getRepo()->fileExists( $thumbPath )
                                                ? $file->transform( $params, File::RENDER_NOW )
                                                : false; // retry once more in exclusive mode
                                },
-                               'fallback' => function() {
+                               'fallback' => function () {
                                        return wfMessage( 'generic-pool-error' )->parse();
                                },
                                'error' => function ( $status ) {