Merge "Restore Content-Language header change from e53ff931a"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 4 Oct 2016 02:24:30 +0000 (02:24 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 4 Oct 2016 02:24:30 +0000 (02:24 +0000)
99 files changed:
RELEASE-NOTES-1.28
autoload.php
composer.json
includes/DefaultSettings.php
includes/ServiceWiring.php
includes/actions/HistoryAction.php
includes/db/MWLBFactory.php [new file with mode: 0644]
includes/db/loadbalancer/LBFactoryMW.php [deleted file]
includes/debug/logger/LegacyLogger.php
includes/exception/MWException.php
includes/exception/MWExceptionHandler.php
includes/exception/MWExceptionRenderer.php
includes/installer/Installer.php
includes/installer/MssqlUpdater.php
includes/installer/MysqlUpdater.php
includes/installer/OracleUpdater.php
includes/installer/PostgresUpdater.php
includes/installer/SqliteUpdater.php
includes/installer/i18n/bn.json
includes/installer/i18n/en.json
includes/installer/i18n/qqq.json
includes/libs/MemoizedCallable.php
includes/libs/WaitConditionLoop.php [deleted file]
includes/libs/lockmanager/LockManager.php
includes/libs/lockmanager/MemcLockManager.php
includes/libs/objectcache/APCBagOStuff.php
includes/libs/objectcache/APCUBagOStuff.php [new file with mode: 0644]
includes/libs/objectcache/BagOStuff.php
includes/libs/rdbms/ChronologyProtector.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabasePostgres.php
includes/libs/rdbms/database/IMaintainableDatabase.php
includes/libs/rdbms/lbfactory/LBFactoryMulti.php
includes/libs/rdbms/lbfactory/LBFactorySimple.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/libs/rdbms/loadmonitor/ILoadMonitor.php
includes/libs/rdbms/loadmonitor/LoadMonitor.php
includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php
includes/libs/rdbms/loadmonitor/LoadMonitorNull.php
includes/objectcache/ObjectCache.php
includes/page/WikiPage.php
includes/profiler/Profiler.php
includes/profiler/SectionProfiler.php
includes/skins/SkinTemplate.php
includes/specials/SpecialNewpages.php [changed mode: 0644->0755]
languages/i18n/ar.json
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/diq.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/fr.json
languages/i18n/got.json
languages/i18n/hr.json
languages/i18n/it.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/mr.json
languages/i18n/nb.json
languages/i18n/pl.json
languages/i18n/qqq.json
languages/i18n/tt-cyrl.json
languages/i18n/uz.json
languages/i18n/zh-hans.json
maintenance/archives/patch-change_tag-ct_id.sql [new file with mode: 0644]
maintenance/archives/patch-tag_summary-ts_id.sql [new file with mode: 0644]
maintenance/interwiki.list
maintenance/interwiki.sql
maintenance/mssql/archives/patch-change_tag-ct_id.sql [new file with mode: 0644]
maintenance/mssql/archives/patch-tag_summary-ts_id.sql [new file with mode: 0644]
maintenance/mssql/tables.sql
maintenance/oracle/archives/patch-change_tag-ct_id.sql [new file with mode: 0644]
maintenance/oracle/archives/patch-tag_summary-ts_id.sql [new file with mode: 0644]
maintenance/oracle/tables.sql
maintenance/postgres/tables.sql
maintenance/sql.php
maintenance/sqlite/archives/patch-change_tag-ct_id.sql [new file with mode: 0644]
maintenance/sqlite/archives/patch-tag_summary-ts_id.sql [new file with mode: 0644]
maintenance/tables.sql
resources/Resources.php
resources/lib/oojs-ui/oojs-ui-apex.js
resources/lib/oojs-ui/oojs-ui-core-apex.css
resources/lib/oojs-ui/oojs-ui-core-mediawiki.css
resources/lib/oojs-ui/oojs-ui-core.js
resources/lib/oojs-ui/oojs-ui-mediawiki.js
resources/lib/oojs-ui/oojs-ui-toolbars-apex.css
resources/lib/oojs-ui/oojs-ui-toolbars-mediawiki.css
resources/lib/oojs-ui/oojs-ui-toolbars.js
resources/lib/oojs-ui/oojs-ui-widgets-apex.css
resources/lib/oojs-ui/oojs-ui-widgets-mediawiki.css
resources/lib/oojs-ui/oojs-ui-widgets.js
resources/lib/oojs-ui/oojs-ui-windows-apex.css
resources/lib/oojs-ui/oojs-ui-windows-mediawiki.css
resources/lib/oojs-ui/oojs-ui-windows.js
resources/src/mediawiki/mediawiki.feedback.js
tests/phpunit/includes/db/LBFactoryTest.php
tests/phpunit/includes/libs/MemoizedCallableTest.php
tests/phpunit/includes/libs/WaitConditionLoopTest.php [deleted file]

index 4f687a1..8b7dced 100644 (file)
@@ -6,6 +6,7 @@ MediaWiki 1.28 is an alpha-quality branch and is not recommended for use in
 production.
 
 === Configuration changes in 1.28 ===
+* $wgSend404Code now affects status code of action=history if the page is not there.
 * BREAKING CHANGE: $wgHTTPProxy is now *required* for all external requests
   made by MediaWiki via a proxy. Relying on the http_proxy environment
   variable is no longer supported.
@@ -65,13 +66,17 @@ production.
 
 ==== Upgraded external libraries ====
 * Updated es5-shim from v4.1.5 to v4.5.8
+* Updated composer/semver from v1.4.1 to v1.4.2
+* Updated wikimedia/php-session-serializer from v1.0.3 to v1.0.4
 
 ==== New external libraries ====
 * Added wikimedia/scoped-callback v1.0.0
+* Added wikimedia/wait-condition-loop v1.0.1
 
 ==== Removed and replaced external libraries ====
 
 === Bug fixes in 1.28 ===
+* (T146496) action=history pages should return 404 HTTP error code if the page does not exist
 * (T137264) SECURITY: XSS in unclosed internal links
 * (T133147) SECURITY: Escape '<' and ']]>' in inline <style> blocks
 * (T133147) SECURITY: Require login to preview user CSS pages
index 5b99fac..8d9a80f 100644 (file)
@@ -5,6 +5,7 @@ global $wgAutoloadLocalClasses;
 
 $wgAutoloadLocalClasses = [
        'APCBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCBagOStuff.php',
+       'APCUBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCUBagOStuff.php',
        'AbstractContent' => __DIR__ . '/includes/content/AbstractContent.php',
        'Action' => __DIR__ . '/includes/actions/Action.php',
        'ActiveUsersPager' => __DIR__ . '/includes/specials/pagers/ActiveUsersPager.php',
@@ -663,7 +664,6 @@ $wgAutoloadLocalClasses = [
        'KkConverter' => __DIR__ . '/languages/classes/LanguageKk.php',
        'KuConverter' => __DIR__ . '/languages/classes/LanguageKu.php',
        'LBFactory' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactory.php',
-       'LBFactoryMW' => __DIR__ . '/includes/db/loadbalancer/LBFactoryMW.php',
        'LBFactoryMulti' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactoryMulti.php',
        'LBFactorySimple' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactorySimple.php',
        'LBFactorySingle' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactorySingle.php',
@@ -781,6 +781,7 @@ $wgAutoloadLocalClasses = [
        'MWFileProps' => __DIR__ . '/includes/utils/MWFileProps.php',
        'MWGrants' => __DIR__ . '/includes/utils/MWGrants.php',
        'MWHttpRequest' => __DIR__ . '/includes/HttpFunctions.php',
+       'MWLBFactory' => __DIR__ . '/includes/db/MWLBFactory.php',
        'MWMemcached' => __DIR__ . '/includes/compat/MemcachedClientCompat.php',
        'MWMessagePack' => __DIR__ . '/includes/libs/MWMessagePack.php',
        'MWNamespace' => __DIR__ . '/includes/MWNamespace.php',
@@ -1516,7 +1517,6 @@ $wgAutoloadLocalClasses = [
        'VirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTService.php',
        'VirtualRESTServiceClient' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTServiceClient.php',
        'WANObjectCache' => __DIR__ . '/includes/libs/objectcache/WANObjectCache.php',
-       'WaitConditionLoop' => __DIR__ . '/includes/libs/WaitConditionLoop.php',
        'WantedCategoriesPage' => __DIR__ . '/includes/specials/SpecialWantedcategories.php',
        'WantedFilesPage' => __DIR__ . '/includes/specials/SpecialWantedfiles.php',
        'WantedPagesPage' => __DIR__ . '/includes/specials/SpecialWantedpages.php',
index c827c0f..884b64f 100644 (file)
@@ -16,7 +16,7 @@
                "wiki": "https://www.mediawiki.org/"
        },
        "require": {
-               "composer/semver": "1.4.1",
+               "composer/semver": "1.4.2",
                "cssjanus/cssjanus": "1.1.2",
                "ext-ctype": "*",
                "ext-iconv": "*",
@@ -25,7 +25,7 @@
                "ext-xml": "*",
                "liuggio/statsd-php-client": "1.0.18",
                "mediawiki/at-ease": "1.1.0",
-               "oojs/oojs-ui": "0.17.9",
+               "oojs/oojs-ui": "0.17.10",
                "oyejorge/less.php": "1.7.0.10",
                "php": ">=5.5.9",
                "psr/log": "1.0.0",
                "wikimedia/composer-merge-plugin": "1.3.1",
                "wikimedia/html-formatter": "1.0.1",
                "wikimedia/ip-set": "1.1.0",
-               "wikimedia/php-session-serializer": "1.0.3",
+               "wikimedia/php-session-serializer": "1.0.4",
                "wikimedia/relpath": "1.0.3",
                "wikimedia/running-stat": "1.1.0",
                "wikimedia/scoped-callback": "1.0.0",
                "wikimedia/utfnormal": "1.0.3",
+               "wikimedia/wait-condition-loop": "1.0.1",
                "wikimedia/wrappedstring": "2.2.0",
                "zordius/lightncandy": "0.23"
        },
index f8626e9..b1436b0 100644 (file)
@@ -2211,7 +2211,7 @@ $wgCacheDirectory = false;
  *   - CACHE_NONE:       Do not cache
  *   - CACHE_DB:         Store cache objects in the DB
  *   - CACHE_MEMCACHED:  MemCached, must specify servers in $wgMemCachedServers
- *   - CACHE_ACCEL:      APC, XCache or WinCache
+ *   - CACHE_ACCEL:      APC, APCU, XCache or WinCache
  *   - (other):          A string may be used which identifies a cache
  *                       configuration in $wgObjectCaches.
  *
@@ -2288,6 +2288,7 @@ $wgObjectCaches = [
        ],
 
        'apc' => [ 'class' => 'APCBagOStuff', 'reportDupes' => false ],
+       'apcu' => [ 'class' => 'APCUBagOStuff', 'reportDupes' => false ],
        'xcache' => [ 'class' => 'XCacheBagOStuff', 'reportDupes' => false ],
        'wincache' => [ 'class' => 'WinCacheBagOStuff', 'reportDupes' => false ],
        'memcached-php' => [ 'class' => 'MemcachedPhpBagOStuff', 'loggroup' => 'memcached' ],
index 6044911..11ee616 100644 (file)
@@ -45,11 +45,11 @@ return [
        'DBLoadBalancerFactory' => function( MediaWikiServices $services ) {
                $mainConfig = $services->getMainConfig();
 
-               $lbConf = LBFactoryMW::applyDefaultConfig(
+               $lbConf = MWLBFactory::applyDefaultConfig(
                        $mainConfig->get( 'LBFactoryConf' ),
                        $mainConfig
                );
-               $class = LBFactoryMW::getLBFactoryClass( $lbConf );
+               $class = MWLBFactory::getLBFactoryClass( $lbConf );
 
                return new $class( $lbConf );
        },
index f3ef3b3..1e1bb39 100644 (file)
@@ -139,6 +139,10 @@ class HistoryAction extends FormlessAction {
 
                // Fail nicely if article doesn't exist.
                if ( !$this->page->exists() ) {
+                       global $wgSend404Code;
+                       if ( $wgSend404Code ) {
+                               $out->setStatusCode( 404 );
+                       }
                        $out->addWikiMsg( 'nohistory' );
                        # show deletion/move log if there is an entry
                        LogEventsList::showLogExtract(
diff --git a/includes/db/MWLBFactory.php b/includes/db/MWLBFactory.php
new file mode 100644 (file)
index 0000000..96c6e9f
--- /dev/null
@@ -0,0 +1,158 @@
+<?php
+/**
+ * Generator of database load balancing objects.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+
+use MediaWiki\Logger\LoggerFactory;
+
+/**
+ * MediaWiki-specific class for generating database load balancers
+ * @ingroup Database
+ */
+abstract class MWLBFactory {
+       /**
+        * @param array $lbConf Config for LBFactory::__construct()
+        * @param Config $mainConfig Main config object from MediaWikiServices
+        * @return array
+        */
+       public static function applyDefaultConfig( array $lbConf, Config $mainConfig ) {
+               global $wgCommandLineMode;
+
+               $lbConf += [
+                       'localDomain' => new DatabaseDomain(
+                               $mainConfig->get( 'DBname' ),
+                               null,
+                               $mainConfig->get( 'DBprefix' )
+                       ),
+                       'profiler' => Profiler::instance(),
+                       'trxProfiler' => Profiler::instance()->getTransactionProfiler(),
+                       'replLogger' => LoggerFactory::getInstance( 'DBReplication' ),
+                       'queryLogger' => LoggerFactory::getInstance( 'DBQuery' ),
+                       'connLogger' => LoggerFactory::getInstance( 'DBConnection' ),
+                       'perfLogger' => LoggerFactory::getInstance( 'DBPerformance' ),
+                       'errorLogger' => [ MWExceptionHandler::class, 'logException' ],
+                       'cliMode' => $wgCommandLineMode,
+                       'hostname' => wfHostname(),
+                       // TODO: replace the global wfConfiguredReadOnlyReason() with a service.
+                       'readOnlyReason' => wfConfiguredReadOnlyReason(),
+               ];
+
+               if ( $lbConf['class'] === 'LBFactorySimple' ) {
+                       if ( isset( $lbConf['servers'] ) ) {
+                               // Server array is already explicitly configured; leave alone
+                       } elseif ( is_array( $mainConfig->get( 'DBservers' ) ) ) {
+                               foreach ( $mainConfig->get( 'DBservers' ) as $i => $server ) {
+                                       if ( $server['type'] === 'sqlite' ) {
+                                               $server += [ 'dbDirectory' => $mainConfig->get( 'SQLiteDataDir' ) ];
+                                       } elseif ( $server['type'] === 'postgres' ) {
+                                               $server += [ 'port' => $mainConfig->get( 'DBport' ) ];
+                                       }
+                                       $lbConf['servers'][$i] = $server + [
+                                               'schema' => $mainConfig->get( 'DBmwschema' ),
+                                               'tablePrefix' => $mainConfig->get( 'DBprefix' ),
+                                               'flags' => DBO_DEFAULT,
+                                               'sqlMode' => $mainConfig->get( 'SQLMode' ),
+                                               'utf8Mode' => $mainConfig->get( 'DBmysql5' )
+                                       ];
+                               }
+                       } else {
+                               $flags = DBO_DEFAULT;
+                               $flags |= $mainConfig->get( 'DebugDumpSql' ) ? DBO_DEBUG : 0;
+                               $flags |= $mainConfig->get( 'DBssl' ) ? DBO_SSL : 0;
+                               $flags |= $mainConfig->get( 'DBcompress' ) ? DBO_COMPRESS : 0;
+                               $server = [
+                                       'host' => $mainConfig->get( 'DBserver' ),
+                                       'user' => $mainConfig->get( 'DBuser' ),
+                                       'password' => $mainConfig->get( 'DBpassword' ),
+                                       'dbname' => $mainConfig->get( 'DBname' ),
+                                       'schema' => $mainConfig->get( 'DBmwschema' ),
+                                       'tablePrefix' => $mainConfig->get( 'DBprefix' ),
+                                       'type' => $mainConfig->get( 'DBtype' ),
+                                       'load' => 1,
+                                       'flags' => $flags,
+                                       'sqlMode' => $mainConfig->get( 'SQLMode' ),
+                                       'utf8Mode' => $mainConfig->get( 'DBmysql5' )
+                               ];
+                               if ( $server['type'] === 'sqlite' ) {
+                                       $server[ 'dbDirectory'] = $mainConfig->get( 'SQLiteDataDir' );
+                               } elseif ( $server['type'] === 'postgres' ) {
+                                       $server['port'] = $mainConfig->get( 'DBport' );
+                               }
+                               $lbConf['servers'] = [ $server ];
+                       }
+                       if ( !isset( $lbConf['externalClusters'] ) ) {
+                               $lbConf['externalClusters'] = $mainConfig->get( 'ExternalServers' );
+                       }
+               } elseif ( $lbConf['class'] === 'LBFactoryMulti' ) {
+                       if ( isset( $lbConf['serverTemplate'] ) ) {
+                               $lbConf['serverTemplate']['schema'] = $mainConfig->get( 'DBmwschema' );
+                               $lbConf['serverTemplate']['sqlMode'] = $mainConfig->get( 'SQLMode' );
+                               $lbConf['serverTemplate']['utf8Mode'] = $mainConfig->get( 'DBmysql5' );
+                       }
+               }
+
+               // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
+               $sCache = ObjectCache::getLocalServerInstance();
+               if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
+                       $lbConf['srvCache'] = $sCache;
+               }
+               $cCache = ObjectCache::getLocalClusterInstance();
+               if ( $cCache->getQoS( $cCache::ATTR_EMULATION ) > $cCache::QOS_EMULATION_SQL ) {
+                       $lbConf['memCache'] = $cCache;
+               }
+               $wCache = ObjectCache::getMainWANInstance();
+               if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
+                       $lbConf['wanCache'] = $wCache;
+               }
+
+               return $lbConf;
+       }
+
+       /**
+        * Returns the LBFactory class to use and the load balancer configuration.
+        *
+        * @todo instead of this, use a ServiceContainer for managing the different implementations.
+        *
+        * @param array $config (e.g. $wgLBFactoryConf)
+        * @return string Class name
+        */
+       public static function getLBFactoryClass( array $config ) {
+               // For configuration backward compatibility after removing
+               // underscores from class names in MediaWiki 1.23.
+               $bcClasses = [
+                       'LBFactory_Simple' => 'LBFactorySimple',
+                       'LBFactory_Single' => 'LBFactorySingle',
+                       'LBFactory_Multi' => 'LBFactoryMulti'
+               ];
+
+               $class = $config['class'];
+
+               if ( isset( $bcClasses[$class] ) ) {
+                       $class = $bcClasses[$class];
+                       wfDeprecated(
+                               '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details',
+                               '1.23'
+                       );
+               }
+
+               return $class;
+       }
+}
diff --git a/includes/db/loadbalancer/LBFactoryMW.php b/includes/db/loadbalancer/LBFactoryMW.php
deleted file mode 100644 (file)
index 9821da1..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-<?php
-/**
- * Generator of database load balancing objects.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Database
- */
-
-use MediaWiki\Logger\LoggerFactory;
-
-/**
- * Legacy MediaWiki-specific class for generating database load balancers
- * @ingroup Database
- */
-abstract class LBFactoryMW {
-       /**
-        * @param array $lbConf Config for LBFactory::__construct()
-        * @param Config $mainConfig Main config object from MediaWikiServices
-        * @return array
-        */
-       public static function applyDefaultConfig( array $lbConf, Config $mainConfig ) {
-               global $wgCommandLineMode;
-
-               $lbConf += [
-                       'localDomain' => new DatabaseDomain(
-                               $mainConfig->get( 'DBname' ),
-                               null,
-                               $mainConfig->get( 'DBprefix' )
-                       ),
-                       'profiler' => Profiler::instance(),
-                       'trxProfiler' => Profiler::instance()->getTransactionProfiler(),
-                       'replLogger' => LoggerFactory::getInstance( 'DBReplication' ),
-                       'queryLogger' => LoggerFactory::getInstance( 'DBQuery' ),
-                       'connLogger' => LoggerFactory::getInstance( 'DBConnection' ),
-                       'perfLogger' => LoggerFactory::getInstance( 'DBPerformance' ),
-                       'errorLogger' => [ MWExceptionHandler::class, 'logException' ],
-                       'cliMode' => $wgCommandLineMode,
-                       'hostname' => wfHostname(),
-                       // TODO: replace the global wfConfiguredReadOnlyReason() with a service.
-                       'readOnlyReason' => wfConfiguredReadOnlyReason(),
-               ];
-
-               if ( $lbConf['class'] === 'LBFactorySimple' ) {
-                       if ( isset( $lbConf['servers'] ) ) {
-                               // Server array is already explicitly configured; leave alone
-                       } elseif ( is_array( $mainConfig->get( 'DBservers' ) ) ) {
-                               foreach ( $mainConfig->get( 'DBservers' ) as $i => $server ) {
-                                       if ( $server['type'] === 'sqlite' ) {
-                                               $server += [ 'dbDirectory' => $mainConfig->get( 'SQLiteDataDir' ) ];
-                                       } elseif ( $server['type'] === 'postgres' ) {
-                                               $server += [ 'port' => $mainConfig->get( 'DBport' ) ];
-                                       }
-                                       $lbConf['servers'][$i] = $server + [
-                                               'schema' => $mainConfig->get( 'DBmwschema' ),
-                                               'tablePrefix' => $mainConfig->get( 'DBprefix' ),
-                                               'flags' => DBO_DEFAULT,
-                                               'sqlMode' => $mainConfig->get( 'SQLMode' ),
-                                               'utf8Mode' => $mainConfig->get( 'DBmysql5' )
-                                       ];
-                               }
-                       } else {
-                               $flags = DBO_DEFAULT;
-                               $flags |= $mainConfig->get( 'DebugDumpSql' ) ? DBO_DEBUG : 0;
-                               $flags |= $mainConfig->get( 'DBssl' ) ? DBO_SSL : 0;
-                               $flags |= $mainConfig->get( 'DBcompress' ) ? DBO_COMPRESS : 0;
-                               $server = [
-                                       'host' => $mainConfig->get( 'DBserver' ),
-                                       'user' => $mainConfig->get( 'DBuser' ),
-                                       'password' => $mainConfig->get( 'DBpassword' ),
-                                       'dbname' => $mainConfig->get( 'DBname' ),
-                                       'schema' => $mainConfig->get( 'DBmwschema' ),
-                                       'tablePrefix' => $mainConfig->get( 'DBprefix' ),
-                                       'type' => $mainConfig->get( 'DBtype' ),
-                                       'load' => 1,
-                                       'flags' => $flags,
-                                       'sqlMode' => $mainConfig->get( 'SQLMode' ),
-                                       'utf8Mode' => $mainConfig->get( 'DBmysql5' )
-                               ];
-                               if ( $server['type'] === 'sqlite' ) {
-                                       $server[ 'dbDirectory'] = $mainConfig->get( 'SQLiteDataDir' );
-                               } elseif ( $server['type'] === 'postgres' ) {
-                                       $server['port'] = $mainConfig->get( 'DBport' );
-                               }
-                               $lbConf['servers'] = [ $server ];
-                       }
-                       if ( !isset( $lbConf['externalClusters'] ) ) {
-                               $lbConf['externalClusters'] = $mainConfig->get( 'ExternalServers' );
-                       }
-               } elseif ( $lbConf['class'] === 'LBFactoryMulti' ) {
-                       if ( isset( $lbConf['serverTemplate'] ) ) {
-                               $lbConf['serverTemplate']['schema'] = $mainConfig->get( 'DBmwschema' );
-                               $lbConf['serverTemplate']['sqlMode'] = $mainConfig->get( 'SQLMode' );
-                               $lbConf['serverTemplate']['utf8Mode'] = $mainConfig->get( 'DBmysql5' );
-                       }
-               }
-
-               // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
-               $sCache = ObjectCache::getLocalServerInstance();
-               if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
-                       $lbConf['srvCache'] = $sCache;
-               }
-               $cCache = ObjectCache::getLocalClusterInstance();
-               if ( $cCache->getQoS( $cCache::ATTR_EMULATION ) > $cCache::QOS_EMULATION_SQL ) {
-                       $lbConf['memCache'] = $cCache;
-               }
-               $wCache = ObjectCache::getMainWANInstance();
-               if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
-                       $lbConf['wanCache'] = $wCache;
-               }
-
-               return $lbConf;
-       }
-
-       /**
-        * Returns the LBFactory class to use and the load balancer configuration.
-        *
-        * @todo instead of this, use a ServiceContainer for managing the different implementations.
-        *
-        * @param array $config (e.g. $wgLBFactoryConf)
-        * @return string Class name
-        */
-       public static function getLBFactoryClass( array $config ) {
-               // For configuration backward compatibility after removing
-               // underscores from class names in MediaWiki 1.23.
-               $bcClasses = [
-                       'LBFactory_Simple' => 'LBFactorySimple',
-                       'LBFactory_Single' => 'LBFactorySingle',
-                       'LBFactory_Multi' => 'LBFactoryMulti'
-               ];
-
-               $class = $config['class'];
-
-               if ( isset( $bcClasses[$class] ) ) {
-                       $class = $bcClasses[$class];
-                       wfDeprecated(
-                               '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details',
-                               '1.23'
-                       );
-               }
-
-               return $class;
-       }
-}
index 3318ceb..4d7c84d 100644 (file)
@@ -94,6 +94,9 @@ class LegacyLogger extends AbstractLogger {
         * @return null
         */
        public function log( $level, $message, array $context = [] ) {
+               if ( is_string( $level ) ) {
+                       $level = self::$levelMapping[$level];
+               }
                if ( $this->channel === 'DBQuery' && isset( $context['method'] )
                        && isset( $context['master'] ) && isset( $context['runtime'] )
                ) {
@@ -102,8 +105,7 @@ class LegacyLogger extends AbstractLogger {
                }
 
                if ( isset( self::$dbChannels[$this->channel] )
-                       && isset( self::$levelMapping[$level] )
-                       && self::$levelMapping[$level] >= LogLevel::ERROR
+                       && $level >= self::$levelMapping[LogLevel::ERROR]
                ) {
                        // Format and write DB errors to the legacy locations
                        $effectiveChannel = 'wfLogDBError';
@@ -127,7 +129,7 @@ class LegacyLogger extends AbstractLogger {
         *
         * @param string $channel
         * @param string $message
-        * @param string|int $level \Psr\Log\LogEvent constant or Monlog level int
+        * @param string|int $level \Psr\Log\LogEvent constant or Monolog level int
         * @param array $context
         * @return bool True if message should be sent to disk/network, false
         * otherwise
@@ -135,6 +137,10 @@ class LegacyLogger extends AbstractLogger {
        public static function shouldEmit( $channel, $message, $level, $context ) {
                global $wgDebugLogFile, $wgDBerrorLog, $wgDebugLogGroups;
 
+               if ( is_string( $level ) ) {
+                       $level = self::$levelMapping[$level];
+               }
+
                if ( $channel === 'wfLogDBError' ) {
                        // wfLogDBError messages are emitted if a database log location is
                        // specfied.
@@ -162,9 +168,6 @@ class LegacyLogger extends AbstractLogger {
                                }
 
                                if ( isset( $logConfig['level'] ) ) {
-                                       if ( is_string( $level ) ) {
-                                               $level = self::$levelMapping[$level];
-                                       }
                                        $shouldEmit = $level >= self::$levelMapping[$logConfig['level']];
                                }
                        } else {
index 5496cb6..e958c94 100644 (file)
@@ -199,7 +199,26 @@ class MWException extends Exception {
         * It will be either HTML or plain text based on isCommandLine().
         */
        public function report() {
-               MWExceptionRenderer::output( $this, MWExceptionRenderer::AS_PRETTY );
+               global $wgMimeType;
+
+               if ( defined( 'MW_API' ) ) {
+                       // Unhandled API exception, we can't be sure that format printer is alive
+                       self::header( 'MediaWiki-API-Error: internal_api_error_' . get_class( $this ) );
+                       wfHttpError( 500, 'Internal Server Error', $this->getText() );
+               } elseif ( self::isCommandLine() ) {
+                       $message = $this->getText();
+                       // T17602: STDERR may not be available
+                       if ( defined( 'STDERR' ) ) {
+                               fwrite( STDERR, $message );
+                       } else {
+                               echo $message;
+                       }
+               } else {
+                       self::statusHeader( 500 );
+                       self::header( "Content-Type: $wgMimeType; charset=utf-8" );
+
+                       $this->reportHTML();
+               }
        }
 
        /**
index 797b3af..4a1f190 100644 (file)
@@ -68,14 +68,13 @@ class MWExceptionHandler {
                                // removed.
                                $e->report();
                        } else {
-                               MWExceptionRenderer::output(
-                                       $e, MWExceptionRenderer::AS_PRETTY );
+                               MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY );
                        }
                } catch ( Exception $e2 ) {
                        // Exception occurred from within exception handler
                        // Show a simpler message for the original exception,
                        // don't try to invoke report()
-                       MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_PRETTY, $e2 );
+                       MWExceptionRenderer::output( $e, MWExceptionRenderer::AS_RAW, $e2 );
                }
        }
 
index aba131d..8fdc417 100644 (file)
@@ -35,11 +35,6 @@ class MWExceptionRenderer {
        public static function output( $e, $mode, $eNew = null ) {
                global $wgMimeType;
 
-               if ( $e instanceof DBConnectionError ) {
-                       self::reportOutageHTML( $e );
-                       return;
-               }
-
                if ( defined( 'MW_API' ) ) {
                        // Unhandled API exception, we can't be sure that format printer is alive
                        self::header( 'MediaWiki-API-Error: internal_api_error_' . get_class( $e ) );
@@ -47,9 +42,13 @@ class MWExceptionRenderer {
                } elseif ( self::isCommandLine() ) {
                        self::printError( self::getText( $e ) );
                } elseif ( $mode === self::AS_PRETTY ) {
-                       self::statusHeader( 500 );
-                       self::header( "Content-Type: $wgMimeType; charset=utf-8" );
-                       self::reportHTML( $e );
+                       if ( $e instanceof DBConnectionError ) {
+                               self::reportOutageHTML( $e );
+                       } else {
+                               self::statusHeader( 500 );
+                               self::header( "Content-Type: $wgMimeType; charset=utf-8" );
+                               self::reportHTML( $e );
+                       }
                } else {
                        if ( $eNew ) {
                                $message = "MediaWiki internal error.\n\n";
index eafb9d4..03f9974 100644 (file)
@@ -244,6 +244,7 @@ abstract class Installer {
        protected $objectCaches = [
                'xcache' => 'xcache_get',
                'apc' => 'apc_fetch',
+               'apcu' => 'apcu_fetch',
                'wincache' => 'wincache_ucache_get'
        ];
 
index 770d3bf..1175e9e 100644 (file)
@@ -92,6 +92,8 @@ class MssqlUpdater extends DatabaseUpdater {
                        // 1.28
                        [ 'addIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
                                'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
+                       [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+                       [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
                ];
        }
 
index 693b6ff..497f273 100644 (file)
@@ -288,6 +288,8 @@ class MysqlUpdater extends DatabaseUpdater {
                                'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
                        [ 'doRevisionPageRevIndexNonUnique' ],
                        [ 'doNonUniquePlTlIl' ],
+                       [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+                       [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
                ];
        }
 
index 8075aac..e1e0d0f 100644 (file)
@@ -116,6 +116,8 @@ class OracleUpdater extends DatabaseUpdater {
                        // 1.28
                        [ 'addIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
                                'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
+                       [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+                       [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
 
                        // KEEP THIS AT THE BOTTOM!!
                        [ 'doRebuildDuplicateFunction' ],
index be94d91..f3d2860 100644 (file)
@@ -68,6 +68,8 @@ class PostgresUpdater extends DatabaseUpdater {
                        [ 'addSequence', 'archive', false, 'archive_ar_id_seq' ],
                        [ 'addSequence', 'externallinks', false, 'externallinks_el_id_seq' ],
                        [ 'addSequence', 'watchlist', false, 'watchlist_wl_id_seq' ],
+                       [ 'addSequence', 'change_tag', false, 'change_tag_ct_id_seq' ],
+                       [ 'addSequence', 'tag_summary', false, 'tag_summary_ts_id_seq' ],
 
                        # new tables
                        [ 'addTable', 'category', 'patch-category.sql' ],
@@ -437,6 +439,10 @@ class PostgresUpdater extends DatabaseUpdater {
                        // 1.28
                        [ 'addPgIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
                                '( rc_namespace, rc_type, rc_patrolled, rc_timestamp )' ],
+                       [ 'addPgField', 'change_tag', 'ct_id',
+                               "INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('change_tag_ct_id_seq')" ],
+                       [ 'addPgField', 'tag_summary', 'ts_id',
+                               "INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('tag_summary_ts_id_seq')" ],
                ];
        }
 
index 1c6e6eb..388c034 100644 (file)
@@ -156,6 +156,8 @@ class SqliteUpdater extends DatabaseUpdater {
                        // 1.28
                        [ 'addIndex', 'recentchanges', 'rc_name_type_patrolled_timestamp',
                                'patch-add-rc_name_type_patrolled_timestamp_index.sql' ],
+                       [ 'addField', 'change_tag', 'ct_id', 'patch-change_tag-ct_id.sql' ],
+                       [ 'addField', 'tag_summary', 'ts_id', 'patch-tag_summary-ts_id.sql' ],
                ];
        }
 
index fb23d01..6926650 100644 (file)
@@ -6,7 +6,8 @@
                        "Aftab1995",
                        "Tauhid16",
                        "Aftabuzzaman",
-                       "Hasive"
+                       "Hasive",
+                       "আজিজ"
                ]
        },
        "config-desc": "মিডিয়াউইকির জন্য ইন্সটলার",
@@ -94,7 +95,9 @@
        "config-admin-name": "আপনার ব্যবহারকারী নাম:",
        "config-admin-password": "পাসওয়ার্ড:",
        "config-admin-password-confirm": "পাসওয়ার্ড আবারও প্রবেশ করান:",
+       "config-admin-help": "এখানে আপনার পছন্দের ব্যবহারকারী নাম লিখুন, উদাহরণস্বরূপ \"আজিজ\"। এই নামটি উইকিতে প্রবেশের সময় ব্যবহার করতে হবে।",
        "config-admin-name-blank": "একটি প্রশাসক ব্যবহারকারী নাম প্রবেশ করান",
+       "config-admin-name-invalid": "উল্লেখিত ব্যবহারকারী নাম \"<nowiki>$1</nowiki>\" অবৈধ। একটি ভিন্ন নাম উল্লেখ করুন।",
        "config-admin-password-blank": "প্রশাসক অ্যাকাউন্টের জন্য পাসওয়ার্ড প্রবেশ করান।",
        "config-admin-password-mismatch": "আপনি যে দুটি পাসওয়ার্ড দিয়েছেন তারা পরস্পর মেলেনি।",
        "config-admin-email": "ইমেইল ঠিকানা:",
index 3f3032b..6a6c0ff 100644 (file)
@@ -57,6 +57,7 @@
        "config-memory-bad": "<strong>Warning:</strong> PHP's <code>memory_limit</code> is $1.\nThis is probably too low.\nThe installation may fail!",
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] is installed",
        "config-apc": "[http://www.php.net/apc APC] is installed",
+       "config-apcu": "[http://www.php.net/apcu APCu] is installed",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] is installed",
        "config-no-cache-apcu": "<strong>Warning:</strong> Could not find [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] or [http://www.iis.net/download/WinCacheForPhp WinCache].\nObject caching is not enabled.",
        "config-mod-security": "<strong>Warning:</strong> Your web server has [http://modsecurity.org/ mod_security]/mod_security2 enabled. Many common configurations of this will cause problems for MediaWiki and other software that allows users to post arbitrary content.\nIf possible, this should be disabled. Otherwise, refer to [http://modsecurity.org/documentation/ mod_security documentation] or contact your host's support if you encounter random errors.",
        "config-cache-options": "Settings for object caching:",
        "config-cache-help": "Object caching is used to improve the speed of MediaWiki by caching frequently used data.\nMedium to large sites are highly encouraged to enable this, and small sites will see benefits as well.",
        "config-cache-none": "No caching (no functionality is removed, but speed may be impacted on larger wiki sites)",
-       "config-cache-accel": "PHP object caching (APC, XCache or WinCache)",
+       "config-cache-accel": "PHP object caching (APC, APCu, XCache or WinCache)",
        "config-cache-memcached": "Use Memcached (requires additional setup and configuration)",
        "config-memcached-servers": "Memcached servers:",
        "config-memcached-help": "List of IP addresses to use for Memcached.\nShould specify one per line and specify the port to be used. For example:\n 127.0.0.1:11211\n 192.168.1.25:1234",
index 833e7d6..d7e86be 100644 (file)
@@ -75,6 +75,7 @@
        "config-memory-bad": "Parameters:\n* $1 is the configured <code>memory_limit</code>.",
        "config-xcache": "Message indicates if this program is available",
        "config-apc": "Message indicates if this program is available",
+       "config-apcu": "Message indicates if this program is available",
        "config-wincache": "Message indicates if this program is available",
        "config-no-cache-apcu": "Status message in the MediaWiki installer environment checks.",
        "config-mod-security": "Status message in the MediaWiki installer environment checks.",
index 50e9732..12a5cad 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * APC-backed function memoization
+ * APC-backed and APCu-backed function memoization
  *
  * This class provides memoization for pure functions. A function is pure
  * if its result value depends on nothing other than its input parameters
@@ -8,7 +8,7 @@
  *
  * The first invocation of the memoized callable with a particular set of
  * arguments will be delegated to the underlying callable. Repeat invocations
- * with the same input parameters will be served from APC.
+ * with the same input parameters will be served from APC or APCu.
  *
  * @par Example:
  * @code
@@ -70,7 +70,7 @@ class MemoizedCallable {
        }
 
        /**
-        * Fetch the result of a previous invocation from APC.
+        * Fetch the result of a previous invocation from APC or APCu.
         *
         * @param string $key
         * @param bool &$success
@@ -79,12 +79,14 @@ class MemoizedCallable {
                $success = false;
                if ( function_exists( 'apc_fetch' ) ) {
                        return apc_fetch( $key, $success );
+               } elseif ( function_exists( 'apcu_fetch' ) ) {
+                       return apcu_fetch( $key, $success );
                }
                return false;
        }
 
        /**
-        * Store the result of an invocation in APC.
+        * Store the result of an invocation in APC or APCu.
         *
         * @param string $key
         * @param mixed $result
@@ -92,6 +94,8 @@ class MemoizedCallable {
        protected function storeResult( $key, $result ) {
                if ( function_exists( 'apc_store' ) ) {
                        apc_store( $key, $result, $this->ttl );
+               } elseif ( function_exists( 'apcu_store' ) ) {
+                       apcu_store( $key, $result, $this->ttl );
                }
        }
 
diff --git a/includes/libs/WaitConditionLoop.php b/includes/libs/WaitConditionLoop.php
deleted file mode 100644 (file)
index 969e86e..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-<?php
-/**
- * Wait loop that reaches a condition or times out.
- *
- * 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 Aaron Schulz
- */
-
-/**
- * Wait loop that reaches a condition or times out
- * @since 1.28
- */
-class WaitConditionLoop {
-       /** @var callable */
-       private $condition;
-       /** @var callable[] */
-       private $busyCallbacks = [];
-       /** @var float Seconds */
-       private $timeout;
-       /** @var float Seconds */
-       private $lastWaitTime;
-       /** @var integer|null */
-       private $rusageMode;
-
-       const CONDITION_REACHED = 1;
-       const CONDITION_CONTINUE = 0; // evaluates as falsey
-       const CONDITION_FAILED = -1;
-       const CONDITION_TIMED_OUT = -2;
-       const CONDITION_ABORTED = -3;
-
-       /**
-        * @param callable $condition Callback that returns a WaitConditionLoop::CONDITION_ constant
-        * @param float $timeout Timeout in seconds
-        * @param array &$busyCallbacks List of callbacks to do useful work (by reference)
-        */
-       public function __construct( callable $condition, $timeout = 5.0, &$busyCallbacks = [] ) {
-               $this->condition = $condition;
-               $this->timeout = $timeout;
-               $this->busyCallbacks =& $busyCallbacks;
-
-               if ( defined( 'HHVM_VERSION' ) && PHP_OS === 'Linux' ) {
-                       $this->rusageMode = 2; // RUSAGE_THREAD
-               } elseif ( function_exists( 'getrusage' ) ) {
-                       $this->rusageMode = 0; // RUSAGE_SELF
-               }
-       }
-
-       /**
-        * Invoke the loop and continue until either:
-        *   - a) The condition callback returns neither CONDITION_CONTINUE nor false
-        *   - b) The timeout is reached
-        * This a condition callback can return true (stop) or false (continue) for convenience.
-        * In such cases, the halting result of "true" will be converted to CONDITION_REACHED.
-        *
-        * If $timeout is 0, then only the condition callback will be called (no busy callbacks),
-        * and this will immediately return CONDITION_FAILED if the condition was not met.
-        *
-        * Exceptions in callbacks will be caught and the callback will be swapped with
-        * one that simply rethrows that exception back to the caller when invoked.
-        *
-        * @return integer WaitConditionLoop::CONDITION_* constant
-        * @throws Exception Any error from the condition callback
-        */
-       public function invoke() {
-               $elapsed = 0.0; // seconds
-               $sleepUs = 0; // microseconds to sleep each time
-               $lastCheck = false;
-               $finalResult = self::CONDITION_TIMED_OUT;
-               do {
-                       $checkStartTime = $this->getWallTime();
-                       // Check if the condition is met yet
-                       $realStart = $this->getWallTime();
-                       $cpuStart = $this->getCpuTime();
-                       $checkResult = call_user_func( $this->condition );
-                       $cpu = $this->getCpuTime() - $cpuStart;
-                       $real = $this->getWallTime() - $realStart;
-                       // Exit if the condition is reached, and error occurs, or this is non-blocking
-                       if ( $this->timeout <= 0 ) {
-                               $finalResult = $checkResult ? self::CONDITION_REACHED : self::CONDITION_FAILED;
-                               break;
-                       } elseif ( (int)$checkResult !== self::CONDITION_CONTINUE ) {
-                               if ( is_int( $checkResult ) ) {
-                                       $finalResult = $checkResult;
-                               } else {
-                                       $finalResult = self::CONDITION_REACHED;
-                               }
-                               break;
-                       } elseif ( $lastCheck ) {
-                               break; // timeout reached
-                       }
-                       // Detect if condition callback seems to block or if justs burns CPU
-                       $conditionUsesInterrupts = ( $real > 0.100 && $cpu <= $real * .03 );
-                       if ( !$this->popAndRunBusyCallback() && !$conditionUsesInterrupts ) {
-                               // 10 queries = 10(10+100)/2 ms = 550ms, 14 queries = 1050ms
-                               $sleepUs = min( $sleepUs + 10 * 1e3, 1e6 ); // stop incrementing at ~1s
-                               $this->usleep( $sleepUs );
-                       }
-                       $checkEndTime = $this->getWallTime();
-                       // The max() protects against the clock getting set back
-                       $elapsed += max( $checkEndTime - $checkStartTime, 0.010 );
-                       // Do not let slow callbacks timeout without checking the condition one more time
-                       $lastCheck = ( $elapsed >= $this->timeout );
-               } while ( true );
-
-               $this->lastWaitTime = $elapsed;
-
-               return $finalResult;
-       }
-
-       /**
-        * @return float Seconds
-        */
-       public function getLastWaitTime() {
-               return $this->lastWaitTime;
-       }
-
-       /**
-        * @param integer $microseconds
-        */
-       protected function usleep( $microseconds ) {
-               usleep( $microseconds );
-       }
-
-       /**
-        * @return float
-        */
-       protected function getWallTime() {
-               return microtime( true );
-       }
-
-       /**
-        * @return float Returns 0.0 if not supported (Windows on PHP < 7)
-        */
-       protected function getCpuTime() {
-               if ( $this->rusageMode === null ) {
-                       return microtime( true ); // assume worst case (all time is CPU)
-               }
-
-               $ru = getrusage( $this->rusageMode );
-               $time = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
-               $time += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
-
-               return $time;
-       }
-
-       /**
-        * Run one of the callbacks that does work ahead of time for another caller
-        *
-        * @return bool Whether a callback was executed
-        */
-       private function popAndRunBusyCallback() {
-               if ( $this->busyCallbacks ) {
-                       reset( $this->busyCallbacks );
-                       $key = key( $this->busyCallbacks );
-                       /** @var callable $workCallback */
-                       $workCallback =& $this->busyCallbacks[$key];
-                       try {
-                               $workCallback();
-                       } catch ( Exception $e ) {
-                               $workCallback = function () use ( $e ) {
-                                       throw $e;
-                               };
-                       }
-                       unset( $this->busyCallbacks[$key] ); // consume
-
-                       return true;
-               }
-
-               return false;
-       }
-}
index e89a9c7..bee34dc 100644 (file)
@@ -4,6 +4,7 @@
  * @ingroup FileBackend
  */
 use Psr\Log\LoggerInterface;
+use Wikimedia\WaitConditionLoop;
 
 /**
  * Resource locking handling.
index 83334fe..aecdf60 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  * @ingroup LockManager
  */
+use Wikimedia\WaitConditionLoop;
 
 /**
  * Manage locks using memcached servers.
index 8f70fc7..9bfcee7 100644 (file)
@@ -75,25 +75,35 @@ class APCBagOStuff extends BagOStuff {
        }
 
        protected function doGet( $key, $flags = 0 ) {
-               $val = apc_fetch( $key . self::KEY_SUFFIX );
+               return $this->getUnserialize(
+                       apc_fetch( $key . self::KEY_SUFFIX )
+               );
+       }
 
-               if ( is_string( $val ) && !$this->nativeSerialize ) {
-                       $val = $this->isInteger( $val )
-                               ? intval( $val )
-                               : unserialize( $val );
+       protected function getUnserialize( $value ) {
+               if ( is_string( $value ) && !$this->nativeSerialize ) {
+                       $value = $this->isInteger( $value )
+                               ? intval( $value )
+                               : unserialize( $value );
                }
-
-               return $val;
+               return $value;
        }
 
        public function set( $key, $value, $exptime = 0, $flags = 0 ) {
+               apc_store(
+                       $key . self::KEY_SUFFIX,
+                       $this->setSerialize( $value ),
+                       $exptime
+               );
+
+               return true;
+       }
+
+       protected function setSerialize( $value ) {
                if ( !$this->nativeSerialize && !$this->isInteger( $value ) ) {
                        $value = serialize( $value );
                }
-
-               apc_store( $key . self::KEY_SUFFIX, $value, $exptime );
-
-               return true;
+               return $value;
        }
 
        public function delete( $key ) {
diff --git a/includes/libs/objectcache/APCUBagOStuff.php b/includes/libs/objectcache/APCUBagOStuff.php
new file mode 100644 (file)
index 0000000..02b3c92
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Object caching using PHP's APCU accelerator.
+ *
+ * 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 Cache
+ */
+
+/**
+ * This is a wrapper for APCU's shared memory functions
+ *
+ * @ingroup Cache
+ */
+class APCUBagOStuff extends APCBagOStuff {
+       /**
+        * Constructor
+        *
+        * Available parameters are:
+        *   - nativeSerialize:     If true, pass objects to apcu_store(), and trust it
+        *                          to serialize them correctly. If false, serialize
+        *                          all values in PHP.
+        *
+        * @param array $params
+        */
+       public function __construct( array $params = [] ) {
+               parent::__construct( $params );
+       }
+
+       protected function doGet( $key, $flags = 0 ) {
+               return $this->getUnserialize(
+                       apcu_fetch( $key . self::KEY_SUFFIX )
+               );
+       }
+
+       public function set( $key, $value, $exptime = 0, $flags = 0 ) {
+               apcu_store(
+                       $key . self::KEY_SUFFIX,
+                       $this->setSerialize( $value ),
+                       $exptime
+               );
+
+               return true;
+       }
+
+       public function delete( $key ) {
+               apcu_delete( $key . self::KEY_SUFFIX );
+
+               return true;
+       }
+
+       public function incr( $key, $value = 1 ) {
+               /**
+                * @todo When we only support php 7 or higher remove this hack
+                *
+                * https://github.com/krakjoe/apcu/issues/166
+                */
+               if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
+                       return apcu_inc( $key . self::KEY_SUFFIX, $value );
+               } else {
+                       return apcu_set( $key . self::KEY_SUFFIX, $value );
+               }
+       }
+
+       public function decr( $key, $value = 1 ) {
+               /**
+                * @todo When we only support php 7 or higher remove this hack
+                *
+                * https://github.com/krakjoe/apcu/issues/166
+                */
+               if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
+                       return apcu_dec( $key . self::KEY_SUFFIX, $value );
+               } else {
+                       return apcu_set( $key . self::KEY_SUFFIX, -$value );
+               }
+       }
+}
index cd79b67..d3deefb 100644 (file)
@@ -29,6 +29,7 @@
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
 use Psr\Log\NullLogger;
+use Wikimedia\WaitConditionLoop;
 
 /**
  * interface is intended to be more or less compatible with
index 1f9aff1..88af1db 100644 (file)
@@ -22,6 +22,7 @@
  */
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
+use Wikimedia\WaitConditionLoop;
 
 /**
  * Class for ensuring a consistent ordering of events as seen by the user, despite replication.
index 4f1f38e..16d30d7 100644 (file)
@@ -3037,10 +3037,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
        public function sourceFile(
                $filename,
-               $lineCallback = false,
-               $resultCallback = false,
+               callable $lineCallback = null,
+               callable $resultCallback = null,
                $fname = false,
-               $inputCallback = false
+               callable $inputCallback = null
        ) {
                MediaWiki\suppressWarnings();
                $fp = fopen( $filename, 'r' );
@@ -3073,10 +3073,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
        public function sourceStream(
                $fp,
-               $lineCallback = false,
-               $resultCallback = false,
+               callable $lineCallback = null,
+               callable $resultCallback = null,
                $fname = __METHOD__,
-               $inputCallback = false
+               callable $inputCallback = null
        ) {
                $cmd = '';
 
index f58628e..f82d76d 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  * @ingroup Database
  */
+use Wikimedia\WaitConditionLoop;
 
 /**
  * @ingroup Database
index f65e0dd..8395359 100644 (file)
@@ -96,21 +96,21 @@ interface IMaintainableDatabase extends IDatabase {
         * on object's error ignore settings).
         *
         * @param string $filename File name to open
-        * @param bool|callable $lineCallback Optional function called before reading each line
-        * @param bool|callable $resultCallback Optional function called for each MySQL result
+        * @param callable|null $lineCallback Optional function called before reading each line
+        * @param callable|null $resultCallback Optional function called for each MySQL result
         * @param bool|string $fname Calling function name or false if name should be
         *   generated dynamically using $filename
-        * @param bool|callable $inputCallback Optional function called for each
+        * @param callable|null $inputCallback Optional function called for each
         *   complete line sent
         * @return bool|string
         * @throws Exception
         */
        public function sourceFile(
                $filename,
-               $lineCallback = false,
-               $resultCallback = false,
+               callable $lineCallback = null,
+               callable $resultCallback = null,
                $fname = false,
-               $inputCallback = false
+               callable $inputCallback = null
        );
 
        /**
@@ -120,18 +120,18 @@ interface IMaintainableDatabase extends IDatabase {
         * on object's error ignore settings).
         *
         * @param resource $fp File handle
-        * @param bool|callable $lineCallback Optional function called before reading each query
-        * @param bool|callable $resultCallback Optional function called for each MySQL result
+        * @param callable|null $lineCallback Optional function called before reading each query
+        * @param callable|null $resultCallback Optional function called for each MySQL result
         * @param string $fname Calling function name
-        * @param bool|callable $inputCallback Optional function called for each complete query sent
+        * @param callable|null $inputCallback Optional function called for each complete query sent
         * @return bool|string
         */
        public function sourceStream(
                $fp,
-               $lineCallback = false,
-               $resultCallback = false,
+               callable $lineCallback = null,
+               callable $resultCallback = null,
                $fname = __METHOD__,
-               $inputCallback = false
+               callable $inputCallback = null
        );
 
        /**
index 2fb8c4b..bee32dc 100644 (file)
@@ -309,7 +309,7 @@ class LBFactoryMulti extends LBFactory {
                        $this->baseLoadBalancerParams(),
                        [
                                'servers' => $this->makeServerArray( $template, $loads, $groupLoads ),
-                               'loadMonitor' => $this->loadMonitorClass,
+                               'loadMonitor' => [ 'class' => $this->loadMonitorClass ],
                                'readOnlyReason' => $readOnlyReason
                        ]
                ) );
index 610052f..674bafd 100644 (file)
@@ -67,7 +67,7 @@ class LBFactorySimple extends LBFactory {
                        : [];
                $this->loadMonitorClass = isset( $conf['loadMonitorClass'] )
                        ? $conf['loadMonitorClass']
-                       : null;
+                       : 'LoadMonitor';
        }
 
        /**
@@ -124,7 +124,7 @@ class LBFactorySimple extends LBFactory {
                        $this->baseLoadBalancerParams(),
                        [
                                'servers' => $servers,
-                               'loadMonitor' => $this->loadMonitorClass,
+                               'loadMonitor' => [ 'class' => $this->loadMonitorClass ],
                        ]
                ) );
                $this->initLoadBalancer( $lb );
index 37c028b..31c022c 100644 (file)
@@ -32,7 +32,7 @@ class LoadBalancer implements ILoadBalancer {
        private $mServers;
        /** @var array[] Map of (local/foreignUsed/foreignFree => server index => IDatabase array) */
        private $mConns;
-       /** @var array Map of (server index => weight) */
+       /** @var float[] Map of (server index => weight) */
        private $mLoads;
        /** @var array[] Map of (group => server index => weight) */
        private $mGroupLoads;
@@ -40,13 +40,13 @@ class LoadBalancer implements ILoadBalancer {
        private $mAllowLagged;
        /** @var integer Seconds to spend waiting on replica DB lag to resolve */
        private $mWaitTimeout;
-       /** @var string The LoadMonitor subclass name */
-       private $mLoadMonitorClass;
+       /** @var array The LoadMonitor configuration */
+       private $loadMonitorConfig;
        /** @var array[] $aliases Map of (table => (dbname, schema, prefix) map) */
        private $tableAliases = [];
 
        /** @var ILoadMonitor */
-       private $mLoadMonitor;
+       private $loadMonitor;
        /** @var BagOStuff */
        private $srvCache;
        /** @var BagOStuff */
@@ -150,14 +150,9 @@ class LoadBalancer implements ILoadBalancer {
                }
 
                if ( isset( $params['loadMonitor'] ) ) {
-                       $this->mLoadMonitorClass = $params['loadMonitor'];
+                       $this->loadMonitorConfig = $params['loadMonitor'];
                } else {
-                       $master = reset( $params['servers'] );
-                       if ( isset( $master['type'] ) && $master['type'] === 'mysql' ) {
-                               $this->mLoadMonitorClass = 'LoadMonitorMySQL';
-                       } else {
-                               $this->mLoadMonitorClass = 'LoadMonitorNull';
-                       }
+                       $this->loadMonitorConfig = [ 'class' => 'LoadMonitorNull' ];
                }
 
                foreach ( $params['servers'] as $i => $server ) {
@@ -217,13 +212,14 @@ class LoadBalancer implements ILoadBalancer {
         * @return ILoadMonitor
         */
        private function getLoadMonitor() {
-               if ( !isset( $this->mLoadMonitor ) ) {
-                       $class = $this->mLoadMonitorClass;
-                       $this->mLoadMonitor = new $class( $this, $this->srvCache, $this->memCache );
-                       $this->mLoadMonitor->setLogger( $this->replLogger );
+               if ( !isset( $this->loadMonitor ) ) {
+                       $class = $this->loadMonitorConfig['class'];
+                       $this->loadMonitor = new $class(
+                               $this, $this->srvCache, $this->memCache, $this->loadMonitorConfig );
+                       $this->loadMonitor->setLogger( $this->replLogger );
                }
 
-               return $this->mLoadMonitor;
+               return $this->loadMonitor;
        }
 
        /**
index e355c03..72a8785 100644 (file)
@@ -34,16 +34,19 @@ interface ILoadMonitor extends LoggerAwareInterface {
         * @param ILoadBalancer $lb LoadBalancer this instance serves
         * @param BagOStuff $sCache Local server memory cache
         * @param BagOStuff $cCache Local cluster memory cache
+        * @param array $options Options map
         */
-       public function __construct( ILoadBalancer $lb, BagOStuff $sCache, BagOStuff $cCache );
+       public function __construct(
+               ILoadBalancer $lb, BagOStuff $sCache, BagOStuff $cCache, array $options = []
+       );
 
        /**
         * Perform pre-connection load ratio adjustment.
-        * @param int[] &$loads
+        * @param int[] &$weightByServer Map of (server index => integer weight)
         * @param string|bool $group The selected query group. Default: false
         * @param string|bool $domain Default: false
         */
-       public function scaleLoads( &$loads, $group = false, $domain = false );
+       public function scaleLoads( array &$weightByServer, $group = false, $domain = false );
 
        /**
         * Get an estimate of replication lag (in seconds) for each server
@@ -55,7 +58,7 @@ interface ILoadMonitor extends LoggerAwareInterface {
         *
         * @return array Map of (server index => float|int|bool)
         */
-       public function getLagTimes( $serverIndexes, $domain );
+       public function getLagTimes( array $serverIndexes, $domain );
 
        /**
         * Clear any process and persistent cache of lag times
index 1da8f4e..dddc7b0 100644 (file)
@@ -37,27 +37,50 @@ class LoadMonitor implements ILoadMonitor {
        /** @var LoggerInterface */
        protected $replLogger;
 
-       public function __construct( ILoadBalancer $lb, BagOStuff $srvCache, BagOStuff $cache ) {
+       /** @var float Moving average ratio (e.g. 0.1 for 10% weight to new weight) */
+       private $movingAveRatio;
+
+       public function __construct(
+               ILoadBalancer $lb, BagOStuff $srvCache, BagOStuff $cache, array $options = []
+       ) {
                $this->parent = $lb;
                $this->srvCache = $srvCache;
                $this->mainCache = $cache;
                $this->replLogger = new \Psr\Log\NullLogger();
+
+               $this->movingAveRatio = isset( $options['movingAveRatio'] )
+                       ? $options['movingAveRatio']
+                       : 0.1;
        }
 
        public function setLogger( LoggerInterface $logger ) {
                $this->replLogger = $logger;
        }
 
-       public function scaleLoads( &$loads, $group = false, $domain = false ) {
+       public function scaleLoads( array &$weightByServer, $group = false, $domain = false ) {
+               $states = $this->getServerStates( $weightByServer, $domain );
+               $coefficientsByServer = $states['weightScales'];
+               foreach ( $weightByServer as $i => $weight ) {
+                       $weightByServer[$i] = $weight * $coefficientsByServer[$i];
+               }
+       }
+
+       public function getLagTimes( array $serverIndexes, $domain ) {
+               $states = $this->getServerStates( $serverIndexes, $domain );
+
+               return $states['lagTimes'];
        }
 
-       public function getLagTimes( $serverIndexes, $domain ) {
+       protected function getServerStates( array $serverIndexes, $domain ) {
                if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
                        # Single server only, just return zero without caching
-                       return [ 0 => 0 ];
+                       return [
+                               'lagTimes' => [ $this->parent->getWriterIndex() => 0 ],
+                               'weightScales' => [ $this->parent->getWriterIndex() => 1 ]
+                       ];
                }
 
-               $key = $this->getLagTimeCacheKey();
+               $key = $this->getCacheKey();
                # Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
                $ttl = mt_rand( 4e6, 5e6 ) / 1e6;
                # Keep keys around longer as fallbacks
@@ -67,7 +90,7 @@ class LoadMonitor implements ILoadMonitor {
                $value = $this->srvCache->get( $key );
                if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
                        $this->replLogger->debug( __METHOD__ . ": got lag times ($key) from local cache" );
-                       return $value['lagTimes']; // cache hit
+                       return $value; // cache hit
                }
                $staleValue = $value ?: false;
 
@@ -77,7 +100,7 @@ class LoadMonitor implements ILoadMonitor {
                        $this->srvCache->set( $key, $value, $staleTTL );
                        $this->replLogger->debug( __METHOD__ . ": got lag times ($key) from main cache" );
 
-                       return $value['lagTimes']; // cache hit
+                       return $value; // cache hit
                }
                $staleValue = $value ?: $staleValue;
 
@@ -91,13 +114,16 @@ class LoadMonitor implements ILoadMonitor {
                        } );
                } elseif ( $staleValue ) {
                        # Could not acquire lock but an old cache exists, so use it
-                       return $staleValue['lagTimes'];
+                       return $staleValue;
                }
 
                $lagTimes = [];
+               $weightScales = [];
+               $movAveRatio = $this->movingAveRatio;
                foreach ( $serverIndexes as $i ) {
                        if ( $i == $this->parent->getWriterIndex() ) {
                                $lagTimes[$i] = 0; // master always has no lag
+                               $weightScales[$i] = 1.0; // nominal weight
                                continue;
                        }
 
@@ -109,17 +135,26 @@ class LoadMonitor implements ILoadMonitor {
                                $close = true; // new connection
                        }
 
+                       $lastWeight = isset( $staleValue['weightScales'][$i] )
+                               ? $staleValue['weightScales'][$i]
+                               : 1.0;
+                       $coefficient = $this->getWeightScale( $i, $conn ?: null );
+                       $newWeight = $movAveRatio * $coefficient + ( 1 - $movAveRatio ) * $lastWeight;
+
+                       // Scale from 10% to 100% of nominal weight
+                       $weightScales[$i] = max( $newWeight, .10 );
+
                        if ( !$conn ) {
                                $lagTimes[$i] = false;
                                $host = $this->parent->getServerName( $i );
-                               $this->replLogger->error( __METHOD__ . ": host $host (#$i) is unreachable" );
+                               $this->replLogger->error( __METHOD__ . ": host $host is unreachable" );
                                continue;
                        }
 
                        $lagTimes[$i] = $conn->getLag();
                        if ( $lagTimes[$i] === false ) {
                                $host = $this->parent->getServerName( $i );
-                               $this->replLogger->error( __METHOD__ . ": host $host (#$i) is not replicating?" );
+                               $this->replLogger->error( __METHOD__ . ": host $host is not replicating?" );
                        }
 
                        if ( $close ) {
@@ -132,26 +167,38 @@ class LoadMonitor implements ILoadMonitor {
                }
 
                # Add a timestamp key so we know when it was cached
-               $value = [ 'lagTimes' => $lagTimes, 'timestamp' => microtime( true ) ];
+               $value = [
+                       'lagTimes' => $lagTimes,
+                       'weightScales' => $weightScales,
+                       'timestamp' => microtime( true )
+               ];
                $this->mainCache->set( $key, $value, $staleTTL );
                $this->srvCache->set( $key, $value, $staleTTL );
                $this->replLogger->info( __METHOD__ . ": re-calculated lag times ($key)" );
 
-               return $value['lagTimes'];
+               return $value;
+       }
+
+       /**
+        * @param integer $index Server index
+        * @param IDatabase|null $conn Connection handle or null on connection failure
+        * @return float
+        */
+       protected function getWeightScale( $index, IDatabase $conn = null ) {
+               return $conn ? 1.0 : 0.0;
        }
 
        public function clearCaches() {
-               $key = $this->getLagTimeCacheKey();
+               $key = $this->getCacheKey();
                $this->srvCache->delete( $key );
                $this->mainCache->delete( $key );
        }
 
-       private function getLagTimeCacheKey() {
-               $writerIndex = $this->parent->getWriterIndex();
+       private function getCacheKey() {
                // Lag is per-server, not per-DB, so key on the master DB name
                return $this->srvCache->makeGlobalKey(
                        'lag-times',
-                       $this->parent->getServerName( $writerIndex )
+                       $this->parent->getServerName( $this->parent->getWriterIndex() )
                );
        }
 }
index 7286417..babd609 100644 (file)
  * @ingroup Database
  */
 class LoadMonitorMySQL extends LoadMonitor {
-       public function scaleLoads( &$loads, $group = false, $domain = false ) {
-               // @TODO: maybe use Threads_running/Threads_created ratio to guess load
-               // and Queries/Uptime to guess if a server is warming up the buffer pool
+       /** @var float What buffer pool use ratio counts as "warm" (e.g. 0.5 for 50% usage) */
+       private $warmCacheRatio;
+
+       public function __construct(
+               ILoadBalancer $lb, BagOStuff $srvCache, BagOStuff $cache, array $options = []
+       ) {
+               parent::__construct( $lb, $srvCache, $cache, $options );
+
+               $this->warmCacheRatio = isset( $options['warmCacheRatio'] )
+                       ? $options['warmCacheRatio']
+                       : 0.0;
+       }
+
+       protected function getWeightScale( $index, IDatabase $conn = null ) {
+               if ( !$conn ) {
+                       return 0.0;
+               }
+
+               $weight = 1.0;
+               if ( $this->warmCacheRatio > 0 ) {
+                       $res = $conn->query( 'SHOW STATUS', false );
+                       $s = $res ? $conn->fetchObject( $res ) : false;
+                       if ( $s === false ) {
+                               $host = $this->parent->getServerName( $index );
+                               $this->replLogger->error( __METHOD__ . ": could not get status for $host" );
+                       } else {
+                               // http://dev.mysql.com/doc/refman/5.7/en/server-status-variables.html
+                               if ( $s->Innodb_buffer_pool_pages_total > 0 ) {
+                                       $ratio = $s->Innodb_buffer_pool_pages_data / $s->Innodb_buffer_pool_pages_total;
+                               } elseif ( $s->Qcache_total_blocks > 0 ) {
+                                       $ratio = 1.0 - $s->Qcache_free_blocks / $s->Qcache_total_blocks;
+                               } else {
+                                       $ratio = 1.0;
+                               }
+                               // Stop caring once $ratio >= $this->warmCacheRatio
+                               $weight *= min( $ratio / $this->warmCacheRatio, 1.0 );
+                       }
+               }
+
+               return $weight;
        }
 }
index 8062001..67bac2b 100644 (file)
 use Psr\Log\LoggerInterface;
 
 class LoadMonitorNull implements ILoadMonitor {
-       public function __construct( ILoadBalancer $lb, BagOStuff $sCache, BagOStuff $cCache ) {
+       public function __construct(
+               ILoadBalancer $lb, BagOStuff $sCache, BagOStuff $cCache, array $options = []
+       ) {
 
        }
 
        public function setLogger( LoggerInterface $logger ) {
        }
 
-       public function scaleLoads( &$loads, $group = false, $domain = false ) {
+       public function scaleLoads( array &$loads, $group = false, $domain = false ) {
 
        }
 
-       public function getLagTimes( $serverIndexes, $domain ) {
+       public function getLagTimes( array $serverIndexes, $domain ) {
                return array_fill_keys( $serverIndexes, 0 );
        }
 
index d81f9e1..87a6272 100644 (file)
@@ -50,7 +50,7 @@ use MediaWiki\MediaWikiServices;
  *
  * - ObjectCache::getLocalServerInstance( $fallbackType )
  *   Purpose: Memory cache for very hot keys.
- *   Stored only on the individual web server (typically APC for web requests,
+ *   Stored only on the individual web server (typically APC or APCu for web requests,
  *   and EmptyBagOStuff in CLI mode).
  *   Not replicated to the other servers.
  *
@@ -265,7 +265,7 @@ class ObjectCache {
        /**
         * Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
         *
-        * This will look for any APC style server-local cache.
+        * This will look for any APC or APCu style server-local cache.
         * A fallback cache can be specified if none is found.
         *
         *     // Direct calls
@@ -282,6 +282,8 @@ class ObjectCache {
        public static function getLocalServerInstance( $fallback = CACHE_NONE ) {
                if ( function_exists( 'apc_fetch' ) ) {
                        $id = 'apc';
+               } elseif ( function_exists( 'apcu_fetch' ) ) {
+                       $id = 'apcu';
                } elseif ( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) {
                        $id = 'xcache';
                } elseif ( function_exists( 'wincache_ucache_get' ) ) {
index 928fc14..4fa042e 100644 (file)
@@ -693,7 +693,7 @@ class WikiPage implements Page, IDBAccessObject {
         * @deprecated since 1.21, getContent() should be used instead.
         */
        public function getText( $audience = Revision::FOR_PUBLIC, User $user = null ) {
-               ContentHandler::deprecated( __METHOD__, '1.21' );
+               wfDeprecated( __METHOD__, '1.21' );
 
                $this->loadLastEdit();
                if ( $this->mLastRevision ) {
index 297dcb2..db9c95b 100644 (file)
@@ -162,9 +162,9 @@ abstract class Profiler {
        abstract public function scopedProfileIn( $section );
 
        /**
-        * @param ScopedCallback $section
+        * @param SectionProfileCallback $section
         */
-       public function scopedProfileOut( ScopedCallback &$section = null ) {
+       public function scopedProfileOut( SectionProfileCallback &$section = null ) {
                $section = null;
        }
 
index bbe139b..7e3c398 100644 (file)
@@ -58,7 +58,7 @@ class SectionProfiler {
 
        /**
         * @param string $section
-        * @return ScopedCallback
+        * @return SectionProfileCallback
         */
        public function scopedProfileIn( $section ) {
                $this->profileInInternal( $section );
index ed7c6df..3efbd3b 100644 (file)
@@ -180,6 +180,7 @@ class SkinTemplate extends Skin {
                                        'text' => $ilLangName,
                                        'title' => $ilTitle,
                                        'class' => $class,
+                                       'link-class' => 'interlanguage-link-target',
                                        'lang' => $ilInterwikiCodeBCP47,
                                        'hreflang' => $ilInterwikiCodeBCP47,
                                ];
old mode 100644 (file)
new mode 100755 (executable)
index 718a6dc..d719e53
@@ -376,7 +376,11 @@ class SpecialNewpages extends IncludableSpecialPage {
 
                if ( !$title->equals( $oldTitle ) ) {
                        $oldTitleText = $oldTitle->getPrefixedText();
-                       $oldTitleText = $this->msg( 'rc-old-title' )->params( $oldTitleText )->escaped();
+                       $oldTitleText = Html::rawElement(
+                               'span',
+                               [ 'class' => 'mw-newpages-oldtitle' ],
+                               $this->msg( 'rc-old-title' )->params( $oldTitleText )->escaped()
+                       );
                }
 
                return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} "
index de6f5ab..9398216 100644 (file)
@@ -67,7 +67,8 @@
                        "Hhaboh162002",
                        "بدارين",
                        "باسم",
-                       "Moud hosny"
+                       "Moud hosny",
+                       "ديفيد"
                ]
        },
        "tog-underline": "سطر تحت الوصلات:",
        "revdelete-failure": "'''تعذر تحديث رؤية المراجعة:'''\n$1",
        "logdelete-success": "تم ضبط رؤية السجلات بنجاح.",
        "logdelete-failure": "'''تعذر ضبط رؤية السجل:'''\n$1",
-       "revdel-restore": "تغÙ\8aÙ\8aر Ø§Ù\84رؤÙ\8aØ©",
+       "revdel-restore": "رؤÙ\8aØ© Ø§Ù\84تغÙ\8aÙ\8aر",
        "pagehist": "تاريخ الصفحة",
        "deletedhist": "التاريخ المحذوف",
        "revdelete-hide-current": "خطأ عند إخفاء العنصر المؤرخ في $2 $1: هذه هي المراجعة الحالية.\nلا يمكن إخفاؤها.",
        "allmessagesname": "الاسم",
        "allmessagesdefault": "النص الافتراضي",
        "allmessagescurrent": "النص الحالي",
-       "allmessagestext": "Ù\87Ø°Ù\87 Ù\82ائÙ\85Ø© Ø¨Ø±Ø³Ø§Ø¦Ù\84 Ø§Ù\84Ù\86ظاÙ\85 Ø§Ù\84Ù\85تÙ\88Ù\81رة Ù\81Ù\8a Ù\86طاÙ\82 Ù\85Ù\8aدÙ\8aاÙ\88Ù\8aÙ\83Ù\8a.\nÙ\8aرجÙ\89 Ø²Ù\8aارة :\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] Ù\88 [https://translatewiki.net translatewiki.net]\nإازا Ù\83Ù\86ت ØªØ±ØºØ¨ Ù\81Ù\8a Ø§Ù\84Ù\85ساÙ\87Ù\85Ø© Ø¨ØªØ¹Ø±Ù\8aب Ù\85Ù\8aدÙ\8aا Ù\88Ù\8aÙ\83Ù\8a",
+       "allmessagestext": "Ù\87Ø°Ù\87 Ù\82ائÙ\85Ø© Ø¨Ø±Ø³Ø§Ø¦Ù\84 Ø§Ù\84Ù\86ظاÙ\85 Ø§Ù\84Ù\85تÙ\88Ù\81رة Ù\81Ù\8a Ù\86طاÙ\82 Ù\85Ù\8aدÙ\8aاÙ\88Ù\8aÙ\83Ù\8a.\nÙ\85Ù\86 Ù\81ضÙ\84Ù\83 Ø²Ø± [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation ØªØ±Ø¬Ù\85Ø© Ù\85Ù\8aدÙ\8aاÙ\88Ù\8aÙ\83Ù\8a] Ù\88 [https://translatewiki.net ØªØ±Ø§Ù\86سÙ\84Ù\8aت Ù\88Ù\8aÙ\83Ù\8a Ø¯Ù\88ت Ù\86ت] Ù\84Ù\88 Ù\83Ù\86ت ØªØ±ØºØ¨ Ù\81Ù\8a Ø§Ù\84Ù\85ساÙ\87Ù\85Ø© Ù\81Ù\8a ØªØ±Ø¬Ù\85Ø© Ù\85Ù\8aدÙ\8aاÙ\88Ù\8aÙ\83Ù\8a Ø§Ù\84أساسÙ\8aØ©.",
        "allmessagesnotsupportedDB": "هذه الصفحة لا يمكن استخدامها لأن '''$wgUseDatabaseMessages''' تم تعطيله.",
        "allmessages-filter-legend": "المرشح",
        "allmessages-filter": "رشح حسب حالة التخصيص:",
index f2413c7..22642ba 100644 (file)
        "previewerrortext": "Адбылася памылка пры спробе папярэдняга прагляду вашых зьменаў.",
        "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}}|адміністратараў]], каб абмеркаваць блякаваньне. Заўважце, што Вы ня зможаце ўжыць магчымасьць «даслаць ліст па электроннай пошце», пакуль не пазначыце сапраўдны адрас электроннай пошты ў Вашых [[Special:Preferences|наладах]], і калі гэта Вам не было забаронена.\nВаш IP-адрас — $3, ідэнтыфікатар блякаваньня — #$5.\nКалі ласка, улучайце ўсю вышэйпададзеную інфармацыю ва ўсе запыты, што Вы будзеце рабіць.",
-       "autoblockedtext": "Ваш IP-адрас быў аўтаматычна заблякаваны, таму што ён ужываўся іншым удзельнікам, які быў заблякаваны $1.\nПрычына гэтага:\n\n:''$2''\n\n* Блякаваньне пачалося: $8\n* Блякаваньне скончыцца: $6\n* Быў заблякаваны: $7\n\nВы можаце скантактавацца з $1 ці з адным зь іншых [[{{MediaWiki:Grouppage-sysop}}|адміністратараў]], каб абмеркаваць блякаваньне.\n\nЗаўважце, што Вы ня зможаце ужываць магчымасьць «даслаць ліст праз электронную пошту», пакуль ня будзе пазначаны дзейны адрас электроннай пошты ў Вашых [[Special:Preferences|наладах удзельніка]], і калі гэта Вам не было забаронена.\n\nВаш цяперашні IP-адрас — $3, ідэнтыфікатар блякаваньня — #$5.\nКалі ласка, улучайце ўсю вышэйпададзеную інфармацыю ва ўсе запыты, што Вы будзеце рабіць.",
+       "autoblockedtext": "Ваш IP-адрас быў аўтаматычна заблякаваны, таму што ён ужываўся іншым удзельнікам, які быў заблякаваны $1.\nПрычына гэтага:\n\n:<em>$2</em>\n\n* Блякаваньне пачалося: $8\n* Блякаваньне скончыцца: $6\n* Быў заблякаваны: $7\n\nВы можаце скантактавацца з $1 ці з адным зь іншых [[{{MediaWiki:Grouppage-sysop}}|адміністратараў]], каб абмеркаваць блякаваньне.\n\nЗаўважце, што Вы ня зможаце ўжываць магчымасьць «даслаць ліст праз электронную пошту», пакуль ня будзе пазначаны дзейны адрас электроннай пошты ў Вашых [[Special:Preferences|наладах удзельніка]], і калі гэта Вам не было забаронена.\n\nВаш цяперашні IP-адрас — $3, ідэнтыфікатар блякаваньня — #$5.\nКалі ласка, улучайце ўсю вышэйпададзеную інфармацыю ва ўсе запыты, што Вы будзеце рабіць.",
        "blockednoreason": "прычына не пазначана",
        "whitelistedittext": "Вам трэба $1, каб рэдагаваць старонкі.",
        "confirmedittext": "Вы мусіце пацьвердзіць Ваш адрас электроннай пошты перад рэдагаваньнем старонак. Калі ласка, пазначце і пацьвердзіце адрас электроннай пошты праз Вашы [[Special:Preferences|налады]].",
        "htmlform-datetime-placeholder": "ГГГГ-ММ-ДД ГГ:ХХ:СС",
        "htmlform-date-invalid": "Уведзенае вамі значэньне не зьяўляецца датай. Паспрабуйце ўжыць фармат ГГГГ-ММ-ДД.",
        "htmlform-time-invalid": "Уведзенае вамі значэньне не зьяўляецца часам. Паспрабуйце ўжыць фармат ГГ:ХХ:СС.",
+       "htmlform-datetime-invalid": "Уведзенае вамі значэньне не зьяўляецца датай і часам. Паспрабуйце ўжыць фармат ГГГГ-ММ-ДД ГГ:ХХ:СС.",
+       "htmlform-date-toolow": "Уведзенае вамі значэньне меней за самую раньнюю дазволеную дату $1.",
        "htmlform-title-badnamespace": "[[:$1]] знаходзіцца не ў прасторы назваў «{{ns:$2}}».",
        "htmlform-title-not-creatable": "«$1» — немагчымы загаловак для старонкі",
        "htmlform-title-not-exists": "$1 не існуе.",
index 50e9cb4..45f4fd8 100644 (file)
        "passwordreset-emailelement": "ব্যবহারকারী নাম: \n$1\n\nঅস্থায়ী পাসওয়ার্ড: \n$2",
        "passwordreset-emailsentemail": "যদি এই ই-মেইল ঠিকানা আপনার অ্যাকাউন্টের সাথে সংযুক্ত করা থাকে, তাহলে একটি পাসওয়ার্ড বদলের ইমেইল পাঠানো হবে।",
        "passwordreset-emailsentusername": "যদি এই ব্যবহারকারী নামের সাথে ই-মেইল ঠিকানা সংযুক্ত করা থাকে, তাহলে একটি পাসওয়ার্ড বদলের ইমেইল পাঠানো হবে।",
-       "passwordreset-emailsent-capture2": "পাসওয়ার্ড পুনঃধার্যকরণের {{PLURAL:$1|email has|ইমেইল পাঠানো}} হয়েছে। {{PLURAL:$1|username and password|ব্যবহারকারীনাম ও পাসওয়ার্ড তালিকা}} এখানে দেখা যাবে।",
-       "passwordreset-emailerror-capture2": "{{GENDER:$2|ব্যবহারকারীকে}} ইমেইল পাঠানো যায়নি: $1 {{PLURAL:$3|username and password|ব্যবহারকারীনাম ও পাসওয়ার্ড তালিকা}} এখানে দেখা যাবে।",
+       "passwordreset-emailsent-capture2": "পাসওয়ার্ড পুনঃধার্যকরণের {{PLURAL:$1|ইমেইল পাঠানো}} হয়েছে। {{PLURAL:$1|ব্যবহারকারী নাম ও পাসওয়ার্ড|ব্যবহারকারী নাম ও পাসওয়ার্ডের তালিকা}} এখানে দেখা যাবে।",
+       "passwordreset-emailerror-capture2": "{{GENDER:$2|ব্যবহারকারীকে}} ইমেইল পাঠানো যায়নি: $1 {{PLURAL:$3|ব্যবহারকারী নাম ও পাসওয়ার্ড|ব্যবহারকারী নাম ও পাসওয়ার্ডের তালিকা}} এখানে দেখা যাবে।",
        "passwordreset-nocaller": "একটি আহ্বানকারী প্রদান করা আবশ্যক",
        "passwordreset-nosuchcaller": "আহ্বানকারীর অস্তিত্ব নেই: $1",
        "passwordreset-ignored": "পাসওয়ার্ড পুনঃধার্যকরণ করা যায়নি। হয়তো কোন প্রদানকারী কনফিগার করা হয়েনি?",
index c2b1d88..b02d00d 100644 (file)
@@ -51,7 +51,7 @@
        "tog-enotifminoredits": "Također mi pošalji e-poštu za male izmjene na stranicama i datotekama",
        "tog-enotifrevealaddr": "Otkrij adresu moje e-pošte u porukama obavještenja",
        "tog-shownumberswatching": "Prikaži broj korisnika koji prate",
-       "tog-oldsig": "Postojeći potpis:",
+       "tog-oldsig": "Vaš postojeći potpis:",
        "tog-fancysig": "Smatraj potpis kao wikitekst (bez automatskog linka)",
        "tog-uselivepreview": "Koristi pregled uživo",
        "tog-forceeditsummary": "Opomeni me pri unosu praznog sažetka",
@@ -68,7 +68,7 @@
        "tog-showhiddencats": "Prikaži skrivene kategorije",
        "tog-norollbackdiff": "Ne prikazuj razliku nakon izvršenog vraćanja",
        "tog-useeditwarning": "Upozori me kad napuštam stranicu za izmjene bez sačuvanih promjena",
-       "tog-prefershttps": "Uvijek koristi sigurnu konekciju kada sam prijavljen.",
+       "tog-prefershttps": "Uvijek koristi sigurnu vezu dok sam prijavljen",
        "underline-always": "Uvijek",
        "underline-never": "Nikad",
        "underline-default": "Prema predodređenim postavkama teme ili preglednika",
        "october-date": "$1. oktobar",
        "november-date": "$1. novembar",
        "december-date": "$1. decembar",
+       "period-am": "AM",
+       "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1|Kategorija|Kategorije}}",
        "category_header": "Članci u kategoriji \"$1\"",
        "subcategories": "Podkategorije",
        "newwindow": "(otvara se u novom prozoru)",
        "cancel": "Odustani",
        "moredotdotdot": "Više...",
-       "morenotlisted": "Ovaj spisak nije potpun.",
+       "morenotlisted": "Ovaj spisak možda nije potpun.",
        "mypage": "Stranica",
        "mytalk": "Razgovor",
        "anontalk": "Razgovor",
        "talk": "Razgovor",
        "views": "Pregledi",
        "toolbox": "Alati",
+       "tool-link-userrights": "Promijeni {{GENDER:$1|korisničke}} grupe",
+       "tool-link-emailuser": "Pošalji e-poruku {{GENDER:$1|korisniku|korisnici}}",
        "userpage": "Pogledaj korisničku stranicu",
        "projectpage": "Pogledaj stranicu projekta",
        "imagepage": "Pogledajte stranicu datoteke",
        "confirmable-confirm": "Da li {{GENDER:$1|ste}} sigurni?",
        "confirmable-yes": "Da",
        "confirmable-no": "Ne",
-       "thisisdeleted": "Pogledati ili vratiti $1?",
+       "thisisdeleted": "Pogledaj ili vrati $1?",
        "viewdeleted": "Pogledaj $1?",
-       "restorelink": "{{PLURAL:$1|$1 izbrisana izmjena|$1 izbrisanih izmjena}}",
+       "restorelink": "{{PLURAL:$1|jednu obrisanu izmjenu|$1 obrisane izmjene|$1 obrisanih izmjena}}",
        "feedlinks": "Fid:",
        "feed-invalid": "Nedozvoljen tip potpisa",
        "feed-unavailable": "RSS izvori nisu dostupni",
        "laggedslavemode": "'''Upozorenje''': Stranica, možda, nije ažurirana.",
        "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",
+       "readonlytext": "Baza podataka trenutno je zaključana za nove unose i druge izmjene, vjerovatno zbog rutinskog održavanja, nakon čega će biti vraćena u uobičajeno stanje.\n\nSistemski administrator koji ju je zaključao naveo je sljedeće objašnjenje: $1",
        "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)",
        "userlogin-resetpassword-link": "Zaboravili ste lozinku?",
        "userlogin-helplink2": "Pomoć pri prijavljivanju",
        "userlogin-loggedin": "Već ste prijavljeni kao {{GENDER:$1|$1}}.\nKoristite donji obrazac da biste se prijavili kao drugi korisnik.",
+       "userlogin-reauth": "Morate se ponovo prijaviti da bismo potvrdili da ste zaista {{GENDER:$1|$1}}.",
        "userlogin-createanother": "Napravi još jedan račun",
        "createacct-emailrequired": "Adresa e-pošte",
        "createacct-emailoptional": "Adresa e-pošte (opcionalno)",
        "noname": "Niste izabrali ispravno korisničko ime.",
        "loginsuccesstitle": "Prijavljen",
        "loginsuccess": "'''Sad ste prijavljeni na {{SITENAME}} kao \"$1\".'''",
-       "nosuchuser": "Ne postoji korisnik s imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite Vaš unos ili [[Special:CreateAccount|napravite novi korisnički račun]].",
+       "nosuchuser": "Ne postoji korisnik s imenom \"$1\".\nKorisnička imena razlikuju velika i mala slova.\nProvjerite jeste li ga tačno upisali ili [[Special:CreateAccount|otvorite novi 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.",
        "wrongpasswordempty": "Lozinka koju ste unijeli je bila prazna.\nMolimo Vas da pokušate ponovno.",
        "passwordtooshort": "Lozinka mora imati najmanje {{PLURAL:$1|1 znak|$1 znaka|$1 znakova}}.",
        "passwordtoolong": "Lozinke ne mogu biti duže od {{PLURAL:$1|jednog znaka|$1 znaka|$1 znakova}}.",
+       "passwordtoopopular": "Ovo je često korištena lozinka i ne može se koristiti. Molimo Vas da izaberete jaču lozinku.",
        "password-name-match": "Vaša lozinka mora biti različita od Vašeg korisničkog imena.",
        "password-login-forbidden": "Korištenje ovih korisničkih imena i šifara je zabranjeo.",
        "mailmypassword": "Poništi lozinku",
        "noemail": "Ne postoji adresa e-pošte za korisnika \"$1\".",
        "noemailcreate": "Morate da navedete validnu e-mail adresu",
        "passwordsent": "Nova lozinka poslana je na adresu e-pošte korisnika \"$1\".\nMolimo Vas da se prijavite nakon što je primite.",
-       "blocked-mailpassword": "Da bi se spriječila nedozvoljena akcija, Vašoj IP adresi je onemogućeno uređivanje stranica kao i mogućnost zahtijevanje nove lozinke.",
+       "blocked-mailpassword": "Vašoj IP-adresi onemogućeno je uređivanje. Da bi se spriječila zloupotreba, s nje nije moguće zahtijevati novu lozinku.",
        "eauthentsent": "Na navedenu adresu e-pošte poslana je poruka s potvrdom.\nPrije nego što pošaljemo daljnje poruke, pratite uputstva s e-pošte da biste potvrdili da je račun zaista Vaš.",
        "throttled-mailpassword": "Već Vam je poslana e-poruka za promjenu lozinke u {{PLURAL:$1|posljednjih sat vremena|posljednja $1 sata|posljednjih $1 sati}}.\nDa bi se spriječila zloupotreba, može se poslati samo jedna e-poruka za promjenu lozinke {{PLURAL:$1|svakih sat vremena|svaka $1 sata|svakih $1 sati}}.",
        "mailerror": "Greška pri slanju e-pošte: $1",
        "passwordreset-emailtext-ip": "Neko (vjerovatno Vi, s IP adrese $1) je zatražio podsjetnik Vaših detalja računa za {{SITENAME}} ($4). Sljedeći {{PLURAL:$3|račun korisnika je|računi korisnika su}} povezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena šifra|Ove privremene šifre}} će isteći za {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu šifru. Ako je neko drugi napravio ovaj zahtjev, ili ako ste se sjetili Vaše početne šifre, a ne želite je promijeniti, možete zanemariti ovu poruku i nastaviti koristiti staru šifru.",
        "passwordreset-emailtext-user": "Korisnik $1 na {{SITENAME}} je zatražio podsjetnik o detaljima Vašeg računa za {{SITENAME}} ($4). Sljedeći {{PLURAL:$3|korisnički račun je|korisnički računi su}} povezani s ovom e-mail adresom:\n\n$2\n\n{{PLURAL:$3|Ova privremena šifra|Ove privremene šifre}} će isteći za {{PLURAL:$5|jedan dan|$5 dana}}.\nTrebate se prijaviti i odabrati novu šifru. Ako je neko drugi napravio ovaj zahtjev, ili ako ste se sjetili Vaše originalne šifre, a ne želite je više promijeniti, možete zanemariti ovu poruku i nastaviti koristiti staru šifru.",
        "passwordreset-emailelement": "Korisničko ime: \n$1\n\nPrivremena šifra: \n$2",
-       "passwordreset-emailsentemail": "Ako je ovo adresa e-pošte s kojom ste registrirali ovaj račun, podsjetnik šifre će vam biti poslan na vašu adresu e-pošte.",
+       "passwordreset-emailsentemail": "Ako je ova adresa e-pošte povezana s Vašim računom, podsjetnik o lozinci bit će Vam poslan na adresu e-pošte.",
        "changeemail": "Promjena ili uklanjanje e-adrese",
        "changeemail-header": "Ispunite sljedeći formular da biste promijenili adresu e-pošte. Ako želite ukloniti postojeću adresu e-pošte s vašeg korisničkog računa, pri ispunjavanju formulara, polje nove adrese e-pošte ostavite prazno.",
        "changeemail-no-info": "Morate biti prijavljeni za direktan pristup ovoj stranici.",
        "accmailtext": "Nasumično odabrana šifra za [[User talk:$1|$1]] je poslata na adresu $2.\n\nŠifra/lozinka za ovaj novi račun može biti promijenjena na stranici ''[[Special:ChangePassword|izmjene šifre]]'' nakon prijave.",
        "newarticle": "(Novi)",
        "newarticletext": "Došli ste na stranicu koja još nema sadržaja.\n*Ako želite unijeti sadržaj, počnite tipkati u prozor ispod ovog teksta.\n*Ako Vam treba pomoć, idite na [$1 stranicu za pomoć].\n*Ako ste ovamo dospjeli slučajno, kliknite na dugme \"Nazad\" (''Back'') u Vašem internetskom pregledniku.",
-       "anontalkpagetext": "----''Ovo je stranica za razgovor za anonimnog korisnika koji još nije napravio nalog ili ga ne koristi.\nZbog toga moramo da koristimo brojčanu IP adresu kako bismo identifikovali njega ili nju.\nTakvu adresu može dijeliti više korisnika.\nAko ste anonimni korisnik i mislite da su vam upućene nebitne primjedbe, molimo Vas da [[Special:CreateAccount|napravite nalog]] ili se [[Special:UserLogin|prijavite]] da biste izbjegli buduću zabunu sa ostalim anonimnim korisnicima.''",
+       "anontalkpagetext": "----\n<em>Ovo je stranica za razgovor s anonimnim korisnikom koji još nije napravio račun ili ga ne koristi.</em>\nZbog toga moramo koristiti brojčanu IP-adresu kako bismo ga prepoznali.\nTakvu adresu može dijeliti više korisnika.\nAko ste anonimni korisnik i smatrate da su Vam upućene nebitne primjedbe, molimo Vas da [[Special:CreateAccount|napravite račun]] ili se [[Special:UserLogin|prijavite]] da biste izbjegli buduću zabunu s ostalim anonimnim korisnicima.",
        "noarticletext": "Na ovoj stranici trenutno nema teksta.\nMožete [[Special:Search/{{PAGENAME}}|tražiti naslov ove stranice]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} tražiti u povezanim zapisnicima] ili [{{fullurl:{{FULLPAGENAME}}|action=edit}} napraviti ovu stranicu]</span>.",
        "noarticletext-nopermission": "Trenutno nema teksta na ovoj stranici.\nMožete [[Special:Search/{{PAGENAME}}|tražiti ovaj naslov stranice]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane zapisnike]</span>, ali nemate dozvolu da napravite ovu stranicu.",
        "missing-revision": "Uređivanje broj $1 na stranici \"{{FULLPAGENAME}}\" ne postoji.\n\nOvo se obično dešava kad pratite zastarjelu vezu na stranicu koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} protokolu brisanja].",
        "previewnote": "<strong>Ne zaboravite da je ovo samo pregled.</strong>\nVaše izmjene još nisu sačuvane!",
        "continue-editing": "Idi na područje uređivanja",
        "previewconflict": "Ovaj pregled prikazuje kako će tekst u gornjem polju\nizgledati ako kliknete \"Sačuvaj članak\".",
-       "session_fail_preview": "<strong>Izvinjavamo se! Nismo mogli obraditi vašu izmjenu zbog gubitka podataka o prijavi.\nMolimo pokušajte ponovno.\nAko i dalje ne bude radilo, pokušajte se [[Special:UserLogout|odjaviti]] i ponovno prijaviti.</strong>",
+       "session_fail_preview": "Izvinjavamo se! Nismo mogli obraditi Vašu izmjenu zbog gubitka podataka o prijavi.\n\nMožda ste odjavljeni. <strong>Provjerite jeste li prijavljeni i pokušajte ponovo</strong>.\nAko i dalje ne radi, pokušajte se [[Special:UserLogout|odjaviti]] i ponovo prijaviti i provjerite dozvoljava li Vaš preglednik kolačiće s ovog sajta.",
        "session_fail_preview_html": "'''Žao nam je! Nismo mogli da obradimo vašu izmjenu zbog gubitka podataka.'''\n\n''Zbog toga što {{SITENAME}} ima omogućen izvorni HTML, predpregled je sakriven kao predostrožnost protiv JavaScript napada.''\n\n'''Ako ste pokušali da napravite pravu izmjenu, molimo pokušajte ponovo. Ako i dalje ne radi, pokušajte da se [[Special:UserLogout|odjavite]] i ponovo prijavite.'''",
        "token_suffix_mismatch": "'''Vaša izmjena nije prihvaćena jer je Vaš web preglednik ubacio znakove interpunkcije u token uređivanja.\nIzmjena je odbačena da bi se spriječilo uništavanje teksta stranice.\nTo se događa ponekad kad korisite problematični anonimni proxy koji je baziran na web-u.'''",
        "edit_form_incomplete": "'''Neki dijelovi uređivačkog obrasca nisu došli do servera; dvaput provjerite da su vaše izmjene nepromjenjene i pokušajte ponovno.'''",
        "nohistory": "Ne postoji historija izmjena za ovu stranicu.",
        "currentrev": "Trenutna verzija",
        "currentrev-asof": "Trenutna verzija na dan $2 u $3",
-       "revisionasof": "Verzija od $1",
+       "revisionasof": "Verzija na dan $2 u $3",
        "revision-info": "Izmjena od $1 od {{GENDER:$6|$2}}$7",
        "previousrevision": "← Starija izmjena",
        "nextrevision": "Novija izmjena →",
        "revdelete-submit": "Primijeni na odabrane {{PLURAL:$1|reviziju|revizije}}",
        "revdelete-success": "'''Vidljivost izmjene je ažurirana.'''",
        "revdelete-failure": "'''Vidljivost revizije nije mogla biti ažurirana:'''\n$1",
-       "logdelete-success": "'''Vidljivost evidencije uspješno postavljena.'''",
+       "logdelete-success": "Postavljena je vidljivost unosa u zapisniku.",
        "logdelete-failure": "'''Zapisnik vidljivosti nije mogao biti postavljen:'''\n$1",
        "revdel-restore": "Promijeni dostupnost",
        "pagehist": "Historija stranice",
        "difference-multipage": "(Razlika između stranica)",
        "lineno": "Red $1:",
        "compareselectedversions": "Uporedi označene verzije",
-       "showhideselectedversions": "Pokaži/sakrij odabrane verzije",
+       "showhideselectedversions": "Prikaži/sakrij izabrane izmjene",
        "editundo": "poništi",
        "diff-empty": "(Nema razlike)",
        "diff-multi-sameuser": "({{PLURAL:$1|Nije prikazana jedna međurevizija|Nisu prikazane $1 međurevizije}} istog korisnika)",
        "editusergroup": "Uredi {{GENDER:$1|korisničke}} grupe",
        "editinguser": "Mijenjate korisnička prava korisnika <strong>[[User:$1|$1]]</strong> $2",
        "userrights-editusergroup": "Uredi korisničke grupe",
-       "saveusergroups": "Sačuvaj korisničke grupe",
+       "saveusergroups": "Sačuvaj {{GENDER:$1|korisničke}} grupe",
        "userrights-groupsmember": "Član:",
        "userrights-groupsmember-auto": "Uključeni član od:",
        "userrights-groups-help": "Možete promijeniti grupe kojima ovaj korisnik pripada:\n* Označeni kvadratić znači da je korisnik u toj grupi.\n* Neoznačen kvadratić znači da korisnik nije u toj grupi.\n* Oznaka * (zvjezdica) označava da Vi ne možete izbrisati ovu grupu ako je dodate i obrnutno.",
        "right-override-export-depth": "Izvoz stranica uključujući povezane stranice do dubine od 5 linkova",
        "right-sendemail": "Slanje e-maila drugim korisnicima",
        "right-passwordreset": "Pogledaj e-mailove za obnavljanje šifre",
-       "right-managechangetags": "Napravi i briši [[Special:Tags|oznake]] iz baze podataka",
+       "right-managechangetags": "Napravi i (de)aktiviraj [[Special:Tags|oznake]]",
        "right-applychangetags": "Primijeni [[Special:Tags|oznake]] na nečije izmjene",
        "right-changetags": "Dodavanje ili uklanjanje raznih [[Special:Tags|oznaka]] na pojedinačnim verzijama i unosima zapisnika",
        "grant-group-page-interaction": "Upravljanje stranicama",
        "uploadstash-clear": "Očisti sakrivene datoteke",
        "uploadstash-nofiles": "Nemate sakrivenih datoteka.",
        "uploadstash-badtoken": "Izvršavanje ove akcije je bilo neuspješno, možda zato što su vaša uređivačka odobrenja istekla. Pokušajte ponovo.",
-       "uploadstash-errclear": "Brisanje sakrivenih datoteka je bilo neuspješno.",
+       "uploadstash-errclear": "Brisanje datoteka nije uspjelo.",
        "uploadstash-refresh": "Osvježi spisak datoteka",
        "invalid-chunk-offset": "Neispravna polazna tačka",
        "img-auth-accessdenied": "Pristup onemogućen",
        "log-title-wildcard": "Traži naslove koji počinju ovim tekstom",
        "showhideselectedlogentries": "Pokaži/sakrij izabrane zapise u evidenciji",
        "log-edit-tags": "Uredi oznake izabranih zapisničkih unosa",
+       "checkbox-select": "Izaberi: $1",
+       "checkbox-all": "Sve",
+       "checkbox-none": "Ništa",
+       "checkbox-invert": "Obrni",
        "allpages": "Sve stranice",
        "nextpage": "Sljedeća stranica ($1)",
        "prevpage": "Prethodna stranica ($1)",
        "enotif_body": "Poštovani $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nSažetak urednika: $PAGESUMMARY $PAGEMINOREDIT\n\nKontaktirajte urednika:\ne-pošta: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nNeće biti drugih obavještenja u slučaju daljnjih izmjena osim ako prijavljeni ponovno posjetite stranicu. Također možete poništiti oznake obavijesti za sve praćene stranice koje imate na vašem spisku praćenja.\n\nVaš prijateljski {{SITENAME}} sistem obavještavanja\n\n--\nZa promjenu vaših postavki email obavijesti, posjetite\n{{canonicalurl:{{#special:Preferences}}}}\n\nZa promjenu postavki vašeg praćenja, posjetite\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nDa obrišete stranicu sa vašeg spiska praćenja, posjetite\n$UNWATCHURL\n\nPovratne informacije i daljnja pomoć:\n$HELPPAGE",
        "created": "napravljena",
        "changed": "promijenjena",
-       "deletepage": "Obrišite stranicu",
+       "deletepage": "Obriši stranicu",
        "confirm": "Potvrdite",
        "excontent": "sadržaj je bio: \"$1\"",
        "excontentauthor": "sadržaj je bio: \"$1\", a jedini urednik \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|razgovor]])",
        "exbeforeblank": "sadržaj prije brisanja je bio: \"$1\"",
        "delete-confirm": "Brisanje \"$1\"",
        "delete-legend": "Obriši",
-       "historywarning": "<strong>Upozorenje</strong>: Stranica koju želite da obrišete ima historiju sa otprilike $1 {{PLURAL:$1|revizijom|revizije|revizija}}:",
+       "historywarning": "<strong>Upozorenje:</strong> Stranica koju želite obrisati ima historiju sa $1 {{PLURAL:$1|izmjenom|izmjene|izmjena}}:",
        "historyaction-submit": "Prikaži",
-       "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]].",
+       "confirmdeletetext": "Obrisat ćete stranicu i njenu historiju.\nPotvrdite svoju namjeru, da razumijete posljedice i da ovo radite u skladu s [[{{MediaWiki:Policy-url}}|pravilima]].",
        "actioncomplete": "Radnja je izvršena",
        "actionfailed": "Akcija nije uspjela",
        "deletedtext": "Stranica \"$1\" je obrisana.\nPogledajte $2 za zapisnik nedavnih brisanja.",
        "restriction-level-all": "svi nivoi",
        "undelete": "Pregled obrisanih stranica",
        "undeletepage": "Pregled i vraćanje obrisanih stranica",
-       "undeletepagetitle": "'''Sljedeći sadržaj prikazuje obrisane revizije od [[:$1|$1]]'''.",
+       "undeletepagetitle": "<strong>Sljedeći sadržaj prikazuje obrisane izmjene stranice [[:$1|$1]]<strong>.",
        "viewdeletedpage": "Pregled obrisanih stranica",
        "undeletepagetext": "{{PLURAL:$1|Slijedeća $1 stranica je obrisana|Slijedeće $1 stranice su obrisane|Slijedećih $1 je obrisano}} ali su još uvijek u arhivi i mogu biti vraćene.\nArhiva moše biti periodično čišćena.",
-       "undelete-fieldset-title": "Vraćanje revizija",
-       "undeleteextrahelp": "Da biste vratili cijelu historiju stranice, ostavite sve kućice neoznačene i kliknite na <strong><em>{{int:undeletebtn}}</em></strong>.\nDa biste vratili određene stranice, izaberite verzije koje želite vratiti i kliknite na <strong><em>{{int:undeletebtn}}</em></strong>.",
+       "undelete-fieldset-title": "Vraćanje izmjena",
+       "undeleteextrahelp": "Da biste vratili cijelu historiju stranice, ostavite sve kućice neoznačene i kliknite na <strong><em>{{int:undeletebtn}}</em></strong>.\nDa biste vratili određene izmjene, označite ih i kliknite na <strong><em>{{int:undeletebtn}}</em></strong>.",
        "undeleterevisions": "$1 {{PLURAL:$1|izmjena je obrisana|izmjena je obrisano}}",
-       "undeletehistory": "Ako vratite stranicu, sve će verzije biti vraćene u njenu historiju.\nAko je u međuvremenu napravljena nova verzija s istim nazivom, vraćene verzije će se pojaviti njenoj ranijoj historiji.",
-       "undeleterevdel": "Vraćanje obrisanog se neće izvršiti ako bi rezultiralo da zaglavlje stranice ili revizija datoteke bude djelimično obrisano.\nU takvim slučajevima, morate ukloniti označene ili otkriti sakrivene najskorije obrisane revizije.",
+       "undeletehistory": "Ako vratite stranicu, sve će izmjene biti vraćene u njenu historiju.\nAko je u međuvremenu napravljena nova izmjena s istim nazivom, vraćene izmjene pojavit će se u njenoj ranijoj historiji.",
+       "undeleterevdel": "Vraćanje neće biti izvršeno ako je rezultat toga djelomično brisanje posljednje izmjene.\nU takvim slučajevima morate isključiti ili otkriti najnoviju obrisanu izmjenu.",
        "undeletehistorynoadmin": "Ova stranica je obrisana.\nRazlog za brisanje se nalazi ispod, zajedno s detaljima o korisniku koji je mijenjao stranicu prije brisanja.\nTekst obrisanih verzija dostupan je samo administratorima.",
        "undelete-revision": "Obrisana izmjena stranice $1 (dana $4, u $5) koju je {{GENDER:$3|napravio|napravila}} $3:",
        "undeleterevision-missing": "Nepoznata ili nedostajuća revizija.\nMožda ste unijeli pogrešan link, ili je revizija vraćena ili uklonjena iz arhive.",
        "undeletebtn": "Vrati",
        "undeletelink": "pogledaj/vrati",
        "undeleteviewlink": "pogledaj",
-       "undeleteinvert": "Izmijeni odabir",
+       "undeleteinvert": "Obrni izbor",
        "undeletecomment": "Razlog:",
        "undeletedrevisions": "{{PLURAL:$1|vraćena $1 verzija|vraćene $1 verzije|vraćeno $1 verzija}}",
        "undeletedrevisions-files": "{{PLURAL:$1|1 verzija|$1 verzije|$1 verzija}} i {{PLURAL:$2|1 datoteka|$2 datoteke|$2 datoteka}} vraćeno",
        "undeletedfiles": "{{PLURAL:$1|1 datoteka vraćena|$1 datoteke vraćene|$1 datoteka vraćeno}}",
-       "cannotundelete": "Vraćanje nije uspjelo:\n$1",
+       "cannotundelete": "Vraćanje jedne ili svih stavki nije uspjelo:\n$1",
        "undeletedpage": "'''$1 je vraćena'''\n\nProvjerite [[Special:Log/delete|zapis brisanja]] za zapise najskorijih brisanja i vraćanja.",
        "undelete-header": "Pogledajte [[Special:Log/delete|zapisnik brisanja]] za nedavno obrisane stranice.",
        "undelete-search-title": "Pretraga obrisanih stranica",
        "sp-contributions-newbies-sub": "Za nove korisnike",
        "sp-contributions-newbies-title": "Doprinosi novih korisnika",
        "sp-contributions-blocklog": "zapisnik blokiranja",
-       "sp-contributions-suppresslog": "obrisani doprinosi korisnika",
-       "sp-contributions-deleted": "obrisani doprinosi korisnika",
+       "sp-contributions-suppresslog": "obrisani {{GENDER:$1|korisnički}} doprinosi",
+       "sp-contributions-deleted": "obrisani {{GENDER:$1|korisnički}} doprinosi",
        "sp-contributions-uploads": "postavljanja",
        "sp-contributions-logs": "zapisnici",
        "sp-contributions-talk": "razgovor",
        "whatlinkshere-hideredirs": "$1 preusmjerenja",
        "whatlinkshere-hidetrans": "$1 uključenja",
        "whatlinkshere-hidelinks": "$1 linkove",
-       "whatlinkshere-hideimages": "Veze do datoteke $1",
+       "whatlinkshere-hideimages": "$1 linkova do datoteke",
        "whatlinkshere-filters": "Filteri",
        "autoblockid": "Automatska blokada #$1",
        "block": "Blokiraj korisnika",
        "move-page": "Premjesti $1",
        "move-page-legend": "Premjesti stranicu",
        "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 premješten 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 premjestite 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 premještanje 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.",
+       "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<strong>Napomena:</strong>\nImajte na umu da premještanje 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": "Ako označite ovu kutijicu, odgovarajuća stranica za razgovor, ako postoji, automatski će biti premještena na novi naziv, osim ako već postoji sadržaj na odredišnoj stranici za razgovor.\n\nU tom slučaju, morat ćete ručno premjestiti ili prekopirati stranicu ako to želite.",
-       "moveuserpage-warning": "'''Upozorenje:''' Premještate korisničku stranicu. Molimo da zapamtite da će se samo stranica premjestiti a korisnik se ''neće'' preimenovati.",
+       "moveuserpage-warning": "<strong>Upozorenje:</strong> Premještate korisničku stranicu. Imajte u vidu da će samo stranica biti premještena, a sam korisnik <em>neće</em> biti preimenovan.",
        "movecategorypage-warning": "<strong>Upozorenje:</strong> Premještate stranicu kategorije. Imajte na umu da će samo stranica biti premještena i da sve stranice u staroj kategoriji <em>neće</em> biti ponovo kategorirane u novu kategoriju.",
        "movenologintext": "Morate biti registrovani korisnik i [[Special:UserLogin|prijavljeni]] da biste premjestili stranicu.",
        "movenotallowed": "Nemate dopuštenje za premještanje stranica.",
        "cant-move-category-page": "Nemate dopuštene da premještate stranice kategorija.",
        "cant-move-to-category-page": "Nemate dopuštenje da premjestite stranicu na stranicu kategorije.",
        "newtitle": "Novi naslov:",
-       "move-watch": "Prati ovu stranicu",
+       "move-watch": "Prati izvornu i odredišnu stranicu",
        "movepagebtn": "Premjesti stranicu",
        "pagemovedsub": "Premještanje uspjelo",
        "movepage-moved": "'''\"$1\" je premještena na \"$2\"'''",
        "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.",
        "cantmove-titleprotected": "Ne možete premjestiti stranicu na ovu lokaciju jer je novi naslov zaštićen od pravljenja.",
-       "movetalk": "Premjestite i stranicu za razgovor ako je moguće.",
+       "movetalk": "Premjesti i stranicu za razgovor",
        "move-subpages": "Premjesti sve podstranice (do $1)",
        "move-talk-subpages": "Premjesti podstranice stranica za razgovor (do $1)",
        "movepage-page-exists": "Stranica $1 već postoji i ne može biti automatski zamijenjena.",
        "revertmove": "vrati",
        "delete_and_move_text": "==Potebno brisanje==\nOdredišna stranica \"[[:$1]]\" već postoji.\nDa li je želite obrisati kako bi ste mogli izvršiti premještanje?",
        "delete_and_move_confirm": "Da, obriši stranicu",
-       "delete_and_move_reason": "Obrisano da bi se napravio prostor za premještanje iz \"[[$1]]\"",
+       "delete_and_move_reason": "Obrisano da se oslobodi mjesto za premještanje iz \"[[$1]]\"",
        "selfmove": "Izvorni i ciljani naziv su isti; strana ne može da se premjesti preko same sebe.",
        "immobile-source-namespace": "Ne mogu premjestiti stranice u imenski prostor \"$1\"",
        "immobile-target-namespace": "Ne mogu se premjestiti stranice u imenski prostor \"$1\"",
        "tags-actions-header": "Radnje",
        "tags-active-yes": "Da",
        "tags-active-no": "Ne",
-       "tags-source-extension": "Definirano preko proširenja",
+       "tags-source-extension": "Definirano softverom",
        "tags-source-manual": "Ručno postavili korisnici ili botovi",
        "tags-source-none": "Više se ne koristi",
        "tags-edit": "uređivanje",
index 3f1ea09..88a0cf8 100644 (file)
        "categoryviewer-pagedlinks": "($1) ($2)",
        "about": "Heqa cı de",
        "article": "Pela zerreki",
-       "newwindow": "(teqayaa newid abeno)",
-       "cancel": "Bıtexelne",
+       "newwindow": "(teqayaa newidı abena)",
+       "cancel": "İbtal",
        "moredotdotdot": "Vêşi...",
        "morenotlisted": "Na lista qay kemi ya.",
        "mypage": "Pele",
        "specialpage": "Pela xısusiye",
        "personaltools": "Hacetê şexsiy",
        "articlepage": "Pera zerreki bıvin",
-       "talk": "Werênayış",
+       "talk": "Vaten",
        "views": "Asayışi",
        "toolbox": "Haceti",
        "tool-link-userrights": "Grubanê {{GENDER:$1|karberi}} bıvırnë",
        "mainpage": "Pela Seri",
        "mainpage-description": "Pela seri",
        "policy-url": "Project:Terzê hereketi",
-       "portal": "Portalê cemaeti",
+       "portal": "Portala Şêlıgi",
        "portal-url": "Project:Portalë şëlıgi",
        "privacy": "Politikaya nımıteyiye",
        "privacypage": "Project:Xısusiyetê nımıtışi",
        "media_tip": "Gıreyê dosya",
        "sig_tip": "İmzay şıma be morê zemani",
        "hr_tip": "Xeta verardiye (teserrufın bıgureyne/bıxebetne)",
-       "summary": "Xulasa:",
+       "summary": "hulasa:",
        "subject": "Mewzu:",
        "minoredit": "No yew vurnayışo werdiyo",
        "watchthis": "Na pele seyr ke",
        "publishpage": "Perer bıhesırne",
        "publishchanges": "Vurnayışa vıla ke",
        "preview": "Verqayt",
-       "showpreview": "Verqayti bıvêne",
+       "showpreview": "Verasayışi bıvin",
        "showdiff": "Vurriyayışan bımocne",
        "anoneditwarning": "<strong>İqaz:</strong> Şıma be hesabê xo nêkewtê cı. \nAdresê şımayê IP tarixê vırnayışê na pele de do qeyd bo. Eke şıma <strong>[$1 cıkewê]</strong> ya zi <strong>[$2 hesab vırazê]</strong>, vurnayışê şıma be zewbina kare ra nameyê şıma rê bar beno.",
        "anonpreviewwarning": "\"Şıma be hesabê xo nêkewtê cı. Eke qeyd kerê, adresê şımaê IP tarixê vırnayışê na pele de do qeyd bo.\"",
        "rcnotefrom": "Cêr de <strong>$2</strong> ra nata {{PLURAL:$5|vurnayışiyê}} asenê (tewr vêşi <strong>$1</strong> asenê) <strong>$3, $4</strong>",
        "rclistfrom": "$3 $2 ra tepiya vurnayışanê neweyan bımocne",
        "rcshowhideminor": "Vurriyayışê werdiy $1",
-       "rcshowhideminor-show": "Bımocne",
+       "rcshowhideminor-show": "Bıasne",
        "rcshowhideminor-hide": "Bınımne",
        "rcshowhidebots": "botan $1",
        "rcshowhidebots-show": "Bımocne",
index cbe755d..fc8ba1f 100644 (file)
        "searchprofile-advanced-tooltip": "Search in custom namespaces",
        "search-result-size": "$1 ({{PLURAL:$2|1 word|$2 words}})",
        "search-result-category-size": "{{PLURAL:$1|1 member|$1 members}} ({{PLURAL:$2|1 subcategory|$2 subcategories}}, {{PLURAL:$3|1 file|$3 files}})",
-       "search-redirect": "(redirect $1)",
+       "search-redirect": "(redirect from $1)",
        "search-section": "(section $1)",
        "search-category": "(category $1)",
        "search-file-match": "(matches file content)",
        "feedback-external-bug-report-button": "File a technical task",
        "feedback-dialog-title": "Submit feedback",
        "feedback-dialog-intro": "You can use the easy form below to submit your feedback. Your comment will be added to the page \"$1\", along with your username.",
-       "feedback-error-title": "Error",
        "feedback-error1": "Error: Unrecognized result from API",
        "feedback-error2": "Error: Edit failed",
        "feedback-error3": "Error: No response from API",
index d1546a1..ec05dce 100644 (file)
        "upload-dialog-disabled": "Alŝutoj de dosiero per ĉi tiun dialogon estas malfunkciigita sur ĉi tiu vikio.",
        "upload-dialog-title": "Alŝuti dosieron",
        "upload-dialog-button-cancel": "Nuligi",
+       "upload-dialog-button-back": "Reen",
        "upload-dialog-button-done": "Farite",
        "upload-dialog-button-save": "Konservi",
        "upload-dialog-button-upload": "Alŝuti",
        "htmlform-cloner-create": "Aldoni plian",
        "htmlform-cloner-delete": "Forigi",
        "htmlform-cloner-required": "Almenaŭ unu valoro estas nepra.",
+       "htmlform-date-placeholder": "JJJJ-MM-TT",
+       "htmlform-time-placeholder": "HH:MM:SS",
+       "htmlform-datetime-placeholder": "JJJJ-MM-TT HH:MM:SS",
        "htmlform-title-badnamespace": "[[:$1]] ne  estas en \"{{ns:$2}}\" nomspaco.",
        "htmlform-title-not-creatable": "\"$1\" estas nekreebla titolo por paĝo",
        "htmlform-title-not-exists": "$1 ne ekzistas.",
index 79538b2..2fe58b4 100644 (file)
        "hebrew-calendar-m12-gen": "eloul",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discussion]])",
        "timezone-local": "Local",
-       "duplicate-defaultsort": "Attention : la clé de tri par défaut « $2 » écrase la précédente clé « $1 ».",
+       "duplicate-defaultsort": "<strong>Attention :</strong> 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 ».",
        "restricted-displaytitle": "<strong>Avertissement :</strong> le titre d’affichage \"$1\" a été ignoré car il n'est pas équivalent au titre effectif de la page.",
        "invalid-indicator-name": "<strong>Erreur :</strong> L’attribut <code>name</code> des indicateurs d’état de la page ne doit pas être vide.",
        "version-license-not-found": "Aucune information détaillée de la licence n'a été trouvée pour cette extension.",
        "version-credits-title": "Remerciements pour $1",
        "version-credits-not-found": "Aucune information détaillée des remerciements n'a été trouvée pour cette extension.",
-       "version-poweredby-credits": "Ce wiki fonctionne grâce à '''[https://www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
+       "version-poweredby-credits": "Ce wiki fonctionne grâce à <strong>[https://www.mediawiki.org/ MediaWiki]</strong>, copyright © 2001-$1 $2.",
        "version-poweredby-others": "autres",
        "version-poweredby-translators": "traducteurs de translatewiki.net",
        "version-credits-summary": "Nous tenons à remercier les personnes suivantes pour leur contribution à  [[Special:Version|MediaWiki]].",
-       "version-license-info": "MediaWiki est un logiciel libre, vous pouvez le redistribuer ou le modifier selon les termes de la Licence Publique Générale GNU telle que publiée par la Free Software Foundation ; soit la version 2 de la Licence, ou (à votre choix) toute version ultérieure.\n\nMediaWiki est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE, sans même la garantie implicite de COMMERCIALISATION ou D'ADAPTATION À UN USAGE PARTICULIER. Voir la Licence Publique Générale GNU pour plus de détails.\n\nVous devriez avoir reçu [{{SERVER}}{{SCRIPTPATH}}/COPYING une copie de la Licence Publique Générale GNU] avec ce programme, sinon, écrivez à la Free Software Foundation, Inc., 51, rue Franklin, cinquième étage, Boston, MA 02110-1301, États-Unis ou [//www.gnu.org/licenses/old-licenses/gpl-2.0.html lisez-la en ligne].",
+       "version-license-info": "MediaWiki est un logiciel libre, vous pouvez le redistribuer ou le modifier selon les termes de la Licence Publique Générale GNU telle que publiée par la Free Software Foundation ; soit la version 2 de la Licence, ou (à votre choix) toute version ultérieure.\n\nMediaWiki est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE, sans même la garantie implicite de COMMERCIALISATION ou D'ADAPTATION À UN USAGE PARTICULIER. Voir la Licence Publique Générale GNU pour plus de détails.\n\nVous devriez avoir reçu [{{SERVER}}{{SCRIPTPATH}}/COPYING une copie de la Licence Publique Générale GNU] avec ce programme, sinon, écrivez à la Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, États-Unis ou [//www.gnu.org/licenses/old-licenses/gpl-2.0.html lisez-la en ligne].",
        "version-software": "Logiciels installés",
        "version-software-product": "Produit",
        "version-software-version": "Version",
index 0f3e624..43d25bf 100644 (file)
        "disclaimers": "𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍂𐌰𐌹𐌷𐍄𐌰𐌹𐍃",
        "disclaimerpage": "Project:𐌲𐌰𐌼𐌰𐌹𐌽𐌰 𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍃 𐍂𐌰𐌹𐌷𐍄𐌰𐌹𐍃",
        "edithelp": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌷𐌹𐌻𐍀𐌰",
+       "helppage-top-gethelp": "𐌷𐌹𐌻𐍀𐌰",
        "mainpage": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "mainpage-description": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
-       "portal": "ð\90\8c±ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c²ð\90\8d\83 ð\90\8c²ð\90\8c°ð\90\8d\85ð\90\8c¹",
-       "portal-url": "Project:ð\90\8c±ð\90\8c°ð\90\8c¿ð\90\8d\82ð\90\8c²ð\90\8d\83 ð\90\8c²ð\90\8c°ð\90\8d\85ð\90\8c¹",
+       "portal": "ð\90\8c²ð\90\8c°ð\90\8cµð\90\8c¿ð\90\8c¼ð\90\8c¸ð\90\8d\83 ð\90\8c²ð\90\8c°ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c½ð\90\8c³ð\90\8c¿ð\90\8c¸ð\90\8c°ð\90\8c¹ð\90\8d\83",
+       "portal-url": "Project:ð\90\8c²ð\90\8c°ð\90\8cµð\90\8c¿ð\90\8c¼ð\90\8c¸ð\90\8d\83 ð\90\8c²ð\90\8c°ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c½ð\90\8c³ð\90\8c¿ð\90\8c¸ð\90\8c°ð\90\8c¹ð\90\8d\83",
        "privacy": "𐌲𐌰𐍂𐌴𐌳𐌴𐌹𐌽𐍉𐍃 𐍃𐌿𐌽𐌳𐍂𐍉𐍅𐌹𐍃𐌰𐌽𐌰",
        "privacypage": "Project:𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍃𐌿𐌽𐌳𐍂𐍉𐍅𐌹𐍃𐌰𐌽𐌰",
        "retrievedfrom": "𐌲𐌰𐌽𐌿𐌼𐌰𐌽 𐍆𐍂𐌰𐌼 \"$1\"",
        "createacct-yourpasswordagain": "𐌲𐌰𐍃𐌹𐌲𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "createacct-yourpasswordagain-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌰𐍆𐍄𐍂𐌰",
        "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 {{GENDER:𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰|𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰}}",
+       "cannotloginnow-title": "𐌽𐌿 𐌽𐌹 𐌼𐌰𐌲𐍄 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽",
        "login": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "userlogin": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "pt-login": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "pt-login-button": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "pt-createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
+       "pt-userlogout": "𐌰𐍆𐌻𐌴𐌹𐌸",
        "passwordreset": "𐌰𐍆𐍄𐍂𐌰 𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
        "bold_sample": "𐍃𐍅𐌹𐌽𐌸𐍉𐍃 𐌱𐍉𐌺𐍉𐍃",
        "bold_tip": "𐍃𐍅𐌹𐌽𐌸𐍉𐍃 𐌱𐍉𐌺𐍉𐍃",
        "showpreview": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽",
        "showdiff": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌽𐌹𐌽𐍃",
        "loginreqlink": "𐌰𐍄𐌲𐌰𐌲𐌲",
-       "newarticle": "(ð\90\8c½ð\90\8c¹ð\90\8c¿ð\90\8c¾ð\90\8c°ð\90\8d\84ð\90\8c°)",
+       "newarticle": "(ð\90\8c½ð\90\8c¹ð\90\8d\85ð\90\8c¹)",
        "newarticletext": "𐌻𐌰𐌹𐍃𐍄𐌹𐌳𐌴𐍃 𐌲𐌰𐍅𐌹𐍃 𐌳𐌿 𐌻𐌰𐌿𐌱𐌰 𐍃𐌰𐌴𐌹 𐌽𐌹𐍃𐍄. 𐌳𐌿 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆, 𐌰𐌽 𐌰𐍃𐍄𐍉𐌳𐌴𐌹 𐌼𐌴𐌻𐌾𐌰𐌽 𐌹𐌽 𐌰𐍂𐌺𐌰𐌹 𐌿𐍆 (𐍃𐌰𐌹𐍈 [$1 𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆] 𐌼𐌰𐌽𐌰𐌲𐌹𐌶𐌹𐌽 𐌺𐌿𐌽𐌸𐌾𐌰). 𐌾𐌰𐌱𐌰𐌹 𐌹𐍃 𐌷𐌴𐍂 𐌹𐌽 𐌰𐌹𐍂𐌶𐌴𐌹𐌽𐍃, 𐌲𐌰𐌲𐌲 𐌳𐌿 <𐍃𐍄𐍂𐍉𐌽𐌲>𐌹𐌱𐌿𐌺𐌰𐌷𐌰𐌿𐌱𐌹𐌳𐌹𐌻𐍉𐌽.",
        "noarticletext": "𐌽𐌿 𐌽𐌹 𐍃𐌹𐌽𐌳 𐌱𐍉𐌺𐍉𐍃 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.\n𐌼𐌰𐌲𐍄 [[Special:Search/{{PAGENAME}}|𐍃𐍉𐌺𐌾𐌰𐌽 𐌸𐌰𐍄𐌰 𐌻𐌰𐌿𐌱𐌰-𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹]] 𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌻𐌰𐌿𐌱𐌰𐌼,  <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 𐍃𐍉𐌺𐌾𐌰𐌽 𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐌲𐌰𐍆𐌰𐍃𐍄𐍉𐍃], 𐌰𐌹𐌸𐌸𐌰𐌿 [{{fullurl:{{FULLPAGENAME}}|action=edit}} 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆.]</ span>",
        "noarticletext-nopermission": "𐌽𐌿 𐌽𐌹 𐍃𐌹𐌽𐌳 𐌱𐍉𐌺𐍉𐍃 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.\n𐌼𐌰𐌲𐍄 [[Special:Search/{{PAGENAME}}|𐍃𐍉𐌺𐌾𐌰𐌽 𐌸𐌰𐍄𐌰 𐌻𐌰𐌿𐌱𐌰-𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹]] 𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌻𐌰𐌿𐌱𐌰𐌼, 𐌸𐌰𐌿 <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 𐍃𐍉𐌺𐌾𐌰𐌽 𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐌲𐌰𐍆𐌰𐍃𐍄𐍉𐍃]</span>, 𐌹𐌸 𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆.",
        "updated": "(𐌰𐌽𐌰𐌽𐌹𐍅𐌹𐌸)",
        "previewnote": "<strong>𐌲𐌰𐌼𐌹𐌽𐌸𐌴𐌹 𐌸𐌰𐍄𐌴𐌹 𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽𐍃.</strong>\n𐌸𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌽𐌰𐌿𐌷 𐌽𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌽𐍉𐍃 𐍃𐌹𐌽𐌳!",
-       "editing": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1",
-       "creating": "{{GENDER:𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃|𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐌴𐌹}} $1",
+       "editing": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃}} $1",
+       "creating": "{{GENDER:𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃|𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐌴𐌹|𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃\n}} $1",
        "editingsection": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌳𐌰𐌹𐌻)",
        "editingcomment": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌽𐌹𐌿𐌾𐌰 𐌳𐌰𐌹𐌻)",
        "yourdiff": "𐌲𐌰𐍃𐌺𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
        "history-feed-item-nocomment": "$1 𐌰𐍄 $2",
        "rev-delundel": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌰𐌽𐌰𐍃𐌹𐌿𐌽",
        "revdel-restore": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌰𐌽𐌰𐍃𐌹𐌿𐌽",
-       "revertmerge": "ð\90\8c¿ð\90\8c½ð\90\8c²ð\90\8c°ð\90\8d\84ð\90\8c¹ð\90\8c»ð\90\8d\89ð\90\8d\83",
+       "revertmerge": "ð\90\8c¿ð\90\8c½ð\90\8c²ð\90\8c°ð\90\8c±ð\90\8c»ð\90\8c°ð\90\8c½ð\90\8c³",
        "history-title": "𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽𐌹𐍃𐍀𐌹𐌻𐌻 𐌻𐌰𐌿𐌱𐌹𐍃 \"$1\"",
        "difference-title": "𐌲𐌰𐍃𐌺𐌰𐌹𐌳𐌴𐌹𐌽𐍃 𐌼𐌹𐌸 𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽𐍉𐌼 𐌻𐌰𐌿𐌱𐌹𐍃 \"$1\"",
        "lineno": "𐍃𐍄𐍂𐌹𐌺𐍃 $1:",
        "search-showingresults": "{{ZPLURAL:$4|𐍄𐌰𐌿𐌹 <strong>$1 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 <strong>$3|𐍄𐍉𐌾𐌰 <strong>$1 - $2 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 <strong>$3}}",
        "search-nonefound": "𐌽𐌹 𐍄𐌰𐌿𐌹 𐍅𐌰𐍃 𐍃𐌰𐌼𐌰𐌽𐌰 𐍃𐍅𐌰 𐍃𐍉𐌺𐌴𐌹𐌽.",
        "powersearch-legend": "𐍃𐍉𐌺𐌴𐌹",
-       "preferences": "ð\90\8c¼ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8c±ð\90\8d\82ð\90\8c¿ð\90\8cºð\90\8c¾ð\90\8c°ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8c´ð\90\8c¹𐍃",
-       "mypreferences": "ð\90\8c²ð\90\8c°ð\90\8c»ð\90\8c´ð\90\8c¹ð\90\8cºð\90\8c°ð\90\8c½ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
+       "preferences": "ð\90\8c¼ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8d\86ð\90\8d\82ð\90\8c¹ð\90\8c¾ð\90\8d\89ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8d\85ð\90\8c°ð\90\8c¹ð\90\8c·ð\90\8d\84𐍃",
+       "mypreferences": "ð\90\8c¼ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8d\86ð\90\8d\82ð\90\8c¹ð\90\8c¾ð\90\8d\89ð\90\8c½ð\90\8d\89𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
        "prefs-skin": "𐍆𐌹𐌻𐌻",
        "skin-preview": "𐍆𐌰𐌿𐍂𐌰𐍃𐌰𐌹𐍈",
        "saveprefs": "𐌲𐌰𐍆𐌰𐍃𐍄",
        "minoreditletter": "l",
        "newpageletter": "N",
        "boteditletter": "b",
-       "recentchangeslinked": "ð\90\8c²ð\90\8c°ð\90\8d\85ð\90\8c¹𐌳𐌰𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
-       "recentchangeslinked-feed": "Máideinlieks",
-       "recentchangeslinked-toolbox": "ð\90\8c²ð\90\8c°ð\90\8d\85ð\90\8c¹𐌳𐌰𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
-       "recentchangeslinked-title": "ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8c²ð\90\8c°ð\90\8d\85ð\90\8c¹𐌳𐌰𐌽𐍉𐍃 𐌼𐌹𐌸 \"$1\"",
-       "recentchangeslinked-summary": "𐍃𐍉 𐌹𐍃𐍄 𐌻𐌴𐌹𐍃𐍄𐌰 𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌴 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍃 𐍃𐌺𐍉𐍀 𐌰𐌽𐌰 𐍃𐌴𐌹𐌳𐍉𐌽𐍃 𐌻𐌴𐌹𐌽𐌺𐍉𐌽𐌳 𐌿𐍃 𐌿𐍃𐍃𐌹𐌽𐌳𐌰𐌹 𐍃𐌴𐌹𐌳𐍉𐌽 (𐌰𐌹𐌸𐌸𐌰𐌿 𐌻𐌹𐌸𐌰𐌿𐍃 𐌿𐍃𐍃𐌹𐌽𐌳𐌰𐌹𐌶𐍉𐍃 𐌷𐌰𐌽𐍃𐍉𐍃). 𐍃𐌴𐌹𐌳𐍉𐌽𐍃 [[Special:Watchlist|𐍅𐌹𐍄𐌰𐌽𐌳𐌻𐌴𐌹𐍃𐍄𐍉𐍃 𐌸𐌴𐌹𐌽𐍉𐍃]] 𐍃𐌹𐌽𐌳 '''𐌳𐌹𐌲𐍂𐍃𐍄𐌰𐍆𐍃'''.",
+       "recentchangeslinked": "ð\90\8c²ð\90\8c°ð\90\8c±ð\90\8c¿ð\90\8c½𐌳𐌰𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
+       "recentchangeslinked-feed": "𐌲𐌰𐌱𐌿𐌽𐌳𐌰𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
+       "recentchangeslinked-toolbox": "ð\90\8c²ð\90\8c°ð\90\8c±ð\90\8c¿ð\90\8c½𐌳𐌰𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
+       "recentchangeslinked-title": "ð\90\8c¹ð\90\8c½ð\90\8c¼ð\90\8c°ð\90\8c¹ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8c½ð\90\8d\89ð\90\8d\83 ð\90\8c²ð\90\8c°ð\90\8c±ð\90\8c¿ð\90\8c½𐌳𐌰𐌽𐍉𐍃 𐌼𐌹𐌸 \"$1\"",
+       "recentchangeslinked-summary": "A𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐍅𐌹𐌺𐍉 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉 𐌽𐌹𐌿𐌾𐌰𐌱𐌰 𐌲𐌰𐍄𐌰𐍅𐌹𐌳𐍉𐍃 𐌻𐌰𐌿𐌱𐌰𐌼 𐌲𐌰𐌱𐌿𐌽𐌳𐌰𐌹 𐍃𐌿𐌼𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰 (𐌸𐌰𐌿 𐌲𐌰𐌳𐌰𐌹𐌻𐌰𐌼 𐍃𐌿𐌼𐌹𐍃 𐌺𐌿𐌽𐌾𐌹𐍃). <strong>𐌻𐌰𐌿𐌱𐍉𐍃 𐌰𐌽𐌰 [[Special:Watchist|your]] 𐍃𐌹𐌽𐌳 </strong>𐍃𐍅𐌹𐌽𐌸𐌰𐌹.",
        "recentchangeslinked-page": "𐌻𐌰𐌿𐌱𐌰𐌽𐌰𐌼𐍉:",
        "recentchangeslinked-to": "𐌰𐍄𐌰𐌿𐌲𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌻𐌰𐌿𐌱𐌴 𐌸𐌰𐌹𐌴𐌹 𐌲𐌰𐍅𐌹𐌳𐌰𐌽𐌰𐌹 𐌳𐌿 𐌲𐌹𐌱𐌰𐌽𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.",
        "upload": "𐌿𐍃𐌷𐌻𐌰𐌸𐌰𐌽 𐍆𐌴𐌹𐌻𐌰𐌽𐍃",
        "brokenredirects-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹",
        "brokenredirects-delete": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹",
        "nbytes": "$1 {{PLURAL:$1|𐌱𐌹𐍄|𐌱𐌰𐍄𐌰}}",
-       "ncategories": "$1 {{PLURAL:$1|ð\90\8cºð\90\8c¿ð\90\8c½ð\90\8c¾ð\90\8c°|ð\90\8cºð\90\8c¿ð\90\8c½ð\90\8c¾ð\90\8d\89ð\90\8d\83}}",
+       "ncategories": "$1 {{PLURAL:$1|ð\90\8cºð\90\8c¿ð\90\8c½ð\90\8c¹|ð\90\8cºð\90\8c¿ð\90\8c½ð\90\8c¾ð\90\8c°}}",
        "nlinks": "$1 {{PLURAL:$1|𐌲𐌰𐍅𐌹𐍃𐍃|𐌲𐌰𐍅𐌹𐍃𐍃𐌴𐌹𐍃}}",
        "nmembers": "$1 {{PLURAL:$1|𐌲𐌰𐌳𐌰𐌹𐌻𐌰|𐌲𐌰𐌳𐌰𐌹𐌻𐌰𐌽𐍃}}",
        "wantedpages": "𐌲𐌰𐌹𐍂𐌽𐌹𐌳𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "longpages": "𐌻𐌰𐌲𐌲𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "listusers": "𐍂𐌴𐌲𐌹𐍃𐍄𐍂𐌴𐍂𐌰𐌳𐌴 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐍃",
        "newpages": "𐌽𐌹𐌿𐌾𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
-       "move": "ð\90\8c½ð\90\8c°ð\90\8c¼ð\90\8c¾ð\90\8c°ð\90\8c½ ð\90\8c°ð\90\8d\86ð\90\8d\84ð\90\8d\82ð\90\8c°",
+       "move": "ð\90\8c¼ð\90\8c¹ð\90\8c¸ð\90\8d\83ð\90\8c°ð\90\8d\84ð\90\8c´ð\90\8c¹",
        "movethispage": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆",
        "booksources": "𐌱𐍉𐌺𐌰𐌱𐍂𐌿𐌽𐌽𐌰𐌽𐍃",
        "booksources-search-legend": "𐍃𐍉𐌺𐌴𐌹 𐌱𐍉𐌺𐌰𐌱𐍂𐌿𐌽𐌽𐌰𐌽𐍃",
        "log": "𐌻𐍉𐌲𐌱𐍉𐌺𐍉𐍃",
        "all-logs-page": "𐌰𐌻𐌻𐌰 𐌻𐍉𐌲𐍉𐍃",
        "allpages": "𐌰𐌻𐌻𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
-       "nextpage": "ð\90\8c¹ð\90\8d\86ð\90\8d\84ð\90\8c¿ð\90\8c¼ð\90\8c° ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³ð\90\8d\89 ($1)",
+       "nextpage": "ð\90\8c¹ð\90\8d\86ð\90\8d\84ð\90\8c¿ð\90\8c¼ð\90\8c° ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8d\86ð\90\8d\83 ($1)",
        "prevpage": "𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍃 𐌻𐌰𐌿𐍆𐍃 ($1)",
        "allarticles": "𐌰𐌻𐌻𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "allpagessubmit": "𐌲𐌰𐌲𐌲",
        "unwatch": "𐌽𐌹𐍅𐌰𐍂𐌰𐌽",
        "watchlist-details": "{{PLURAL:$1|$1 𐌻𐌰𐌿𐍆𐍃|$1 𐌻𐌰𐌿𐌱𐍉𐍃}} 𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽, 𐌽𐌹 𐍃𐌿𐌽𐌳𐍂𐍉 𐍂𐌰𐌷𐌽𐌾𐌰𐌽𐌳𐌰 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰𐌻𐌰𐌿𐌱𐍉𐍃.",
        "watching": "Wita...",
-       "unwatching": "Niwita...",
+       "unwatching": "𐌿𐌽𐍅𐌹𐍄𐌰𐌽𐌳𐍉...",
        "created": "𐌲𐌰𐍃𐌺𐌰𐍀𐌾𐌰𐌽",
        "deletepage": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹 𐌻𐌰𐌿𐌱𐌰",
        "delete-legend": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹",
        "prot_1movedto2": "[[$1]] 𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌸 𐌳𐌿 [[$2]]",
        "protect-level-sysop": "𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐌸 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍂𐌴𐌹𐌺𐍃",
        "protect-expiring": "𐌿𐍃𐍄𐌹𐌿𐌷𐌹𐌸 $1 (UTC)",
-       "restriction-type": "Freihals:",
+       "restriction-type": "𐌰𐌽𐌳𐌻𐌴𐍄",
        "restriction-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹",
-       "restriction-move": "ð\90\8d\83ð\90\8cºð\90\8c¹ð\90\8c¿ð\90\8c±ð\90\8c°ð\90\8c½",
+       "restriction-move": "ð\90\8c¼ð\90\8c¹ð\90\8c¸ð\90\8d\83ð\90\8c°ð\90\8d\84ð\90\8c´ð\90\8c¹",
        "undeletebtn": "𐌰𐍆𐍄𐍂𐌰 𐌲𐌰𐌱𐍉𐍄𐌾𐌰𐌽",
        "undeletelink": "𐍃𐌰𐌹𐍈𐌰𐌽/𐌰𐍆𐍄𐍂𐌰𐌲𐌰𐍃𐌰𐍄𐌾𐌰𐌽",
        "undeleteviewlink": "𐍃𐌰𐌹𐍈𐌹𐍃",
        "blocklogentry": "𐌰𐍆𐌳𐍂𐌰𐌿𐍃𐌹𐌸 [[$1]] 𐍆𐌰𐌿𐍂 $2 $3",
        "newtitle": "𐌽𐌹𐌿𐌾𐌹 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹:",
        "move-watch": "𐌰𐍄𐍅𐌹𐍄 𐌱𐍂𐌿𐌽𐌽𐌰𐌻𐌰𐌿𐌱𐌰 𐌾𐌰𐌷 𐌼𐌿𐌽𐌳𐍂𐌴𐌹𐌻𐌰𐌿𐌱𐌰",
-       "movepagebtn": "ð\90\8d\83ð\90\8cºð\90\8c¹ð\90\8c¿ð\90\8c±ð\90\8c° ð\90\8d\83ð\90\8c´ð\90\8c¹ð\90\8c³ð\90\8d\89",
+       "movepagebtn": "ð\90\8c¼ð\90\8c¹ð\90\8c¸ð\90\8d\83ð\90\8c°ð\90\8d\84ð\90\8c´ð\90\8c¹ ð\90\8c»ð\90\8c°ð\90\8c¿ð\90\8d\86",
        "movelogpage": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽",
        "movereason": "𐍆𐌰𐌹𐍂𐌹𐌽𐌰:",
        "revertmove": "𐍂𐌰𐌹𐌳𐌾𐌰𐌽",
        "tag-filter": "[[Special:Tags|𐍄𐌰𐌹𐌺𐌽𐍉𐍃]] 𐍆𐌹𐌻𐌷𐌰",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|𐍃𐍉𐌺𐌴𐌹𐌽𐌹𐍅𐌰𐌿𐍂𐌳|𐍃𐍉𐌺𐌴𐌹𐌽𐌹𐍅𐌰𐌿𐍂𐌳𐌰}}]]: $2)",
        "tags-source-header": "𐌱𐍂𐌿𐌽𐌽𐌰",
-       "tags-actions-header": "ð\90\8c³ð\90\8c´ð\90\8c³ð\90\8c´ð\90\8c¹ð\90\8d\83",
+       "tags-actions-header": "ð\90\8d\84ð\90\8d\89ð\90\8c¾ð\90\8c°",
        "tags-source-none": "𐌽𐌹 𐌾𐌿 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰",
        "tags-delete": "𐌿𐍃𐌽𐌹𐌼",
        "tags-activate": "𐌲𐌰𐌵𐌹𐌿𐌴𐌹",
index 716b426..14b2bd4 100644 (file)
        "export-download": "Ponudi opciju snimanja u datoteku",
        "export-templates": "Uključi predloške",
        "export-pagelinks": "Uključi povezane stranice do dubine od:",
-       "allmessages": "Sve sistemske poruke",
+       "allmessages": "Sve poruke sustava",
        "allmessagesname": "Ime",
        "allmessagesdefault": "Prvotni tekst",
        "allmessagescurrent": "Trenutačni tekst",
index 328d5c7..debdc18 100644 (file)
        "createacct-yourpasswordagain-ph": "Inserisci nuovamente la password",
        "userlogin-remembermypassword": "Mantienimi collegato",
        "userlogin-signwithsecure": "Usa una connessione sicura",
+       "cannotlogin-title": "Non è possibile effettuare l'accesso",
        "cannotlogin-text": "L'accesso non è possibile.",
        "cannotloginnow-title": "Impossibile accedere ora",
        "cannotloginnow-text": "L'accesso non è possibile quando si sta usando $1.",
index f8b033b..113b4a0 100644 (file)
@@ -90,7 +90,7 @@
        "tog-enotifminoredits": "문서나 파일의 사소한 편집도 이메일로 알림",
        "tog-enotifrevealaddr": "알림 메일에 내 이메일 주소를 밝히기",
        "tog-shownumberswatching": "주시하는 사용자 수 보이기",
-       "tog-oldsig": "현재 서명:",
+       "tog-oldsig": "당신의 기존 서명:",
        "tog-fancysig": "서명을 위키텍스트로 취급 (자동으로 링크를 걸지 않음)",
        "tog-uselivepreview": "실시간 미리 보기 사용하기",
        "tog-forceeditsummary": "편집 요약을 쓰지 않았을 때 내게 물어보기",
        "file-thumbnail-no": "파일 이름이 <strong>$1</strong>으로 시작합니다.\n이 파일은 그림의 크기를 줄인 (섬네일) 파일인 것 같습니다.\n더 해상도가 좋은 파일이 있다면 그 파일을 올리거나 아니면 올리려는 파일 이름을 바꾸세요.",
        "fileexists-forbidden": "같은 이름의 파일이 이미 있고, 덮어쓸 수 없습니다.\n그래도 파일을 올리시려면, 뒤로 돌아가서 다른 이름으로 시도해 주시기 바랍니다.\n[[File:$1|thumb|center|$1]]",
        "fileexists-shared-forbidden": "같은 이름의 파일이 이미 위키미디어 공용에 있습니다.\n그래도 파일을 올리려면 뒤로 돌아가서 다른 이름으로 시도해 주시기 바랍니다.\n[[File:$1|thumb|center|$1]]",
+       "fileexists-no-change": "업로드한 항목은 <strong>[[:$1]]</strong>의 현재 판과 완전히 중복입니다.",
+       "fileexists-duplicate-version": "업로드한 항목은 <strong>[[:$1]]</strong>의 {{PLURAL:$2|과거의 판}}과 완전히 중복입니다.",
        "file-exists-duplicate": "현재 올리고 있는 {{PLURAL:$1|파일}}이 아래 파일과 중복됩니다:",
        "file-deleted-duplicate": "이 파일과 같은 파일 ([[:$1]])이 이전에 삭제된 적이 있습니다. 파일을 다시 올리기 전에 문서의 삭제 기록을 확인해 주시기 바랍니다.",
        "file-deleted-duplicate-notitle": "이 파일과 같은 파일이 이전에 삭제된 적이 있으며, 제목은 숨겨져 있습니다.\n다시 올리기 전에 상확은 검토하기 위해 숨겨진 파일 데이터를 볼 수 있는 누군가에게 물어봐야 합니다.",
        "userjsispublic": "주목해 주십시오: 자바스크립트의 하위 문서들은 다른 사용자들이 볼 수 있기 때문에 기밀 데이터를 포함해서는 안 됩니다.",
        "usercssispublic": "주목해 주십시오: CSS의 하위 문서들은 다른 사용자들이 볼 수 있기 때문에 기밀 데이터를 포함해서는 안 됩니다.",
        "restrictionsfield-badip": "유효하지 않은 IP 주소나 대역: $1",
-       "restrictionsfield-label": "허용된 IP 대역:"
+       "restrictionsfield-label": "허용된 IP 대역:",
+       "restrictionsfield-help": "줄 단위의 하나의 IP 주소 또는 CIDR 대역입니다. 모든 곳에 적용하려면, 다음을 사용하세요<br><code>0.0.0.0/0</code><br><code>::/0</code>"
 }
index 767938c..142c423 100644 (file)
        "upload-options": "Optioune vum Eroplueden",
        "watchthisupload": "Dëse Fichier iwwerwaachen",
        "filewasdeleted": "E Fichier mat dësem Numm gouf schonn eemol eropgelueden an duerno nees geläscht. Kuckt w.e.g op $1 no, ier Dir dee Fichier nach eng Kéier eropluet.",
+       "filename-thumb-name": "Dësen Numm gesäit aus wéi den Numm vun engem Miniaturbild. Luet w.e.g. keng Miniatur-Biller zréck op déi selwecht Wiki. Sollt et sech ëm een anert Bild handelen da sicht w.e.g. e Fichiersnumm dee méi verständlech ass an den net sou ufänkt wéi e Miniaturbild.",
        "filename-bad-prefix": "Den Numm vum Fichier fänkt mat '''„$1“''' un. Dësen Numm krut en automatesch vun der Kamera a seet näischt iwwer dat aus, wat drop ass. Gitt dem Fichier w.e.g. en Numm, deen den Inhalt besser beschreift, an deen net verwiesselt ka ginn.",
        "upload-proto-error": "Falsche Protokoll",
        "upload-proto-error-text": "D'URL muss mat <code>http://</code> oder <code>ftp://</code> ufänken.",
index 11c42a1..033c37b 100644 (file)
        "tag-filter": "[[Special:Tags|खूणपताका]] गाळक:",
        "tag-filter-submit": "गाळक",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|खूणपताका}}]]: $2)",
-       "tags-title": "खुणा",
-       "tags-intro": "प्रणालीतून विशिष्ट संपादनांच्या अर्थासहित  खुणांची  यादी नमूद करणारे पान",
+       "tags-title": "à¤\96à¥\81णपताà¤\95ा",
+       "tags-intro": "प्रणालीतून, विशिष्ट संपादनांच्या अर्थासहित  खुणपताकांची  यादी नमूद करणारे पान",
        "tags-tag": "खूण नाव",
        "tags-display-header": "बदल सुचीवर कसे दिसेल",
        "tags-description-header": "अर्थाची पूर्ण माहिती",
        "tags-hitcount": "$1 {{PLURAL:$1|बदल|बदल}}",
        "tags-manage-blocked": "आपण प्रतिबंधित असतांना बदल खूणपताकांचे व्यवस्थापन करु शकत नाही.",
        "tags-create-heading": "नवीन बिल्ला तयार करा",
+       "tags-create-explanation": "अविचलरित्या, नविन तयार केलेल्या खुणपताका सदस्यांना व सांगकाम्यांना वापरासाठी उपलब्ध होतील.",
        "tags-create-tag-name": "खूणपताकेचे नाव:",
        "tags-create-reason": "कारण:",
        "tags-create-submit": "निर्मित करा",
index 151f629..37b91d4 100644 (file)
        "upload-dialog-disabled": "Filopplastinger med denne dialogen er slått av for denne wikien.",
        "upload-dialog-title": "Last opp fil",
        "upload-dialog-button-cancel": "Avbryt",
+       "upload-dialog-button-back": "Tilbake",
        "upload-dialog-button-done": "Utført",
        "upload-dialog-button-save": "Lagre",
        "upload-dialog-button-upload": "Last opp",
        "htmlform-cloner-create": "Legg til mer",
        "htmlform-cloner-delete": "Fjern",
        "htmlform-cloner-required": "Minst én verdi kreves.",
+       "htmlform-date-placeholder": "ÅÅÅÅ-MM-DD",
+       "htmlform-time-placeholder": "TT:MM:SS",
+       "htmlform-datetime-placeholder": "ÅÅÅÅ-MM-DD TT:MM:SS",
+       "htmlform-date-invalid": "Verdien du anga gjenkjennes ikke som en dato. Prøv formatet ÅÅÅÅ-MM-DD.",
+       "htmlform-time-invalid": "Verdien du anga gjenkjennes ikke som et tidspunkt. Prøv formatet TT:MM:SS.",
+       "htmlform-datetime-invalid": "Verdien du anga gjenkjennes ikke som en dato og et tidspunkt. Prøv formatet ÅÅÅÅ-MM-DD TT:MM:SS.",
+       "htmlform-date-toolow": "Verdien du anga er før den tidligste tillatte datoen $1.",
+       "htmlform-date-toohigh": "Verdien du anga er etter den siste tillatte datoen $1.",
+       "htmlform-time-toolow": "Verdien du anga er før det tidligste tillatte tidspunktet $1.",
+       "htmlform-time-toohigh": "Verdien du anga er etter det siste tillatte tidspunktet $1.",
+       "htmlform-datetime-toolow": "Verdien du anga er før den tidligste tillatte datoen og tidspunktet $1.",
+       "htmlform-datetime-toohigh": "Verdien du anga er etter den siste tillatte datoen og tidspunktet $1.",
        "htmlform-title-badnamespace": "[[:$1]] er ikke i «{{ns:$2}}»-navnerommet",
        "htmlform-title-not-creatable": "«$1» er ikke en opprettbar sidetittel",
        "htmlform-title-not-exists": "$1 forefinnes ikke.",
index ad9848b..c7e8927 100644 (file)
        "htmlform-cloner-delete": "Usuń",
        "htmlform-cloner-required": "Wymagana jest co najmniej jedna wartość.",
        "htmlform-date-placeholder": "RRRR-MM-DD",
+       "htmlform-time-placeholder": "GG:MM:SS",
+       "htmlform-datetime-placeholder": "RRRR-MM-DD GG:MM:SS",
        "htmlform-title-badnamespace": "[[:$1]] nie znajduje się w przestrzeni nazw „{{ns:$2}}”.",
        "htmlform-title-not-creatable": "Nie można użyć „$1” do utworzenia tytułu strony",
        "htmlform-title-not-exists": "$1 nie istnieje.",
        "linkaccounts-success-text": "Konto zostało połączone.",
        "linkaccounts-submit": "Połącz konta",
        "unlinkaccounts": "Odłącz konta",
-       "unlinkaccounts-success": "Konta zostały odłączone."
+       "unlinkaccounts-success": "Konta zostały odłączone.",
+       "restrictionsfield-badip": "Nieprawidłowy adres IP lub zakres adresów: $1",
+       "restrictionsfield-label": "Dozwolone zakresy adresów IP:"
 }
index 915f629..610ebea 100644 (file)
        "feedback-external-bug-report-button": "A button for submitting an external technical bug report.",
        "feedback-dialog-title": "Title of the feedback dialog",
        "feedback-dialog-intro": "An introduction at the top of the feedback dialog. $1 - Feedback page link",
-       "feedback-error-title": "{{Identical|Error}}",
        "feedback-error1": "Error message, appears when an unknown error occurs submitting feedback",
        "feedback-error2": "Error message, appears when we could not add feedback",
        "feedback-error3": "Error message, appears when we lose our connection to the wiki",
index 5009a53..e237fd2 100644 (file)
        "password-change-forbidden": "Сез бу викидә серсүзне үзгәртә алмыйсыз.",
        "externaldberror": "Тышкы мәгълүмат базасы ярдәмендә аутентификация үткәндә хата чыкты, яисә тышкы хисап язмагызга үзгәрешләр кертү хокукыгыз юк.",
        "login": "Керү",
+       "login-security": "Шәхесегезне раслагыз",
        "nav-login-createaccount": "Керү / теркәлү",
        "userlogin": "Керү / теркәлү",
        "userloginnocreate": "Керү",
        "minoredit": "Бу кече үзгәртү",
        "watchthis": "Бу битне күзәтү",
        "savearticle": "Битне саклау",
+       "savechanges": "Үзгәртүләрне саклау",
+       "publishpage": "Бит ясау",
+       "publishchanges": "Битне бастыру",
        "preview": "Алдан карау",
        "showpreview": "Алдан карау",
        "showdiff": "Кертелгән үзгәртүләр",
        "exif-copyrighted": "Автор хокуклары халәте:",
        "exif-copyrightowner": "Автор хокуклары иясе",
        "exif-usageterms": "Куллану шартлары",
-       "exif-orientation-1": "Ð\9dоÑ\80малÑ\8c",
+       "exif-orientation-1": "Ð\93адÓ\99Ñ\82и",
        "exif-orientation-3": "180° ка борылган",
        "exif-componentsconfiguration-0": "юк",
        "exif-exposureprogram-0": "Билгесез",
index 71b389f..25b3d3d 100644 (file)
                        "Arystanbek",
                        "6ahodir",
                        "Таржимон",
-                       "Ximik1991"
+                       "Ximik1991",
+                       "Bmansurov"
                ]
        },
-       "tog-underline": "Havolalarning tagiga chizish:",
+       "tog-underline": "Havolaning tagiga chizish:",
        "tog-hideminor": "Yangi oʻzgarishlar roʻyxatida kichik tahrirlarni yashirish",
        "tog-hidepatrolled": "Yangi oʻzgarishlar roʻyxatida tekshirilgan tahrirlarni yashirish",
        "tog-newpageshidepatrolled": "Yangi sahifalar roʻyxatidan tekshirilgan sahifalarni yashirish",
        "tog-diffonly": "Versiyalar taqqoslanayotganda, pastda sahifa matni koʻrsatilmasin",
        "tog-showhiddencats": "Yashirin turkumlarni koʻrsatish",
        "tog-norollbackdiff": "Tahrir qaytarilganda, versiyalar taqqosi koʻrsatilmasin",
-       "tog-useeditwarning": "Oʻzgarishlarni saqlamay sahifadan chiqib ketayotganim haqida ogohlantirish",
+       "tog-useeditwarning": "Oʻzgarishlarni saqlamay sahifadan chiqib ketayotganim haqida ogohlantir",
        "tog-prefershttps": "Doim himoyalangan holda kirish",
        "underline-always": "Har doim",
        "underline-never": "Hech qachon",
-       "underline-default": "Brauzer moslamari boʻyicha",
+       "underline-default": "Bezak mavzusi yoki brauzer andozasi boʻyicha",
        "editfont-style": "Tahrirlash maydonidagi shrift turi:",
-       "editfont-default": "Brauzer moslamari boʻyicha",
+       "editfont-default": "Brauzer andozasi boʻyicha",
        "editfont-monospace": "Teng enli shrift (Monospaced)",
        "editfont-sansserif": "Kertiksiz shrift (Sans-serif)",
        "editfont-serif": "Kertikli shrift (Serif)",
        "oct": "Okt",
        "nov": "Noy",
        "dec": "Dek",
-       "january-date": "Yanvar $1",
-       "february-date": "Fevral $1",
-       "march-date": "Mart $1",
-       "april-date": "Aprel $1",
-       "may-date": "$1-may",
-       "june-date": "Iyun $1",
-       "july-date": "Iyul $1",
+       "january-date": "$1 yanvar",
+       "february-date": "$1 fevral",
+       "march-date": "$1 mart",
+       "april-date": "$1 aprel",
+       "may-date": "$1 may",
+       "june-date": "$1 iyun",
+       "july-date": "$1 iyul",
        "august-date": "Avgust $1",
        "september-date": "Sentabr $1",
        "october-date": "Oktabr $1",
        "yourpasswordagain": "Maxfiy so‘zni qayta kiriting:",
        "createacct-yourpasswordagain": "Maxfiy soʻzni tasdiqlang",
        "createacct-yourpasswordagain-ph": "Maxfiy soʻzni yana bir bor kiriting",
-       "remembermypassword": "Hisob ma’lumotlarim ushbu brauzerda eslab qolinsin (ko‘pi bilan $1 {{PLURAL:$1|kunga|kunga}})",
        "userlogin-remembermypassword": "Kirgan deb esda saqla",
        "userlogin-signwithsecure": "Himoyalangan holda kirish",
        "yourdomainname": "Sizning domeningiz:",
index 1ee2677..605f1fb 100644 (file)
        "htmlform-cloner-create": "添加更多",
        "htmlform-cloner-delete": "移除",
        "htmlform-cloner-required": "至少一个值是必需的。",
+       "htmlform-date-placeholder": "YYYY-MM-DD",
+       "htmlform-time-placeholder": "HH:MM:SS",
+       "htmlform-datetime-placeholder": "YYYY-MM-DD HH:MM:SS",
+       "htmlform-date-invalid": "您指定的值不是可识别的日期。尝试使用YYYY-MM-DD格式。",
+       "htmlform-time-invalid": "您指定的值不是可识别的时间。尝试使用HH:MM:SS格式。",
+       "htmlform-datetime-invalid": "您指定的值不是可识别的日期和时间。尝试使用YYYY-MM-DD HH:MM:SS格式。",
+       "htmlform-date-toolow": "您指定的值在$1的最早允许日期之前。",
+       "htmlform-date-toohigh": "您指定的值在$1的最晚允许日期之后。",
+       "htmlform-time-toolow": "您指定的值在$1的最早允许时间之前。",
+       "htmlform-time-toohigh": "您指定的值在$1的最晚允许时间之后。",
+       "htmlform-datetime-toolow": "您指定的值在$1的最早允许日期和时间之前。",
+       "htmlform-datetime-toohigh": "您指定的值在$1的最晚允许日期和时间之后。",
        "htmlform-title-badnamespace": "[[:$1]]不在“{{ns:$2}}”名字空间中。",
        "htmlform-title-not-creatable": "“$1”不是一个可创建的页面标题",
        "htmlform-title-not-exists": "$1不存在",
diff --git a/maintenance/archives/patch-change_tag-ct_id.sql b/maintenance/archives/patch-change_tag-ct_id.sql
new file mode 100644 (file)
index 0000000..7b986d6
--- /dev/null
@@ -0,0 +1,5 @@
+-- Primary key in change_tag table
+
+ALTER TABLE /*$wgDBprefix*/change_tag
+       ADD COLUMN ct_id INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
+       ADD PRIMARY KEY (ct_id);
diff --git a/maintenance/archives/patch-tag_summary-ts_id.sql b/maintenance/archives/patch-tag_summary-ts_id.sql
new file mode 100644 (file)
index 0000000..66fa72e
--- /dev/null
@@ -0,0 +1,5 @@
+-- Primary key in tag_summary table
+
+ALTER TABLE /*$wgDBprefix*/tag_summary
+       ADD COLUMN ts_id INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
+       ADD PRIMARY KEY (ts_id);
index b1e0fa4..3cc009e 100644 (file)
@@ -7,7 +7,6 @@ c2find|http://c2.com/cgi/wiki?FindPage&value=$1|0|
 cache|http://www.google.com/search?q=cache:$1|0|
 commons|https://commons.wikimedia.org/wiki/$1|0|https://commons.wikimedia.org/w/api.php
 dictionary|http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1|0|
-docbook|http://wiki.docbook.org/$1|0|
 doi|http://dx.doi.org/$1|0|
 drumcorpswiki|http://www.drumcorpswiki.com/$1|0|http://drumcorpswiki.com/api.php
 dwjwiki|http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1|0|
@@ -16,22 +15,18 @@ emacswiki|http://www.emacswiki.org/cgi-bin/wiki.pl?$1|0|
 foldoc|http://foldoc.org/?$1|0|
 foxwiki|http://fox.wikis.com/wc.dll?Wiki~$1|0|
 freebsdman|http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1|0|
-gej|http://www.esperanto.de/dej.malnova/aktivikio.pl?$1|0|
 gentoo-wiki|http://gentoo-wiki.com/$1|0|
 google|http://www.google.com/search?q=$1|0|
 googlegroups|http://groups.google.com/groups?q=$1|0|
 hammondwiki|http://www.dairiki.org/HammondWiki/$1|0|
 hrwiki|http://www.hrwiki.org/wiki/$1|0|http://www.hrwiki.org/w/api.php
 imdb|http://www.imdb.com/find?q=$1&tt=on|0|
-jargonfile|http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1|0|
 kmwiki|http://kmwiki.wikispaces.com/$1|0|
 linuxwiki|http://linuxwiki.de/$1|0|
 lojban|http://mw.lojban.org/papri/$1|0|
 lqwiki|http://wiki.linuxquestions.org/wiki/$1|0|
-lugkr|http://www.lug-kr.de/wiki/$1|0|
 meatball|http://www.usemod.com/cgi-bin/mb.pl?$1|0|
 mediawikiwiki|https://www.mediawiki.org/wiki/$1|0|https://www.mediawiki.org/w/api.php
-mediazilla|https://bugzilla.wikimedia.org/$1|0|
 memoryalpha|http://en.memory-alpha.org/wiki/$1|0|http://en.memory-alpha.org/api.php
 metawiki|http://sunir.org/apps/meta.pl?$1|0|
 metawikimedia|https://meta.wikimedia.org/wiki/$1|0|https://meta.wikimedia.org/w/api.php
@@ -39,25 +34,20 @@ mozillawiki|http://wiki.mozilla.org/$1|0|https://wiki.mozilla.org/api.php
 mw|https://www.mediawiki.org/wiki/$1|0|https://www.mediawiki.org/w/api.php
 oeis|http://oeis.org/$1|0|
 openwiki|http://openwiki.com/ow.asp?$1|0|
-ppr|http://c2.com/cgi/wiki?$1|0|
 pythoninfo|http://wiki.python.org/moin/$1|0|
 rfc|http://www.rfc-editor.org/rfc/rfc$1.txt|0|
 s23wiki|http://s23.org/wiki/$1|0|http://s23.org/w/api.php
 seattlewireless|http://seattlewireless.net/$1|0|
 senseislibrary|http://senseis.xmp.net/?$1|0|
 shoutwiki|http://www.shoutwiki.com/wiki/$1|0|http://www.shoutwiki.com/w/api.php
-sourcewatch|http://www.sourcewatch.org/index.php?title=$1|0|http://www.sourcewatch.org/api.php
 squeak|http://wiki.squeak.org/squeak/$1|0|
-tejo|http://www.tejo.org/vikio/$1|0|
 tmbw|http://www.tmbw.net/wiki/$1|0|http://tmbw.net/wiki/api.php
 tmnet|http://www.technomanifestos.net/?$1|0|
 theopedia|http://www.theopedia.com/$1|0|
 twiki|http://twiki.org/cgi-bin/view/$1|0|
-uea|http://uea.org/vikio/index.php/$1|0|http://uea.org/vikio/api.php
 uncyclopedia|http://en.uncyclopedia.co/wiki/$1|0|http://en.uncyclopedia.co/w/api.php
 unreal|http://wiki.beyondunreal.com/$1|0|http://wiki.beyondunreal.com/w/api.php
 usemod|http://www.usemod.com/cgi-bin/wiki.pl?$1|0|
-webseitzwiki|http://webseitz.fluxent.com/wiki/$1|0|
 wiki|http://c2.com/cgi/wiki?$1|0|
 wikia|http://www.wikia.com/wiki/$1|0|
 wikibooks|https://en.wikibooks.org/wiki/$1|0|https://en.wikibooks.org/w/api.php
index b7d1a84..0e0bb5c 100644 (file)
@@ -9,7 +9,6 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local,iw_api) VALUES
 ('cache','http://www.google.com/search?q=cache:$1',0,''),
 ('commons','https://commons.wikimedia.org/wiki/$1',0,'https://commons.wikimedia.org/w/api.php'),
 ('dictionary','http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1',0,''),
-('docbook','http://wiki.docbook.org/$1',0,''),
 ('doi','http://dx.doi.org/$1',0,''),
 ('drumcorpswiki','http://www.drumcorpswiki.com/$1',0,'http://drumcorpswiki.com/api.php'),
 ('dwjwiki','http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1',0,''),
@@ -18,22 +17,18 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local,iw_api) VALUES
 ('foldoc','http://foldoc.org/?$1',0,''),
 ('foxwiki','http://fox.wikis.com/wc.dll?Wiki~$1',0,''),
 ('freebsdman','http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1',0,''),
-('gej','http://www.esperanto.de/dej.malnova/aktivikio.pl?$1',0,''),
 ('gentoo-wiki','http://gentoo-wiki.com/$1',0,''),
 ('google','http://www.google.com/search?q=$1',0,''),
 ('googlegroups','http://groups.google.com/groups?q=$1',0,''),
 ('hammondwiki','http://www.dairiki.org/HammondWiki/$1',0,''),
 ('hrwiki','http://www.hrwiki.org/wiki/$1',0,'http://www.hrwiki.org/w/api.php'),
 ('imdb','http://www.imdb.com/find?q=$1&tt=on',0,''),
-('jargonfile','http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1',0,''),
 ('kmwiki','http://kmwiki.wikispaces.com/$1',0,''),
 ('linuxwiki','http://linuxwiki.de/$1',0,''),
 ('lojban','http://www.lojban.org/tiki/tiki-index.php?page=$1',0,''),
 ('lqwiki','http://wiki.linuxquestions.org/wiki/$1',0,''),
-('lugkr','http://www.lug-kr.de/wiki/$1',0,''),
 ('meatball','http://www.usemod.com/cgi-bin/mb.pl?$1',0,''),
 ('mediawikiwiki','https://www.mediawiki.org/wiki/$1',0,'https://www.mediawiki.org/w/api.php'),
-('mediazilla','https://bugzilla.wikimedia.org/$1',0,''),
 ('memoryalpha','http://en.memory-alpha.org/wiki/$1',0,'http://en.memory-alpha.org/api.php'),
 ('metawiki','http://sunir.org/apps/meta.pl?$1',0,''),
 ('metawikimedia','https://meta.wikimedia.org/wiki/$1',0,'https://meta.wikimedia.org/w/api.php'),
@@ -41,25 +36,20 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local,iw_api) VALUES
 ('mw','https://www.mediawiki.org/wiki/$1',0,'https://www.mediawiki.org/w/api.php'),
 ('oeis','http://oeis.org/$1',0,''),
 ('openwiki','http://openwiki.com/ow.asp?$1',0,''),
-('ppr','http://c2.com/cgi/wiki?$1',0,''),
 ('pythoninfo','http://wiki.python.org/moin/$1',0,''),
 ('rfc','http://www.rfc-editor.org/rfc/rfc$1.txt',0,''),
 ('s23wiki','http://s23.org/wiki/$1',0,'http://s23.org/w/api.php'),
 ('seattlewireless','http://seattlewireless.net/$1',0,''),
 ('senseislibrary','http://senseis.xmp.net/?$1',0,''),
 ('shoutwiki','http://www.shoutwiki.com/wiki/$1',0,'http://www.shoutwiki.com/w/api.php'),
-('sourcewatch','http://www.sourcewatch.org/index.php?title=$1',0,'http://www.sourcewatch.org/api.php'),
 ('squeak','http://wiki.squeak.org/squeak/$1',0,''),
-('tejo','http://www.tejo.org/vikio/$1',0,''),
 ('tmbw','http://www.tmbw.net/wiki/$1',0,'http://tmbw.net/wiki/api.php'),
 ('tmnet','http://www.technomanifestos.net/?$1',0,''),
 ('theopedia','http://www.theopedia.com/$1',0,''),
 ('twiki','http://twiki.org/cgi-bin/view/$1',0,''),
-('uea','http://uea.org/vikio/index.php/$1',0,'http://uea.org/vikio/api.php'),
 ('uncyclopedia','http://en.uncyclopedia.co/wiki/$1',0,'http://en.uncyclopedia.co/w/api.php'),
 ('unreal','http://wiki.beyondunreal.com/$1',0,'http://wiki.beyondunreal.com/w/api.php'),
 ('usemod','http://www.usemod.com/cgi-bin/wiki.pl?$1',0,''),
-('webseitzwiki','http://webseitz.fluxent.com/wiki/$1',0,''),
 ('wiki','http://c2.com/cgi/wiki?$1',0,''),
 ('wikia','http://www.wikia.com/wiki/$1',0,''),
 ('wikibooks','https://en.wikibooks.org/wiki/$1',0,'https://en.wikibooks.org/w/api.php'),
diff --git a/maintenance/mssql/archives/patch-change_tag-ct_id.sql b/maintenance/mssql/archives/patch-change_tag-ct_id.sql
new file mode 100644 (file)
index 0000000..94cb9d1
--- /dev/null
@@ -0,0 +1,4 @@
+-- Primary key in change_tag table
+
+ALTER TABLE /*_*/change_tag ADD ct_id INT IDENTITY;
+ALTER TABLE /*_*/change_tag ADD CONSTRAINT pk_change_tag PRIMARY KEY(ct_id)
diff --git a/maintenance/mssql/archives/patch-tag_summary-ts_id.sql b/maintenance/mssql/archives/patch-tag_summary-ts_id.sql
new file mode 100644 (file)
index 0000000..d62bd35
--- /dev/null
@@ -0,0 +1,4 @@
+-- Primary key in tag_summary table
+
+ALTER TABLE /*_*/tag_summary ADD ts_id INT IDENTITY;
+ALTER TABLE /*_*/tag_summary ADD CONSTRAINT pk_tag_summary PRIMARY KEY(ts_id)
index ea087a6..beb9727 100644 (file)
@@ -1193,6 +1193,7 @@ CREATE TABLE /*_*/updatelog (
 
 -- A table to track tags for revisions, logs and recent changes.
 CREATE TABLE /*_*/change_tag (
+  ct_id int NOT NULL PRIMARY KEY IDENTITY,
   -- RCID for the change
   ct_rc_id int NULL REFERENCES /*_*/recentchanges(rc_id),
   -- LOGID for the change
@@ -1215,6 +1216,7 @@ CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_i
 -- Rollup table to pull a LIST of tags simply without ugly GROUP_CONCAT
 -- that only works on MySQL 4.1+
 CREATE TABLE /*_*/tag_summary (
+  ts_id int NOT NULL PRIMARY KEY IDENTITY,
   -- RCID for the change
   ts_rc_id int NULL REFERENCES /*_*/recentchanges(rc_id),
   -- LOGID for the change
diff --git a/maintenance/oracle/archives/patch-change_tag-ct_id.sql b/maintenance/oracle/archives/patch-change_tag-ct_id.sql
new file mode 100644 (file)
index 0000000..6672872
--- /dev/null
@@ -0,0 +1,6 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.change_tag ADD (
+ct_id NUMBER NOT NULL,
+);
+ALTER TABLE &mw_prefix.change_tag ADD CONSTRAINT &mw_prefix.change_tag_pk PRIMARY KEY (ct_id);
diff --git a/maintenance/oracle/archives/patch-tag_summary-ts_id.sql b/maintenance/oracle/archives/patch-tag_summary-ts_id.sql
new file mode 100644 (file)
index 0000000..91c3338
--- /dev/null
@@ -0,0 +1,6 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.tag_summary ADD (
+ts_id NUMBER NOT NULL,
+);
+ALTER TABLE &mw_prefix.tag_summary ADD CONSTRAINT &mw_prefix.tag_summary_pk PRIMARY KEY (ts_id);
index d9369c9..616b401 100644 (file)
@@ -616,23 +616,27 @@ CREATE TABLE &mw_prefix.updatelog (
 ALTER TABLE &mw_prefix.updatelog ADD CONSTRAINT &mw_prefix.updatelog_pk PRIMARY KEY (ul_key);
 
 CREATE TABLE &mw_prefix.change_tag (
+  ct_id NUMBER NOT NULL,
   ct_rc_id NUMBER NULL,
   ct_log_id NUMBER NULL,
   ct_rev_id NUMBER NULL,
   ct_tag VARCHAR2(255) NOT NULL,
   ct_params BLOB NULL
 );
+ALTER TABLE &mw_prefix.change_tag ADD CONSTRAINT &mw_prefix.change_tag_pk PRIMARY KEY (ct_id);
 CREATE UNIQUE INDEX &mw_prefix.change_tag_u01 ON &mw_prefix.change_tag (ct_rc_id,ct_tag);
 CREATE UNIQUE INDEX &mw_prefix.change_tag_u02 ON &mw_prefix.change_tag (ct_log_id,ct_tag);
 CREATE UNIQUE INDEX &mw_prefix.change_tag_u03 ON &mw_prefix.change_tag (ct_rev_id,ct_tag);
 CREATE INDEX &mw_prefix.change_tag_i01 ON &mw_prefix.change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
 
 CREATE TABLE &mw_prefix.tag_summary (
+  ts_id NUMBER NOT NULL,
   ts_rc_id NUMBER NULL,
   ts_log_id NUMBER NULL,
   ts_rev_id NUMBER NULL,
   ts_tags BLOB NOT NULL
 );
+ALTER TABLE &mw_prefix.tag_summary ADD CONSTRAINT &mw_prefix.tag_summary_pk PRIMARY KEY (ts_id);
 CREATE UNIQUE INDEX &mw_prefix.tag_summary_u01 ON &mw_prefix.tag_summary (ts_rc_id);
 CREATE UNIQUE INDEX &mw_prefix.tag_summary_u02 ON &mw_prefix.tag_summary (ts_log_id);
 CREATE UNIQUE INDEX &mw_prefix.tag_summary_u03 ON &mw_prefix.tag_summary (ts_rev_id);
index 95c87c0..2273761 100644 (file)
@@ -25,6 +25,8 @@ DROP SEQUENCE IF EXISTS category_cat_id_seq CASCADE;
 DROP SEQUENCE IF EXISTS archive_ar_id_seq CASCADE;
 DROP SEQUENCE IF EXISTS externallinks_el_id_seq CASCADE;
 DROP SEQUENCE IF EXISTS sites_site_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS change_tag_ct_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS tag_summary_ts_id_seq CASCADE;
 DROP FUNCTION IF EXISTS page_deleted() CASCADE;
 DROP FUNCTION IF EXISTS ts2_page_title() CASCADE;
 DROP FUNCTION IF EXISTS ts2_page_text() CASCADE;
@@ -653,7 +655,9 @@ CREATE TABLE category (
 CREATE UNIQUE INDEX category_title ON category(cat_title);
 CREATE INDEX category_pages ON category(cat_pages);
 
+CREATE SEQUENCE change_tag_ct_id_seq;
 CREATE TABLE change_tag (
+  ct_id      INTEGER  NOT NULL  PRIMARY KEY DEFAULT nextval('change_tag_ct_id_seq'),
   ct_rc_id   INTEGER      NULL,
   ct_log_id  INTEGER      NULL,
   ct_rev_id  INTEGER      NULL,
@@ -665,11 +669,13 @@ CREATE UNIQUE INDEX change_tag_log_tag ON change_tag(ct_log_id,ct_tag);
 CREATE UNIQUE INDEX change_tag_rev_tag ON change_tag(ct_rev_id,ct_tag);
 CREATE INDEX change_tag_tag_id ON change_tag(ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
 
+CREATE SEQUENCE tag_summary_ts_id_seq;
 CREATE TABLE tag_summary (
-  ts_rc_id   INTEGER     NULL,
-  ts_log_id  INTEGER     NULL,
-  ts_rev_id  INTEGER     NULL,
-  ts_tags    TEXT    NOT NULL
+  ts_id      INTEGER  NOT NULL  PRIMARY KEY DEFAULT nextval('tag_summary_ts_id_seq'),
+  ts_rc_id   INTEGER      NULL,
+  ts_log_id  INTEGER      NULL,
+  ts_rev_id  INTEGER      NULL,
+  ts_tags    TEXT     NOT NULL
 );
 CREATE UNIQUE INDEX tag_summary_rc_id ON tag_summary(ts_rc_id);
 CREATE UNIQUE INDEX tag_summary_log_id ON tag_summary(ts_log_id);
index a9a982c..cc976ed 100644 (file)
@@ -91,7 +91,7 @@ class MwSql extends Maintenance {
                                $this->error( "Unable to open input file", true );
                        }
 
-                       $error = $db->sourceStream( $file, false, [ $this, 'sqlPrintResult' ] );
+                       $error = $db->sourceStream( $file, null, [ $this, 'sqlPrintResult' ] );
                        if ( $error !== true ) {
                                $this->error( $error, true );
                        } else {
diff --git a/maintenance/sqlite/archives/patch-change_tag-ct_id.sql b/maintenance/sqlite/archives/patch-change_tag-ct_id.sql
new file mode 100644 (file)
index 0000000..1c01094
--- /dev/null
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS /*_*/change_tag_tmp;
+
+CREATE TABLE /*$wgDBprefix*/change_tag_tmp (
+  ct_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+  ct_rc_id int NULL,
+  ct_log_id int NULL,
+  ct_rev_id int NULL,
+  ct_tag varchar(255) NOT NULL,
+  ct_params blob NULL
+);
+
+INSERT OR IGNORE INTO /*_*/change_tag_tmp (
+    ct_rc_id, ct_log_id, ct_rev_id, ct_tag, ct_params )
+    SELECT
+    ct_rc_id, ct_log_id, ct_rev_id, ct_tag, ct_params
+    FROM /*_*/change_tag;
+
+DROP TABLE /*_*/change_tag;
+
+ALTER TABLE /*_*/change_tag_tmp RENAME TO /*_*/change_tag;
+
+CREATE UNIQUE INDEX /*i*/change_tag_rc_tag ON /*_*/change_tag (ct_rc_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_log_tag ON /*_*/change_tag (ct_log_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_rev_tag ON /*_*/change_tag (ct_rev_id,ct_tag);
+CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
diff --git a/maintenance/sqlite/archives/patch-tag_summary-ts_id.sql b/maintenance/sqlite/archives/patch-tag_summary-ts_id.sql
new file mode 100644 (file)
index 0000000..b6a1202
--- /dev/null
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS /*_*/tag_summary_tmp;
+
+CREATE TABLE /*$wgDBprefix*/tag_summary_tmp (
+  ts_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+  ts_rc_id int NULL,
+  ts_log_id int NULL,
+  ts_rev_id int NULL,
+  ts_tags blob NOT NULL
+);
+
+INSERT OR IGNORE INTO /*_*/tag_summary_tmp (
+    ts_rc_id, ts_log_id, ts_rev_id, ts_tags )
+    SELECT
+    ts_rc_id, ts_log_id, ts_rev_id, ts_tags
+    FROM /*_*/tag_summary;
+
+DROP TABLE /*_*/tag_summary;
+
+ALTER TABLE /*_*/tag_summary_tmp RENAME TO /*_*/tag_summary;
+
+CREATE UNIQUE INDEX /*i*/tag_summary_rc_id ON /*_*/tag_summary (ts_rc_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_log_id ON /*_*/tag_summary (ts_log_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_rev_id ON /*_*/tag_summary (ts_rev_id);
index b5c14e3..03ce508 100644 (file)
@@ -1472,6 +1472,7 @@ CREATE TABLE /*_*/updatelog (
 
 -- A table to track tags for revisions, logs and recent changes.
 CREATE TABLE /*_*/change_tag (
+  ct_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
   -- RCID for the change
   ct_rc_id int NULL,
   -- LOGID for the change
@@ -1494,6 +1495,7 @@ CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_i
 -- Rollup table to pull a LIST of tags simply without ugly GROUP_CONCAT
 -- that only works on MySQL 4.1+
 CREATE TABLE /*_*/tag_summary (
+  ts_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
   -- RCID for the change
   ts_rc_id int NULL,
   -- LOGID for the change
index b81fbde..32a754f 100644 (file)
@@ -1020,7 +1020,6 @@ return [
                        'feedback-cancel',
                        'feedback-close',
                        'feedback-dialog-title',
-                       'feedback-error-title',
                        'feedback-error1',
                        'feedback-error2',
                        'feedback-error3',
index 594cea2..d72957d 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:02Z
+ * Date: 2016-10-03T18:59:01Z
  */
 ( function ( OO ) {
 
index 6437ca8..2f811da 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-element-hidden {
        display: none !important;
@@ -406,6 +406,10 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
        max-width: 100%;
        padding: 0;
        white-space: normal;
+       float: left;
+}
+.oo-ui-fieldsetLayout-group {
+       clear: both;
 }
 .oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help {
        float: right;
index 08d91b4..9a3d7eb 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-element-hidden {
        display: none !important;
@@ -529,6 +529,10 @@ body:not( :-moz-handler-blocked ) .oo-ui-fieldsetLayout {
        max-width: 100%;
        padding: 0;
        white-space: normal;
+       float: left;
+}
+.oo-ui-fieldsetLayout-group {
+       clear: both;
 }
 .oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help {
        float: right;
index c982010..109645b 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:02Z
+ * Date: 2016-10-03T18:59:01Z
  */
 ( function ( OO ) {
 
@@ -10121,6 +10121,7 @@ OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
        }
 
        // Initialization
+       this.$group.addClass( 'oo-ui-fieldsetLayout-group' );
        this.$element
                .addClass( 'oo-ui-fieldsetLayout' )
                .prepend( this.$label, this.$help, this.$icon, this.$group );
index 343508c..616f78e 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:02Z
+ * Date: 2016-10-03T18:59:01Z
  */
 ( function ( OO ) {
 
index 9c9954e..d6ed767 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-popupTool .oo-ui-popupWidget-popup,
 .oo-ui-popupTool .oo-ui-popupWidget-anchor {
index a413005..411c6bb 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-tool.oo-ui-widget-enabled {
        -webkit-transition: background-color 100ms;
index ba959cf..822b2d9 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:02Z
+ * Date: 2016-10-03T18:59:01Z
  */
 ( function ( OO ) {
 
index bd8034d..2d2b200 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-draggableElement-handle,
 .oo-ui-draggableElement-handle.oo-ui-widget {
index 126b591..d1b4225 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-draggableElement-handle,
 .oo-ui-draggableElement-handle.oo-ui-widget {
index 62195df..636e3f5 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:02Z
+ * Date: 2016-10-03T18:59:01Z
  */
 ( function ( OO ) {
 
index 3cff8f7..1cceac5 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-actionWidget.oo-ui-pendingElement-pending {
        background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
index 2c115f9..38e40b9 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:06Z
+ * Date: 2016-10-03T18:59:06Z
  */
 .oo-ui-window {
        background: transparent;
index 8ef5ea5..0a29b8b 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.17.9
+ * OOjs UI v0.17.10
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2016 OOjs UI Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2016-09-13T18:30:02Z
+ * Date: 2016-10-03T18:59:01Z
  */
 ( function ( OO ) {
 
index 46b6aec..0b3ea04 100644 (file)
                                        ]
                                };
                                break;
-                       case 'error1':
-                       case 'error2':
-                       case 'error3':
-                       case 'error4':
-                               dialogConfig = {
-                                       title: mw.msg( 'feedback-error-title' ),
-                                       message: mw.msg( 'feedback-' + status ),
-                                       actions: [
-                                               {
-                                                       action: 'accept',
-                                                       label: mw.msg( 'feedback-close' ),
-                                                       flags: 'primary'
-                                               }
-                                       ]
-                               };
-                               break;
                }
 
                // Show the message dialog
                                }, function () {
                                        fb.status = 'error4';
                                        mw.log.warn( 'Feedback report failed because MessagePoster could not be fetched' );
-                               } ).always( function () {
+                               } ).then( function () {
                                        fb.close();
+                               }, function () {
+                                       return fb.getErrorMessage();
                                } );
                        }, this );
                }
                return mw.Feedback.Dialog.parent.prototype.getActionProcess.call( this, action );
        };
 
+       /**
+        * Returns an error message for the current status.
+        *
+        * @private
+        *
+        * @return {OO.ui.Error}
+        */
+       mw.Feedback.Dialog.prototype.getErrorMessage = function () {
+               switch ( this.status ) {
+                       case 'error1':
+                       case 'error2':
+                       case 'error3':
+                       case 'error4':
+                               // Messages: feedback-error1, feedback-error2, feedback-error3, feedback-error4
+                               return new OO.ui.Error( mw.msg( 'feedback-' + this.status ) );
+               }
+       };
+
        /**
         * Posts the message
         *
index 0f4484e..aed2d83 100644 (file)
@@ -43,7 +43,7 @@ class LBFactoryTest extends MediaWikiTestCase {
                ];
 
                $this->hideDeprecated( '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details' );
-               $result = LBFactoryMW::getLBFactoryClass( $config );
+               $result = MWLBFactory::getLBFactoryClass( $config );
 
                $this->assertEquals( $expected, $result );
        }
index 6eb96b1..881f5e1 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /**
  * A MemoizedCallable subclass that stores function return values
- * in an instance property rather than APC.
+ * in an instance property rather than APC or APCu.
  */
 class ArrayBackedMemoizedCallable extends MemoizedCallable {
        private $cache = [];
@@ -44,7 +44,7 @@ class MemoizedCallableTest extends PHPUnit_Framework_TestCase {
         * Consecutive calls to the memoized callable with the same arguments
         * should result in just one invocation of the underlying callable.
         *
-        * @requires function apc_store
+        * @requires function apc_store/apcu_store
         */
        public function testCallableMemoized() {
                $observer = $this->getMock( 'stdClass', [ 'computeSomething' ] );
diff --git a/tests/phpunit/includes/libs/WaitConditionLoopTest.php b/tests/phpunit/includes/libs/WaitConditionLoopTest.php
deleted file mode 100644 (file)
index 9ce93d6..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-<?php
-
-class WaitConditionLoopFakeTime extends WaitConditionLoop {
-       protected $wallClock = 1;
-
-       function __construct( callable $condition, $timeout, array $busyCallbacks ) {
-               parent::__construct( $condition, $timeout, $busyCallbacks );
-       }
-
-       function usleep( $microseconds ) {
-               $this->wallClock += $microseconds / 1e6;
-       }
-
-       function getCpuTime() {
-               return 0.0;
-       }
-
-       function getWallTime() {
-               return $this->wallClock;
-       }
-
-       public function setWallClock( &$timestamp ) {
-               $this->wallClock =& $timestamp;
-       }
-}
-
-class WaitConditionLoopTest extends PHPUnit_Framework_TestCase {
-       public function testCallbackReached() {
-               $wallClock = microtime( true );
-
-               $count = 0;
-               $status = new StatusValue();
-               $loop = new WaitConditionLoopFakeTime(
-                       function () use ( &$count, $status ) {
-                               ++$count;
-                               $status->value = 'cookie';
-
-                               return WaitConditionLoop::CONDITION_REACHED;
-                       },
-                       10.0,
-                       $this->newBusyWork( $x, $y, $z )
-               );
-               $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke() );
-               $this->assertEquals( 1, $count );
-               $this->assertEquals( 'cookie', $status->value );
-               $this->assertEquals( [ 0, 0, 0 ], [ $x, $y, $z ], "No busy work done" );
-
-               $count = 0;
-               $loop = new WaitConditionLoopFakeTime(
-                       function () use ( &$count, &$wallClock ) {
-                               $wallClock += 1;
-                               ++$count;
-
-                               return $count >= 2 ? WaitConditionLoop::CONDITION_REACHED : false;
-                       },
-                       7.0,
-                       $this->newBusyWork( $x, $y, $z, $wallClock )
-               );
-               $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke(),
-                       "Busy work did not cause timeout" );
-               $this->assertEquals( [ 1, 0, 0 ], [ $x, $y, $z ] );
-
-               $count = 0;
-               $loop = new WaitConditionLoopFakeTime(
-                       function () use ( &$count, &$wallClock ) {
-                               $wallClock += .1;
-                               ++$count;
-
-                               return $count > 80 ? true : false;
-                       },
-                       50.0,
-                       $this->newBusyWork( $x, $y, $z, $wallClock, $dontCallMe, $badCalls )
-               );
-               $this->assertEquals( 0, $badCalls, "Callback exception not yet called" );
-               $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke() );
-               $this->assertEquals( [ 1, 1, 1 ], [ $x, $y, $z ], "Busy work done" );
-               $this->assertEquals( 1, $badCalls, "Bad callback ran and was exception caught" );
-
-               try {
-                       $e = null;
-                       $dontCallMe();
-               } catch ( Exception $e ) {
-               }
-
-               $this->assertInstanceOf( 'RunTimeException', $e );
-               $this->assertEquals( 1, $badCalls, "Callback exception cached" );
-       }
-
-       public function testCallbackTimeout() {
-               $count = 0;
-               $wallClock = microtime( true );
-               $loop = new WaitConditionLoopFakeTime(
-                       function () use ( &$count, &$wallClock ) {
-                               $wallClock += 3;
-                               ++$count;
-
-                               return $count > 300 ? true : false;
-                       },
-                       50.0,
-                       $this->newBusyWork( $x, $y, $z, $wallClock )
-               );
-               $loop->setWallClock( $wallClock );
-               $this->assertEquals( $loop::CONDITION_TIMED_OUT, $loop->invoke() );
-               $this->assertEquals( [ 1, 1, 1 ], [ $x, $y, $z ], "Busy work done" );
-
-               $loop = new WaitConditionLoopFakeTime(
-                       function () use ( &$count, &$wallClock ) {
-                               $wallClock += 3;
-                               ++$count;
-
-                               return true;
-                       },
-                       0.0,
-                       $this->newBusyWork( $x, $y, $z, $wallClock )
-               );
-               $this->assertEquals( $loop::CONDITION_REACHED, $loop->invoke() );
-
-               $count = 0;
-               $loop = new WaitConditionLoopFakeTime(
-                       function () use ( &$count, &$wallClock ) {
-                               $wallClock += 3;
-                               ++$count;
-
-                               return $count > 10 ? true : false;
-                       },
-                       0,
-                       $this->newBusyWork( $x, $y, $z, $wallClock )
-               );
-               $this->assertEquals( $loop::CONDITION_FAILED, $loop->invoke() );
-       }
-
-       public function testCallbackAborted() {
-               $x = 0;
-               $wallClock = microtime( true );
-               $loop = new WaitConditionLoopFakeTime(
-                       function () use ( &$x, &$wallClock ) {
-                               $wallClock += 2;
-                               ++$x;
-
-                               return $x > 2 ? WaitConditionLoop::CONDITION_ABORTED : false;
-                       },
-                       10.0,
-                       $this->newBusyWork( $x, $y, $z, $wallClock )
-               );
-               $loop->setWallClock( $wallClock );
-               $this->assertEquals( $loop::CONDITION_ABORTED, $loop->invoke() );
-       }
-
-       private function newBusyWork(
-               &$x, &$y, &$z, &$wallClock = 1, &$dontCallMe = null, &$badCalls = 0
-       ) {
-               $x = $y = $z = 0;
-               $badCalls = 0;
-
-               $list = [];
-               $list[] = function () use ( &$x, &$wallClock ) {
-                       $wallClock += 1;
-
-                       return ++$x;
-               };
-               $dontCallMe = function () use ( &$badCalls ) {
-                       ++$badCalls;
-                       throw new RuntimeException( "TrollyMcTrollFace" );
-               };
-               $list[] =& $dontCallMe;
-               $list[] = function () use ( &$y, &$wallClock ) {
-                       $wallClock += 15;
-
-                       return ++$y;
-               };
-               $list[] = function () use ( &$z, &$wallClock ) {
-                       $wallClock += 0.1;
-
-                       return ++$z;
-               };
-
-               return $list;
-       }
-}