Merge "Make sure that the temp zone has an .htaccess file"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 6 Nov 2014 19:09:43 +0000 (19:09 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 6 Nov 2014 19:09:43 +0000 (19:09 +0000)
43 files changed:
.rubocop.yml
RELEASE-NOTES-1.25
composer.json
docs/hooks.txt
includes/AutoLoader.php
includes/CategoryViewer.php
includes/Cookie.php [deleted file]
includes/EditPage.php
includes/api/i18n/cs.json
includes/api/i18n/es.json
includes/api/i18n/fy.json [new file with mode: 0644]
includes/api/i18n/ja.json
includes/api/i18n/mk.json
includes/api/i18n/vi.json
includes/api/i18n/zh-hans.json
includes/db/Database.php
includes/installer/i18n/fy.json
includes/installer/i18n/nap.json
includes/libs/ArrayUtils.php [new file with mode: 0644]
includes/libs/CSSJanus.php [deleted file]
includes/libs/Cookie.php [new file with mode: 0644]
includes/logging/LogEventsList.php
includes/page/Article.php
includes/profiler/Profiler.php
includes/profiler/ProfilerStandard.php
includes/profiler/ProfilerStub.php
includes/profiler/TransactionProfiler.php
includes/specials/SpecialNewimages.php
includes/specials/SpecialVersion.php
includes/upload/UploadBase.php
includes/utils/ArrayUtils.php [deleted file]
includes/utils/MWFunction.php
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/cdo.json
languages/i18n/el.json
languages/i18n/eo.json
languages/i18n/fy.json
languages/i18n/ms.json
languages/i18n/vi.json
languages/i18n/zh-hans.json
resources/Resources.php
resources/lib/oojs/oojs.jquery.js

index cc32da4..00479d1 100644 (file)
@@ -1 +1,8 @@
 inherit_from: .rubocop_todo.yml
+
+AllCops:
+    Exclude:
+        - 'extensions/**/*'
+        - 'skins/**/*'
+        - 'tests/frontend/node_modules/**/*'
+        - 'vendor/**/*'
index aa0d5a7..b649c2b 100644 (file)
@@ -180,6 +180,8 @@ changes to languages because of Bugzilla reports.
   tag, instead of after the <text> and <sha1> tags.
   The new schema version is 0.10, the new schema URI is
   <https://www.mediawiki.org/xml/export-0.10.xsd>.
+* MWFunction::call() and MWFunction::callArray() were removed, having being
+  deprecated in 1.22.
 
 == Compatibility ==
 
index 851ad41..61f30ce 100644 (file)
@@ -17,7 +17,8 @@
        },
        "require": {
                "php": ">=5.3.3",
-               "psr/log": "1.0.0"
+               "psr/log": "1.0.0",
+               "cssjanus/cssjanus": "1.1.0"
        },
        "require-dev": {
                "phpunit/phpunit": "*"
index 18b7099..0eb6572 100644 (file)
@@ -528,6 +528,10 @@ $error: if the deletion was prohibited, the (raw HTML) error message to display
 $status: Status object, modify this to throw an error. Overridden by $error
   (added in 1.20)
 
+'ArticleDeleteAfterSuccess': Output after an article has been deleted.
+$title: Title of the article that has been deleted.
+$outputPage: OutputPage that can be used to append the output.
+
 'ArticleDeleteComplete': After an article is deleted.
 $wikiPage: the WikiPage that was deleted
 $user: the user that deleted the article
index 172bd49..e89e500 100644 (file)
@@ -48,8 +48,6 @@ $wgAutoloadLocalClasses = array(
        'CollationCkb' => 'includes/Collation.php',
        'CollationEt' => 'includes/Collation.php',
        'ConcatenatedGzipHistoryBlob' => 'includes/HistoryBlob.php',
-       'Cookie' => 'includes/Cookie.php',
-       'CookieJar' => 'includes/Cookie.php',
        'CurlHttpRequest' => 'includes/HttpFunctions.php',
        'DeprecatedGlobal' => 'includes/DeprecatedGlobal.php',
        'DerivativeRequest' => 'includes/WebRequest.php',
@@ -675,8 +673,9 @@ $wgAutoloadLocalClasses = array(
        'FormatJson' => 'includes/json/FormatJson.php',
 
        # includes/libs
-       'CSSJanus' => 'includes/libs/CSSJanus.php',
-       'CSSJanusTokenizer' => 'includes/libs/CSSJanus.php',
+       'ArrayUtils' => 'includes/libs/ArrayUtils.php',
+       'Cookie' => 'includes/libs/Cookie.php',
+       'CookieJar' => 'includes/libs/Cookie.php',
        'CSSMin' => 'includes/libs/CSSMin.php',
        'GenericArrayObject' => 'includes/libs/GenericArrayObject.php',
        'HashRing' => 'includes/libs/HashRing.php',
@@ -1153,7 +1152,6 @@ $wgAutoloadLocalClasses = array(
        'UploadStashNoSuchKeyException' => 'includes/upload/UploadStash.php',
 
        # includes/utils
-       'ArrayUtils' => 'includes/utils/ArrayUtils.php',
        'CdbException' => 'includes/utils/Cdb.php',
        'CdbFunctions' => 'includes/utils/CdbPHP.php',
        'CdbReader' => 'includes/utils/Cdb.php',
index 7581ae4..f68da95 100644 (file)
@@ -136,7 +136,7 @@ class CategoryViewer extends ContextSource {
                }
 
                $lang = $this->getLanguage();
-               $langAttribs = array( 'lang' => $lang->getCode(), 'dir' => $lang->getDir() );
+               $langAttribs = array( 'lang' => $lang->getHtmlCode(), 'dir' => $lang->getDir() );
                # put a div around the headings which are in the user language
                $r = Html::openElement( 'div', $langAttribs ) . $r . '</div>';
 
@@ -515,7 +515,7 @@ class CategoryViewer extends ContextSource {
                }
 
                $pageLang = $this->title->getPageLanguage();
-               $attribs = array( 'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(),
+               $attribs = array( 'lang' => $pageLang->getHtmlCode(), 'dir' => $pageLang->getDir(),
                        'class' => 'mw-content-' . $pageLang->getDir() );
                $list = Html::rawElement( 'div', $attribs, $list );
 
diff --git a/includes/Cookie.php b/includes/Cookie.php
deleted file mode 100644 (file)
index cb04190..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-<?php
-/**
- * Cookie for HTTP requests.
- *
- * 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 HTTP
- */
-
-class Cookie {
-       protected $name;
-       protected $value;
-       protected $expires;
-       protected $path;
-       protected $domain;
-       protected $isSessionKey = true;
-       // TO IMPLEMENT  protected $secure
-       // TO IMPLEMENT? protected $maxAge (add onto expires)
-       // TO IMPLEMENT? protected $version
-       // TO IMPLEMENT? protected $comment
-
-       function __construct( $name, $value, $attr ) {
-               $this->name = $name;
-               $this->set( $value, $attr );
-       }
-
-       /**
-        * Sets a cookie.  Used before a request to set up any individual
-        * cookies. Used internally after a request to parse the
-        * Set-Cookie headers.
-        *
-        * @param string $value The value of the cookie
-        * @param array $attr Possible key/values:
-        *        expires A date string
-        *        path    The path this cookie is used on
-        *        domain  Domain this cookie is used on
-        * @throws MWException
-        */
-       public function set( $value, $attr ) {
-               $this->value = $value;
-
-               if ( isset( $attr['expires'] ) ) {
-                       $this->isSessionKey = false;
-                       $this->expires = strtotime( $attr['expires'] );
-               }
-
-               if ( isset( $attr['path'] ) ) {
-                       $this->path = $attr['path'];
-               } else {
-                       $this->path = '/';
-               }
-
-               if ( isset( $attr['domain'] ) ) {
-                       if ( self::validateCookieDomain( $attr['domain'] ) ) {
-                               $this->domain = $attr['domain'];
-                       }
-               } else {
-                       throw new MWException( 'You must specify a domain.' );
-               }
-       }
-
-       /**
-        * Return the true if the cookie is valid is valid.  Otherwise,
-        * false.  The uses a method similar to IE cookie security
-        * described here:
-        * http://kuza55.blogspot.com/2008/02/understanding-cookie-security.html
-        * A better method might be to use a blacklist like
-        * http://publicsuffix.org/
-        *
-        * @todo fixme fails to detect 3-letter top-level domains
-        * @todo fixme fails to detect 2-letter top-level domains for single-domain use (probably
-        * not a big problem in practice, but there are test cases)
-        *
-        * @param string $domain The domain to validate
-        * @param string $originDomain (optional) the domain the cookie originates from
-        * @return bool
-        */
-       public static function validateCookieDomain( $domain, $originDomain = null ) {
-               $dc = explode( ".", $domain );
-
-               // Don't allow a trailing dot or addresses without a or just a leading dot
-               if ( substr( $domain, -1 ) == '.' ||
-                       count( $dc ) <= 1 ||
-                       count( $dc ) == 2 && $dc[0] === ''
-               ) {
-                       return false;
-               }
-
-               // Only allow full, valid IP addresses
-               if ( preg_match( '/^[0-9.]+$/', $domain ) ) {
-                       if ( count( $dc ) != 4 ) {
-                               return false;
-                       }
-
-                       if ( ip2long( $domain ) === false ) {
-                               return false;
-                       }
-
-                       if ( $originDomain == null || $originDomain == $domain ) {
-                               return true;
-                       }
-
-               }
-
-               // Don't allow cookies for "co.uk" or "gov.uk", etc, but allow "supermarket.uk"
-               if ( strrpos( $domain, "." ) - strlen( $domain ) == -3 ) {
-                       if ( ( count( $dc ) == 2 && strlen( $dc[0] ) <= 2 )
-                               || ( count( $dc ) == 3 && strlen( $dc[0] ) == "" && strlen( $dc[1] ) <= 2 ) ) {
-                               return false;
-                       }
-                       if ( ( count( $dc ) == 2 || ( count( $dc ) == 3 && $dc[0] == '' ) )
-                               && preg_match( '/(com|net|org|gov|edu)\...$/', $domain ) ) {
-                               return false;
-                       }
-               }
-
-               if ( $originDomain != null ) {
-                       if ( substr( $domain, 0, 1 ) != '.' && $domain != $originDomain ) {
-                               return false;
-                       }
-
-                       if ( substr( $domain, 0, 1 ) == '.'
-                               && substr_compare(
-                                       $originDomain,
-                                       $domain,
-                                       -strlen( $domain ),
-                                       strlen( $domain ),
-                                       true
-                               ) != 0
-                       ) {
-                               return false;
-                       }
-               }
-
-               return true;
-       }
-
-       /**
-        * Serialize the cookie jar into a format useful for HTTP Request headers.
-        *
-        * @param string $path The path that will be used. Required.
-        * @param string $domain The domain that will be used. Required.
-        * @return string
-        */
-       public function serializeToHttpRequest( $path, $domain ) {
-               $ret = '';
-
-               if ( $this->canServeDomain( $domain )
-                               && $this->canServePath( $path )
-                               && $this->isUnExpired() ) {
-                       $ret = $this->name . '=' . $this->value;
-               }
-
-               return $ret;
-       }
-
-       /**
-        * @param string $domain
-        * @return bool
-        */
-       protected function canServeDomain( $domain ) {
-               if ( $domain == $this->domain
-                       || ( strlen( $domain ) > strlen( $this->domain )
-                               && substr( $this->domain, 0, 1 ) == '.'
-                               && substr_compare(
-                                       $domain,
-                                       $this->domain,
-                                       -strlen( $this->domain ),
-                                       strlen( $this->domain ),
-                                       true
-                               ) == 0
-                       )
-               ) {
-                       return true;
-               }
-
-               return false;
-       }
-
-       /**
-        * @param string $path
-        * @return bool
-        */
-       protected function canServePath( $path ) {
-               return ( $this->path && substr_compare( $this->path, $path, 0, strlen( $this->path ) ) == 0 );
-       }
-
-       /**
-        * @return bool
-        */
-       protected function isUnExpired() {
-               return $this->isSessionKey || $this->expires > time();
-       }
-}
-
-class CookieJar {
-       private $cookie = array();
-
-       /**
-        * Set a cookie in the cookie jar. Make sure only one cookie per-name exists.
-        * @see Cookie::set()
-        * @param string $name
-        * @param string $value
-        * @param array $attr
-        */
-       public function setCookie( $name, $value, $attr ) {
-               /* cookies: case insensitive, so this should work.
-                * We'll still send the cookies back in the same case we got them, though.
-                */
-               $index = strtoupper( $name );
-
-               if ( isset( $this->cookie[$index] ) ) {
-                       $this->cookie[$index]->set( $value, $attr );
-               } else {
-                       $this->cookie[$index] = new Cookie( $name, $value, $attr );
-               }
-       }
-
-       /**
-        * @see Cookie::serializeToHttpRequest
-        * @param string $path
-        * @param string $domain
-        * @return string
-        */
-       public function serializeToHttpRequest( $path, $domain ) {
-               $cookies = array();
-
-               foreach ( $this->cookie as $c ) {
-                       $serialized = $c->serializeToHttpRequest( $path, $domain );
-
-                       if ( $serialized ) {
-                               $cookies[] = $serialized;
-                       }
-               }
-
-               return implode( '; ', $cookies );
-       }
-
-       /**
-        * Parse the content of an Set-Cookie HTTP Response header.
-        *
-        * @param string $cookie
-        * @param string $domain Cookie's domain
-        * @return null
-        */
-       public function parseCookieResponseHeader( $cookie, $domain ) {
-               $len = strlen( 'Set-Cookie:' );
-
-               if ( substr_compare( 'Set-Cookie:', $cookie, 0, $len, true ) === 0 ) {
-                       $cookie = substr( $cookie, $len );
-               }
-
-               $bit = array_map( 'trim', explode( ';', $cookie ) );
-
-               if ( count( $bit ) >= 1 ) {
-                       list( $name, $value ) = explode( '=', array_shift( $bit ), 2 );
-                       $attr = array();
-
-                       foreach ( $bit as $piece ) {
-                               $parts = explode( '=', $piece );
-                               if ( count( $parts ) > 1 ) {
-                                       $attr[strtolower( $parts[0] )] = $parts[1];
-                               } else {
-                                       $attr[strtolower( $parts[0] )] = true;
-                               }
-                       }
-
-                       if ( !isset( $attr['domain'] ) ) {
-                               $attr['domain'] = $domain;
-                       } elseif ( !Cookie::validateCookieDomain( $attr['domain'], $domain ) ) {
-                               return null;
-                       }
-
-                       $this->setCookie( $name, $value, $attr );
-               }
-       }
-}
index fa19c78..d106da2 100644 (file)
@@ -2956,7 +2956,7 @@ HTML
                );
 
                $pageLang = $this->mTitle->getPageLanguage();
-               $attribs['lang'] = $pageLang->getCode();
+               $attribs['lang'] = $pageLang->getHtmlCode();
                $attribs['dir'] = $pageLang->getDir();
 
                $wgOut->addHTML( Html::textarea( $name, $wikitext, $attribs ) );
index a0751b8..f8fbdc1 100644 (file)
@@ -15,7 +15,7 @@
        "apihelp-main-param-servedby": "Zahrnout do odpovědi název hostitele, který požadavek obsloužil.",
        "apihelp-main-param-curtimestamp": "Zahrnout do odpovědi aktuální časové razítko.",
        "apihelp-main-param-origin": "Pokud k API přistupujete pomocí mezidoménového AJAXového požadavku (CORS), nastavte tento parametr na doménu původu. Musí být součástí všech předběžných požadavků, takže musí být součástí URI požadavku (nikoli těla POSTu). Hodnota musí přesně odpovídat jednomu z původů v hlavičce Origin:, takže musí být nastavena na něco jako http://en.wikipedia.org nebo https://meta.wikimedia.org. Pokud parametr neodpovídá hlavičce Origin:, bude vrácena odpověď 403. Pokud parametr odpovídá hlavičce Origin: a tento původ je na bílé listině, bude nastavena hlavička Access-Control-Allow-Origin.",
-       "apihelp-main-param-uselang": "Jazyk, který se má použít pro překlad hlášení. Seznam kódů lze načíst z [[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo&siprop=languages]] nebo uveďte „user“ pro použití předvoleného jazyka aktuálního uživatele.",
+       "apihelp-main-param-uselang": "Jazyk, který se má použít pro překlad hlášení. Seznam kódů lze načíst z [[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]] se siprop=languages nebo uveďte „user“ pro použití předvoleného jazyka aktuálního uživatele či „content“ pro použití jazyka obsahu této wiki.",
        "apihelp-help-description": "Zobrazuje nápovědu k uvedeným modulům.",
        "apihelp-help-param-modules": "Moduly, pro které se má zobrazit nápověda (hodnoty parametrů action= a format= nebo „main“). Submoduly lze zadávat pomocí „+“.",
        "apihelp-help-param-submodules": "Zahrnout nápovědu pro submoduly uvedeného modulu.",
index 5768706..8e5ba53 100644 (file)
@@ -1,9 +1,13 @@
 {
        "@metadata": {
                "authors": [
-                       "Macofe"
+                       "Macofe",
+                       "Effy"
                ]
        },
+       "apihelp-createaccount-param-name": "Nombre de usuario.",
+       "apihelp-expandtemplates-param-title": "Título de la página.",
+       "apihelp-feedrecentchanges-param-hideminor": "Ocultar cambios menores.",
        "apihelp-query+allusers-param-activeusers": "Solo listar usuarios activos en {{PLURAL:$1|el último día|los $1 últimos días}}.",
        "apihelp-query+images-description": "Devuelve todos los archivos contenidos en las páginas dadas.",
        "apihelp-query+search-param-info": "Qué metadatos devolver.",
diff --git a/includes/api/i18n/fy.json b/includes/api/i18n/fy.json
new file mode 100644 (file)
index 0000000..8013687
--- /dev/null
@@ -0,0 +1,10 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Robin0van0der0vliet"
+               ]
+       },
+       "apihelp-login-param-name": "Brûkersnamme.",
+       "apihelp-login-param-password": "Wachtwurd.",
+       "apihelp-userrights-param-user": "Brûkersnamme."
+}
index ed02edf..46da945 100644 (file)
@@ -12,7 +12,7 @@
        "apihelp-main-param-requestid": "任意の値を指定でき、その値が結果に含められます。リクエストを識別するために使用できます。",
        "apihelp-main-param-servedby": "リクエストを処理したホスト名を結果に含めます。",
        "apihelp-main-param-curtimestamp": "現在のタイムスタンプを結果に含めます。",
-       "apihelp-main-param-uselang": "メッセージの翻訳に使用する言語です。言語の一覧は [[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo&siprop=languages]] から取得できます。\"user\" を指定することで、現在の利用者の個人設定の言語を使用することもできます。",
+       "apihelp-main-param-uselang": "メッセージの翻訳に使用する言語です。コードの一覧は [[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]] に siprop=languages を付けることで取得できます。\"user\" を指定することで現在の利用者の個人設定の言語を、\"content\" を指定することでこのウィキの本文の言語を使用することもできます。",
        "apihelp-help-description": "指定したモジュールのヘルプを表示します。",
        "apihelp-help-param-modules": "ヘルプを表示するモジュールです (action= パラメーターおよび format= パラメーターの値、または \"main\")。\"+\" を使用して下位モジュールを指定できます。",
        "apihelp-help-param-submodules": "指定したモジュールの下位モジュールのヘルプを含めます。",
index c6fcec7..ffd7079 100644 (file)
        "apihelp-query+backlinks-example-simple": "Прикажи врски до [[Главна страница|Главната страница]]",
        "apihelp-query+backlinks-example-generator": "Дава информации за страниците што водат до [[Главна страница|Главната страница]]",
        "apihelp-query+blocks-description": "Список на сите блокирани корисници и IP-адреси",
-       "apihelp-query+blocks-param-start": "Од кој датум и време да се почне набројувањето.",
+       "apihelp-query+blocks-param-start": "Од кој датум и време да почне набројувањето.",
        "apihelp-query+blocks-param-end": "На кој датум и време да запре набројувањето.",
        "apihelp-query+blocks-param-ids": "Список на назнаки на блоковите за испис (незадолжително)",
        "apihelp-query+blocks-param-users": "Список на корисници што ќе се пребаруваат (незадолжително)",
index ab1a1e5..30211af 100644 (file)
        "apihelp-emailuser-param-text": "Nội dung bức thư.",
        "apihelp-emailuser-param-ccme": "Gửi bản sao của thư này cho tôi.",
        "apihelp-emailuser-example-email": "Gửi thư điện tử cho thành viên “BQVWiki” với văn bản “Nội dung”",
-       "apihelp-expandtemplates-description": "Bung các bản mẫu trong văn bản wiki.",
+       "apihelp-expandtemplates-description": "Bung tất cả bản mẫu trong văn bản wiki.",
        "apihelp-expandtemplates-param-title": "Tên trang.",
-       "apihelp-expandtemplates-param-text": "Văn bản wiki để chuyển đổi.",
+       "apihelp-expandtemplates-param-text": "Văn bản wiki để bung.",
        "apihelp-help-param-helpformat": "Định dạng của văn bản trợ giúp được cho ra.",
        "apihelp-imagerotate-example-simple": "Xoay [[:Tập tin:Ví dụ.jpg]] 90 độ",
-       "apihelp-imagerotate-example-generator": "Xoay tất cả các hình ảnh trong [[:Category:Flip]] 180 độ",
+       "apihelp-imagerotate-example-generator": "Xoay tất cả các hình ảnh trong [[:Thể loại:Búng]] 180 độ",
        "apihelp-login-param-name": "Tên người dùng.",
        "apihelp-login-param-password": "Mật khẩu.",
        "apihelp-login-param-domain": "Tên miền (tùy chọn).",
-       "apihelp-login-param-token": "Token đăng nhập được lấy trong yêu cầu đầu tiên.",
-       "apihelp-login-example-gettoken": "Lấy Token đăng nhập",
+       "apihelp-login-param-token": "Dấu hiệu đăng nhập được lấy trong yêu cầu đầu tiên.",
+       "apihelp-login-example-gettoken": "Lấy dấu hiệu đăng nhập",
        "apihelp-login-example-login": "Đăng nhập",
        "apihelp-logout-example-logout": "Đăng xuất người dùng hiện tại",
        "apihelp-move-description": "Di chuyển trang.",
@@ -62,7 +62,7 @@
        "apihelp-move-param-noredirect": "Không tạo trang đổi hướng.",
        "apihelp-move-param-ignorewarnings": "Bỏ qua tất cả các cảnh báo.",
        "apihelp-opensearch-description": "Tìm kiếm trong wiki qua giao thức OpenSearch.",
-       "apihelp-opensearch-param-search": "Chuỗi để tìm kiếm.",
+       "apihelp-opensearch-param-search": "Chuỗi tìm kiếm.",
        "apihelp-opensearch-param-limit": "Đa số kết quả để cho ra.",
        "apihelp-opensearch-param-namespace": "Không gian tên để tìm kiếm.",
        "apihelp-opensearch-param-format": "Định dạng kết quả được cho ra.",
@@ -81,7 +81,7 @@
        "apihelp-purge-example-generator": "Làm mới 10 trang đầu tiên trong không gian tên chính",
        "apihelp-query-param-prop": "Các thuộc tính để lấy khi truy vấn các trang.",
        "apihelp-query-param-list": "Các danh sách để lấy.",
-       "apihelp-query-param-meta": "Các metadata để lấy.",
+       "apihelp-query-param-meta": "Siêu dữ liệu để lấy.",
        "apihelp-format-example-generic": "Định dạng kết quả truy vấn dưới dạng $1",
        "apihelp-dbg-description": "Cho ra dữ liệu dưới dạng var_export() của PHP.",
        "apihelp-dbgfm-description": "Cho ra dữ liệu dưới dạng var_export() của PHP (định dạng bằng HTML).",
index 8690a85..3fb7b68 100644 (file)
        "apihelp-query+pageswithprop-example-generator": "获取有关前10个使用_&#95;NOTOC_&#95;的页面的信息",
        "apihelp-query+prefixsearch-param-search": "搜索字符串。",
        "apihelp-query+prefixsearch-param-namespace": "搜索的名字空间。",
+       "apihelp-query+protectedtitles-param-namespace": "只列出这些名字空间的标题。",
        "apihelp-query+protectedtitles-example-simple": "受保护标题列表",
        "apihelp-query+querypage-param-limit": "返回的结果数。",
        "apihelp-query+querypage-example-ancientpages": "返回[[Special:Ancientpages]]的结果。",
index 4bb646e..34132aa 100644 (file)
@@ -1117,7 +1117,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                # Keep track of whether the transaction has write queries pending
                if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery( $sql ) ) {
                        $this->mTrxDoneWrites = true;
-                       Profiler::instance()->transactionWritingIn(
+                       Profiler::instance()->getTransactionProfiler()->transactionWritingIn(
                                $this->mServer, $this->mDBname, $this->mTrxShortId );
                }
 
@@ -1162,6 +1162,14 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                        throw new DBUnexpectedError( $this, "DB connection was already closed." );
                }
 
+               # Log the query time and feed it into the DB trx profiler
+               $queryStartTime = microtime( true );
+               $queryProfile = new ScopedCallback( function() use ( $queryStartTime, $queryProf ) {
+                       $elapsed = microtime( true ) - $queryStartTime;
+                       $trxProfiler = Profiler::instance()->getTransactionProfiler();
+                       $trxProfiler->recordFunctionCompletion( $queryProf, $elapsed );
+               } );
+
                # Do the query and handle errors
                $ret = $this->doQuery( $commentedSql );
 
@@ -3524,7 +3532,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                        $this->runOnTransactionPreCommitCallbacks();
                        $this->doCommit( $fname );
                        if ( $this->mTrxDoneWrites ) {
-                               Profiler::instance()->transactionWritingOut(
+                               Profiler::instance()->getTransactionProfiler()->transactionWritingOut(
                                        $this->mServer, $this->mDBname, $this->mTrxShortId );
                        }
                        $this->runOnTransactionIdleCallbacks();
@@ -3604,7 +3612,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                $this->runOnTransactionPreCommitCallbacks();
                $this->doCommit( $fname );
                if ( $this->mTrxDoneWrites ) {
-                       Profiler::instance()->transactionWritingOut(
+                       Profiler::instance()->getTransactionProfiler()->transactionWritingOut(
                                $this->mServer, $this->mDBname, $this->mTrxShortId );
                }
                $this->runOnTransactionIdleCallbacks();
@@ -3662,7 +3670,7 @@ abstract class DatabaseBase implements IDatabase, DatabaseType {
                $this->mTrxPreCommitCallbacks = array(); // cancel
                $this->mTrxAtomicLevels = new SplStack;
                if ( $this->mTrxDoneWrites ) {
-                       Profiler::instance()->transactionWritingOut(
+                       Profiler::instance()->getTransactionProfiler()->transactionWritingOut(
                                $this->mServer, $this->mDBname, $this->mTrxShortId );
                }
        }
index ee29f38..8577834 100644 (file)
@@ -5,7 +5,10 @@
                        "Robin0van0der0vliet"
                ]
        },
+       "config-page-language": "Taal",
        "config-page-name": "Namme",
+       "config-admin-password": "Wachtwurd:",
+       "config-help": "help",
        "mainpagetext": "'''MediaWiki-program goed ynstallearre.'''",
        "mainpagedocfooter": "Rieplachtsje de [//meta.wikimedia.org/wiki/Help:Contents Ynhâldsopjefte hantlieding] foar ynformaasje oer it gebrûk fan 'e wikisoftware.\n\n== Mear help oer Mediawiki ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings List mei ynstellings]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Faak stelde fragen (FAQ)]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Mailinglist foar oankundigings fan nije ferzjes]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]"
 }
index 71b1cba..93c31a7 100644 (file)
        "config-no-db": "Nun se può truvà nu driver adatto p' 'o database! È necessario installare nu driver p' 'o PHP.\n'E furmatte 'e database ccà annanze songo suppurtate: $1.\n\nSi cumpilate PHP autonomamente, riaccunciatevello attivando nu client database, p'esempio ausannoo <code>./configure --with-mysqli</code>.\nQuanno fosse installato PHP pe' bbìa 'e nu pacchetto Debian o Ubuntu, allora avite 'a installà pure 'o pacchetto <code>php5-mysql</code>.",
        "config-outdated-sqlite": "'''Attenziò''': tenite 'o SQLite $1 pe' tramente ca ce vulesse 'a verziona $2, SQLite nun sarrà a disposizione.",
        "config-no-fts3": "'''Attenziò''': SQLite è cumpilato senza 'o [//sqlite.org/fts3.html modulo FTS3], 'e funziune 'e p'ascià dinto nun sarranno a disposizione ncopp'a stu backend.",
+       "config-register-globals-error": "<strong>Errore: l'opzione PHP <code>[http://php.net/register_globals register_globals]</code> è apicciata.\nS'avesse 'a stutà pe' cuntinuà c' 'a installazione.</strong>\nVide [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] pe' n'avé n'aiuto ncopp'a comme s'avess'a ffà.",
+       "config-magic-quotes-gpc": "<strong>Fatale: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] è attivo!</strong>\nChest'opzione scassa 'e date d'input 'n modo scanusciuto.\nNun putite installare o utilizzare MediaWiki, si nun stutate st'opzione.",
+       "config-magic-quotes-runtime": "<strong>Fatale: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] è attivo!'</strong>\nSt'opzione scassa 'e date 'e na manera scanusciuta.\nNun se può installà o ausà MediaWiki si nun se stuta st'opzione.",
+       "config-xml-bad": "'O modulo XML 'e PHP è mancante.\nA MediaWiki servessero 'e funziune prisente dint'a stu modulo e nun faticarrà c' 'a configurazione 'e mò.\nSi se sta eseguenno Mandrake, installare 'o pacco php-xml.",
        "config-memory-raised": "'O valore 'e PHP <code>memory_limit</code> è $1, aumentato a $2.",
        "config-memory-bad": "<strong>Attenziò:</strong> 'o valore 'e PHP <code>memory_limit</code> è $1.\nProbabbilmente troppo basso.\n'A installazione se putesse scassà!",
        "config-ctype": "'''Errore''': 'o PHP s'adda ghienchere c' 'o supporto pe' l'[http://www.php.net/manual/it/ctype.installation.php estensione Ctype].",
        "config-imagemagick": "Truvato ImageMagick: <code>$1</code>.\n'E miniature d' 'e fiùre sarranno prisente si l'upload song'abbiàte.",
        "config-gd": "Truvata 'a bibblioteca ntegrata GD Graphics.\n'E miniature 'e ll'immaggene sarranno prisente si l'upload se song'abbiàte.",
        "config-no-scaling": "Nun se può truvà 'a bibblioteca GD o ImageMagick.\n'E miniature 'e l'immaggene sarranno stutate.",
-       "config-no-uri": "<strong>Errore:</strong> Nun se può determina l'URI 'e mmò.\nInstallazione interrotta.",
+       "config-no-uri": "<strong>Errore:</strong> Nun se può determina l'URI 'e mmò.\nInstallazione spezzata.",
        "config-using-server": "Nomme d' 'o server ca se stà ausanno \"<nowiki>$1</nowiki>\".",
        "config-using-uri": "URL d' 'o server ca se stà ausanno \"<nowiki>$1$2</nowiki>\".",
+       "config-brokenlibxml": "'O sistema vuosto ave na combinazione 'e verziune 'e PHP e libxml2 nguacchiata ca putesse scassà 'e date 'e MediaWiki 'n manera annascunnusa e pure l'ati apprecaziune p' 'o web.\nAgghiurnate a libxml2 2.7.3 o cchiù muderno ([https://bugs.php.net/bug.php?id=45996 'o bug studiato d' 'o lato PHP]).\nInstallaziona spezzata.",
        "config-db-type": "Tipo 'e database:",
        "config-db-host": "Host d' 'o database:",
+       "config-db-host-oracle": "TNS d' 'o database:",
+       "config-db-wiki-settings": "Identifica stu wiki",
+       "config-db-name": "Nomme d' 'o database:",
+       "config-db-name-help": "Sciglite nu nomme ca identificasse 'a wiki vosta.\nNun avess'a cuntenè spazie.\n\nSi ausate nu web hosting spartuto, 'o furnitore d' 'o hosting v'avesse 'a specificà nu nomme 'e database specifico pe' ve permettere 'e crià database pe' bbìa 'e nu pannello 'e cuntrollo.",
+       "config-db-name-oracle": "Schema d' 'o database:",
+       "config-db-install-account": "Cunto utente pe' l'installazione",
+       "config-db-username": "Nomme utente p' 'o database:",
+       "config-db-password": "Password d' 'o database:",
+       "config-db-password-empty": "Avita nzertà na password pe' l'utente nuovo d' 'o database: $1.\nPure si fosse possibbele 'e crià ll'utente senza password chisto nun fosse sicuro.",
+       "config-db-username-empty": "Avita miette nu valore p' 'o \"{{int:config-db-username}}\"",
+       "config-db-wiki-account": "Account utente p' 'o funzionamento nurmale",
+       "config-db-charset": "Nzieme 'e carattere d' 'o database",
+       "config-charset-mysql5-binary": "MySQL 4.1/5.0 binario",
+       "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
+       "config-charset-mysql4": "MySQL 4.0 cu compatibbelità UTF-8",
+       "config-mysql-old": "MySQL $1 o cchiù muderno è necessario. Vuje avite $2.",
        "config-db-port": "Porta d' 'o database:",
        "config-db-schema": "Schema pe' MediaWiki:",
        "config-db-schema-help": "Stu schema 'n genere sarrà buono.\nSi 'o vulite cagnà facite sulamente si ne tenite abbesuogno.",
        "config-header-oracle": "Mpustaziune Oracle",
        "config-header-mssql": "Mpustaziune 'e Microsoft SQL Server",
        "config-invalid-db-type": "'O tipo 'e database nun è buono.",
+       "config-missing-db-name": "Avita miette nu valore p' 'o \"{{int:config-db-name}}\"",
+       "config-missing-db-host": "Avita miette nu valore p' 'o \"{{int:config-db-host}}\"",
+       "config-missing-db-server-oracle": "Avita miette nu valore p' 'o \"{{int:config-db-host-oracle}}\"",
        "config-mssql-install-auth": "Sceglie 'o tipo d'autenticazziona ca s'ausarrà pe cunnettà â database, durante ll'operazziona d'istallazziona. Si piglie \"{{int:config-mssql-windowsauth}}\", 'e credenziale 'e qualunque fosse ll'utenza ca 'o webserver sta pruciessanno sarranno ausate.",
        "config-mssql-web-auth": "Sceglie 'o tipo d'autenticazziona ca 'o web server pigliarrà pe se cunnettà a 'o server 'e bbase 'e dati, durante ll'operazziona nurmale d' 'a wiki.\nSi piglie \"{{int:config-mssql-windowsauth}}\", 'e credenziale 'e qualunque fosse ll'utenza ca 'o webserver sta pruciessanno sarranno ausate."
 }
diff --git a/includes/libs/ArrayUtils.php b/includes/libs/ArrayUtils.php
new file mode 100644 (file)
index 0000000..f934021
--- /dev/null
@@ -0,0 +1,187 @@
+<?php
+/**
+ * Methods to play with arrays.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * A collection of static methods to play with arrays.
+ *
+ * @since 1.21
+ */
+class ArrayUtils {
+       /**
+        * Sort the given array in a pseudo-random order which depends only on the
+        * given key and each element value. This is typically used for load
+        * balancing between servers each with a local cache.
+        *
+        * Keys are preserved. The input array is modified in place.
+        *
+        * Note: Benchmarking on PHP 5.3 and 5.4 indicates that for small
+        * strings, md5() is only 10% slower than hash('joaat',...) etc.,
+        * since the function call overhead dominates. So there's not much
+        * justification for breaking compatibility with installations
+        * compiled with ./configure --disable-hash.
+        *
+        * @param array $array Array to sort
+        * @param string $key
+        * @param string $separator A separator used to delimit the array elements and the
+        *     key. This can be chosen to provide backwards compatibility with
+        *     various consistent hash implementations that existed before this
+        *     function was introduced.
+        */
+       public static function consistentHashSort( &$array, $key, $separator = "\000" ) {
+               $hashes = array();
+               foreach ( $array as $elt ) {
+                       $hashes[$elt] = md5( $elt . $separator . $key );
+               }
+               uasort( $array, function ( $a, $b ) use ( $hashes ) {
+                       return strcmp( $hashes[$a], $hashes[$b] );
+               } );
+       }
+
+       /**
+        * Given an array of non-normalised probabilities, this function will select
+        * an element and return the appropriate key
+        *
+        * @param array $weights
+        * @return bool|int|string
+        */
+       public static function pickRandom( $weights ) {
+               if ( !is_array( $weights ) || count( $weights ) == 0 ) {
+                       return false;
+               }
+
+               $sum = array_sum( $weights );
+               if ( $sum == 0 ) {
+                       # No loads on any of them
+                       # In previous versions, this triggered an unweighted random selection,
+                       # but this feature has been removed as of April 2006 to allow for strict
+                       # separation of query groups.
+                       return false;
+               }
+               $max = mt_getrandmax();
+               $rand = mt_rand( 0, $max ) / $max * $sum;
+
+               $sum = 0;
+               foreach ( $weights as $i => $w ) {
+                       $sum += $w;
+                       # Do not return keys if they have 0 weight.
+                       # Note that the "all 0 weight" case is handed above
+                       if ( $w > 0 && $sum >= $rand ) {
+                               break;
+                       }
+               }
+
+               return $i;
+       }
+
+       /**
+        * Do a binary search, and return the index of the largest item that sorts
+        * less than or equal to the target value.
+        *
+        * @since 1.23
+        *
+        * @param callable $valueCallback A function to call to get the value with
+        *     a given array index.
+        * @param int $valueCount The number of items accessible via $valueCallback,
+        *     indexed from 0 to $valueCount - 1
+        * @param callable $comparisonCallback A callback to compare two values, returning
+        *     -1, 0 or 1 in the style of strcmp().
+        * @param string $target The target value to find.
+        *
+        * @return int|bool The item index of the lower bound, or false if the target value
+        *     sorts before all items.
+        */
+       public static function findLowerBound( $valueCallback, $valueCount,
+               $comparisonCallback, $target
+       ) {
+               if ( $valueCount === 0 ) {
+                       return false;
+               }
+
+               $min = 0;
+               $max = $valueCount;
+               do {
+                       $mid = $min + ( ( $max - $min ) >> 1 );
+                       $item = call_user_func( $valueCallback, $mid );
+                       $comparison = call_user_func( $comparisonCallback, $target, $item );
+                       if ( $comparison > 0 ) {
+                               $min = $mid;
+                       } elseif ( $comparison == 0 ) {
+                               $min = $mid;
+                               break;
+                       } else {
+                               $max = $mid;
+                       }
+               } while ( $min < $max - 1 );
+
+               if ( $min == 0 ) {
+                       $item = call_user_func( $valueCallback, $min );
+                       $comparison = call_user_func( $comparisonCallback, $target, $item );
+                       if ( $comparison < 0 ) {
+                               // Before the first item
+                               return false;
+                       }
+               }
+               return $min;
+       }
+
+       /**
+        * Do array_diff_assoc() on multi-dimensional arrays.
+        *
+        * Note: empty arrays are removed.
+        *
+        * @since 1.23
+        *
+        * @param array $array1 The array to compare from
+        * @param array $array2,... More arrays to compare against
+        * @return array An array containing all the values from array1
+        *               that are not present in any of the other arrays.
+        */
+       public static function arrayDiffAssocRecursive( $array1 ) {
+               $arrays = func_get_args();
+               array_shift( $arrays );
+               $ret = array();
+
+               foreach ( $array1 as $key => $value ) {
+                       if ( is_array( $value ) ) {
+                               $args = array( $value );
+                               foreach ( $arrays as $array ) {
+                                       if ( isset( $array[$key] ) ) {
+                                               $args[] = $array[$key];
+                                       }
+                               }
+                               $valueret = call_user_func_array( __METHOD__, $args );
+                               if ( count( $valueret ) ) {
+                                       $ret[$key] = $valueret;
+                               }
+                       } else {
+                               foreach ( $arrays as $array ) {
+                                       if ( isset( $array[$key] ) && $array[$key] === $value ) {
+                                               continue 2;
+                                       }
+                               }
+                               $ret[$key] = $value;
+                       }
+               }
+
+               return $ret;
+       }
+}
diff --git a/includes/libs/CSSJanus.php b/includes/libs/CSSJanus.php
deleted file mode 100644 (file)
index e96baec..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-<?php
-/**
- * PHP port of CSSJanus.
- *
- * Copyright 2008 Google Inc.
- * Copyright 2010 Roan Kattouw
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @file
- */
-
-/**
- * This is a PHP port of CSSJanus, a utility that transforms CSS style sheets
- * written for LTR to RTL.
- *
- * Original code: http://code.google.com/p/cssjanus/source/browse/trunk/cssjanus.py
- *
- * @author Lindsey Simon <elsigh@google.com>
- * @author Roan Kattouw
- */
-class CSSJanus {
-       // Patterns defined as null are built dynamically by buildPatterns()
-       private static $patterns = array(
-               'tmpToken' => '`TMP`',
-               'nonAscii' => '[\200-\377]',
-               'unicode' => '(?:(?:\\[0-9a-f]{1,6})(?:\r\n|\s)?)',
-               'num' => '(?:[0-9]*\.[0-9]+|[0-9]+)',
-               'unit' => '(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)',
-               'body_selector' => 'body\s*{\s*',
-               'direction' => 'direction\s*:\s*',
-               'escape' => null,
-               'nmstart' => null,
-               'nmchar' => null,
-               'ident' => null,
-               'quantity' => null,
-               'possibly_negative_quantity' => null,
-               'color' => null,
-               'url_special_chars' => '[!#$%&*-~]',
-               'valid_after_uri_chars' => '[\'\"]?\s*',
-               'url_chars' => null,
-               'lookahead_not_open_brace' => null,
-               'lookahead_not_closing_paren' => null,
-               'lookahead_for_closing_paren' => null,
-               'lookahead_not_letter' => '(?![a-zA-Z])',
-               'lookbehind_not_letter' => '(?<![a-zA-Z])',
-               'chars_within_selector' => '[^\}]*?',
-               'noflip_annotation' => '\/\*\!?\s*@noflip\s*\*\/',
-               'noflip_single' => null,
-               'noflip_class' => null,
-               'comment' => '/\/\*[^*]*\*+([^\/*][^*]*\*+)*\//',
-               'direction_ltr' => null,
-               'direction_rtl' => null,
-               'left' => null,
-               'right' => null,
-               'left_in_url' => null,
-               'right_in_url' => null,
-               'ltr_in_url' => null,
-               'rtl_in_url' => null,
-               'cursor_east' => null,
-               'cursor_west' => null,
-               'four_notation_quantity' => null,
-               'four_notation_color' => null,
-               'border_radius' => null,
-               'box_shadow' => null,
-               'text_shadow1' => null,
-               'text_shadow2' => null,
-               'bg_horizontal_percentage' => null,
-               'bg_horizontal_percentage_x' => null,
-       );
-
-       /**
-        * Build patterns we can't define above because they depend on other patterns.
-        */
-       private static function buildPatterns() {
-               if (!is_null(self::$patterns['escape'])) {
-                       // Patterns have already been built
-                       return;
-               }
-
-               // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
-               $patterns =& self::$patterns;
-               $patterns['escape'] = "(?:{$patterns['unicode']}|\\[^\r\n\f0-9a-f])";
-               $patterns['nmstart'] = "(?:[_a-z]|{$patterns['nonAscii']}|{$patterns['escape']})";
-               $patterns['nmchar'] = "(?:[_a-z0-9-]|{$patterns['nonAscii']}|{$patterns['escape']})";
-               $patterns['ident'] = "-?{$patterns['nmstart']}{$patterns['nmchar']}*";
-               $patterns['quantity'] = "{$patterns['num']}(?:\s*{$patterns['unit']}|{$patterns['ident']})?";
-               $patterns['possibly_negative_quantity'] = "((?:-?{$patterns['quantity']})|(?:inherit|auto))";
-               $patterns['color'] = "(#?{$patterns['nmchar']}+|(?:rgba?|hsla?)\([ \d.,%-]+\))";
-               $patterns['url_chars'] = "(?:{$patterns['url_special_chars']}|{$patterns['nonAscii']}|{$patterns['escape']})*";
-               $patterns['lookahead_not_open_brace'] = "(?!({$patterns['nmchar']}|\r?\n|\s|#|\:|\.|\,|\+|>|\(|\)|\[|\]|=|\*=|~=|\^=|'[^']*'])*?{)";
-               $patterns['lookahead_not_closing_paren'] = "(?!{$patterns['url_chars']}?{$patterns['valid_after_uri_chars']}\))";
-               $patterns['lookahead_for_closing_paren'] = "(?={$patterns['url_chars']}?{$patterns['valid_after_uri_chars']}\))";
-               $patterns['noflip_single'] = "/({$patterns['noflip_annotation']}{$patterns['lookahead_not_open_brace']}[^;}]+;?)/i";
-               $patterns['noflip_class'] = "/({$patterns['noflip_annotation']}{$patterns['chars_within_selector']}})/i";
-               $patterns['direction_ltr'] = "/({$patterns['direction']})ltr/i";
-               $patterns['direction_rtl'] = "/({$patterns['direction']})rtl/i";
-               $patterns['left'] = "/{$patterns['lookbehind_not_letter']}(left){$patterns['lookahead_not_letter']}{$patterns['lookahead_not_closing_paren']}{$patterns['lookahead_not_open_brace']}/i";
-               $patterns['right'] = "/{$patterns['lookbehind_not_letter']}(right){$patterns['lookahead_not_letter']}{$patterns['lookahead_not_closing_paren']}{$patterns['lookahead_not_open_brace']}/i";
-               $patterns['left_in_url'] = "/{$patterns['lookbehind_not_letter']}(left){$patterns['lookahead_for_closing_paren']}/i";
-               $patterns['right_in_url'] = "/{$patterns['lookbehind_not_letter']}(right){$patterns['lookahead_for_closing_paren']}/i";
-               $patterns['ltr_in_url'] = "/{$patterns['lookbehind_not_letter']}(ltr){$patterns['lookahead_for_closing_paren']}/i";
-               $patterns['rtl_in_url'] = "/{$patterns['lookbehind_not_letter']}(rtl){$patterns['lookahead_for_closing_paren']}/i";
-               $patterns['cursor_east'] = "/{$patterns['lookbehind_not_letter']}([ns]?)e-resize/";
-               $patterns['cursor_west'] = "/{$patterns['lookbehind_not_letter']}([ns]?)w-resize/";
-               $patterns['four_notation_quantity_props'] = "((?:margin|padding|border-width)\s*:\s*)";
-               $patterns['four_notation_quantity'] = "/{$patterns['four_notation_quantity_props']}{$patterns['possibly_negative_quantity']}(\s+){$patterns['possibly_negative_quantity']}(\s+){$patterns['possibly_negative_quantity']}(\s+){$patterns['possibly_negative_quantity']}(\s*[;}])/i";
-               $patterns['four_notation_color'] = "/((?:-color|border-style)\s*:\s*){$patterns['color']}(\s+){$patterns['color']}(\s+){$patterns['color']}(\s+){$patterns['color']}(\s*[;}])/i";
-               $patterns['border_radius'] = "/(border-radius\s*:\s*)([^;}]*)/";
-               $patterns['box_shadow'] = "/(box-shadow\s*:\s*(?:inset\s*)?){$patterns['possibly_negative_quantity']}/i";
-               $patterns['text_shadow1'] = "/(text-shadow\s*:\s*){$patterns['color']}(\s*){$patterns['possibly_negative_quantity']}/i";
-               $patterns['text_shadow2'] = "/(text-shadow\s*:\s*){$patterns['possibly_negative_quantity']}/i";
-               $patterns['bg_horizontal_percentage'] = "/(background(?:-position)?\s*:\s*(?:[^:;}\s]+\s+)*?)({$patterns['quantity']})/i";
-               $patterns['bg_horizontal_percentage_x'] = "/(background-position-x\s*:\s*)(-?{$patterns['num']}%)/i";
-               // @codingStandardsIgnoreEnd
-
-       }
-
-       /**
-        * Transform an LTR stylesheet to RTL
-        * @param string $css stylesheet to transform
-        * @param $swapLtrRtlInURL Boolean: If true, swap 'ltr' and 'rtl' in URLs
-        * @param $swapLeftRightInURL Boolean: If true, swap 'left' and 'right' in URLs
-        * @return string Transformed stylesheet
-        */
-       public static function transform($css, $swapLtrRtlInURL = false, $swapLeftRightInURL = false) {
-               // We wrap tokens in ` , not ~ like the original implementation does.
-               // This was done because ` is not a legal character in CSS and can only
-               // occur in URLs, where we escape it to %60 before inserting our tokens.
-               $css = str_replace('`', '%60', $css);
-
-               self::buildPatterns();
-
-               // Tokenize single line rules with /* @noflip */
-               $noFlipSingle = new CSSJanusTokenizer(self::$patterns['noflip_single'], '`NOFLIP_SINGLE`');
-               $css = $noFlipSingle->tokenize($css);
-
-               // Tokenize class rules with /* @noflip */
-               $noFlipClass = new CSSJanusTokenizer(self::$patterns['noflip_class'], '`NOFLIP_CLASS`');
-               $css = $noFlipClass->tokenize($css);
-
-               // Tokenize comments
-               $comments = new CSSJanusTokenizer(self::$patterns['comment'], '`C`');
-               $css = $comments->tokenize($css);
-
-               // LTR->RTL fixes start here
-               $css = self::fixDirection($css);
-               if ($swapLtrRtlInURL) {
-                       $css = self::fixLtrRtlInURL($css);
-               }
-
-               if ($swapLeftRightInURL) {
-                       $css = self::fixLeftRightInURL($css);
-               }
-               $css = self::fixLeftAndRight($css);
-               $css = self::fixCursorProperties($css);
-               $css = self::fixFourPartNotation($css);
-               $css = self::fixBorderRadius($css);
-               $css = self::fixBackgroundPosition($css);
-               $css = self::fixShadows($css);
-
-               // Detokenize stuff we tokenized before
-               $css = $comments->detokenize($css);
-               $css = $noFlipClass->detokenize($css);
-               $css = $noFlipSingle->detokenize($css);
-
-               return $css;
-       }
-
-       /**
-        * Replace direction: ltr; with direction: rtl; and vice versa.
-        *
-        * The original implementation only does this inside body selectors
-        * and misses "body\n{\ndirection:ltr;\n}". This function does not have
-        * these problems.
-        *
-        * See https://code.google.com/p/cssjanus/issues/detail?id=15
-        *
-        * @param $css string
-        * @return string
-        */
-       private static function fixDirection($css) {
-               $css = preg_replace(
-                       self::$patterns['direction_ltr'],
-                       '$1' . self::$patterns['tmpToken'],
-                       $css
-               );
-               $css = preg_replace(self::$patterns['direction_rtl'], '$1ltr', $css);
-               $css = str_replace(self::$patterns['tmpToken'], 'rtl', $css);
-
-               return $css;
-       }
-
-       /**
-        * Replace 'ltr' with 'rtl' and vice versa in background URLs
-        * @param $css string
-        * @return string
-        */
-       private static function fixLtrRtlInURL($css) {
-               $css = preg_replace(self::$patterns['ltr_in_url'], self::$patterns['tmpToken'], $css);
-               $css = preg_replace(self::$patterns['rtl_in_url'], 'ltr', $css);
-               $css = str_replace(self::$patterns['tmpToken'], 'rtl', $css);
-
-               return $css;
-       }
-
-       /**
-        * Replace 'left' with 'right' and vice versa in background URLs
-        * @param $css string
-        * @return string
-        */
-       private static function fixLeftRightInURL($css) {
-               $css = preg_replace(self::$patterns['left_in_url'], self::$patterns['tmpToken'], $css);
-               $css = preg_replace(self::$patterns['right_in_url'], 'left', $css);
-               $css = str_replace(self::$patterns['tmpToken'], 'right', $css);
-
-               return $css;
-       }
-
-       /**
-        * Flip rules like left: , padding-right: , etc.
-        * @param $css string
-        * @return string
-        */
-       private static function fixLeftAndRight($css) {
-               $css = preg_replace(self::$patterns['left'], self::$patterns['tmpToken'], $css);
-               $css = preg_replace(self::$patterns['right'], 'left', $css);
-               $css = str_replace(self::$patterns['tmpToken'], 'right', $css);
-
-               return $css;
-       }
-
-       /**
-        * Flip East and West in rules like cursor: nw-resize;
-        * @param $css string
-        * @return string
-        */
-       private static function fixCursorProperties($css) {
-               $css = preg_replace(
-                       self::$patterns['cursor_east'],
-                       '$1' . self::$patterns['tmpToken'],
-                       $css
-               );
-               $css = preg_replace(self::$patterns['cursor_west'], '$1e-resize', $css);
-               $css = str_replace(self::$patterns['tmpToken'], 'w-resize', $css);
-
-               return $css;
-       }
-
-       /**
-        * Swap the second and fourth parts in four-part notation rules like
-        * padding: 1px 2px 3px 4px;
-        *
-        * Unlike the original implementation, this function doesn't suffer from
-        * the bug where whitespace is not preserved when flipping four-part rules
-        * and four-part color rules with multiple whitespace characters between
-        * colors are not recognized.
-        * See https://code.google.com/p/cssjanus/issues/detail?id=16
-        * @param $css string
-        * @return string
-        */
-       private static function fixFourPartNotation($css) {
-               $css = preg_replace(self::$patterns['four_notation_quantity'], '$1$2$3$8$5$6$7$4$9', $css);
-               $css = preg_replace(self::$patterns['four_notation_color'], '$1$2$3$8$5$6$7$4$9', $css);
-               return $css;
-       }
-
-       /**
-        * Swaps appropriate corners in border-radius values.
-        *
-        * @param $css string
-        * @return string
-        */
-       private static function fixBorderRadius($css) {
-               $css = preg_replace_callback(self::$patterns['border_radius'], function ($matches) {
-                       $pre = $matches[1];
-                       $values = $matches[2];
-                       $numValues = count(preg_split('/\s+/', trim($values)));
-                       switch ($numValues) {
-                               case 4:
-                                       $values = preg_replace('/^(\S+)(\s*)(\S+)(\s*)(\S+)(\s*)(\S+)/', '$3$2$1$4$7$6$5', $values);
-                                       break;
-                               case 3:
-                               case 2:
-                                       $values = preg_replace('/^(\S+)(\s*)(\S+)/', '$3$2$1', $values);
-                                       break;
-                       }
-                       return $pre . $values;
-               }, $css);
-
-               return $css;
-       }
-
-       /**
-        * Negates horizontal offset in box-shadow and text-shadow rules.
-        *
-        * @param $css string
-        * @return string
-        */
-       private static function fixShadows($css) {
-               // Flips the sign of a CSS value, possibly with a unit.
-               // (We can't just negate the value with unary minus due to the units.)
-               $flipSign = function ($cssValue) {
-                       // Don't mangle zeroes
-                       if (floatval($cssValue) === 0.0) {
-                               return $cssValue;
-                       } elseif ($cssValue[0] === '-') {
-                               return substr($cssValue, 1);
-                       } else {
-                               return "-" . $cssValue;
-                       }
-               };
-
-               $css = preg_replace_callback(self::$patterns['box_shadow'], function ($matches) use ($flipSign) {
-                       return $matches[1] . $flipSign($matches[2]);
-               }, $css);
-
-               $css = preg_replace_callback(self::$patterns['text_shadow1'], function ($matches) use ($flipSign) {
-                       return $matches[1] . $matches[2] . $matches[3] . $flipSign($matches[4]);
-               }, $css);
-
-               $css = preg_replace_callback(self::$patterns['text_shadow2'], function ($matches) use ($flipSign) {
-                       return $matches[1] . $flipSign($matches[2]);
-               }, $css);
-
-               return $css;
-       }
-
-       /**
-        * Flip horizontal background percentages.
-        * @param $css string
-        * @return string
-        */
-       private static function fixBackgroundPosition($css) {
-               $replaced = preg_replace_callback(
-                       self::$patterns['bg_horizontal_percentage'],
-                       array('self', 'calculateNewBackgroundPosition'),
-                       $css
-               );
-               if ($replaced !== null) {
-                       // preg_replace_callback() sometimes returns null
-                       $css = $replaced;
-               }
-               $replaced = preg_replace_callback(
-                       self::$patterns['bg_horizontal_percentage_x'],
-                       array('self', 'calculateNewBackgroundPosition'),
-                       $css
-               );
-               if ($replaced !== null) {
-                       $css = $replaced;
-               }
-
-               return $css;
-       }
-
-       /**
-        * Callback for fixBackgroundPosition()
-        * @param $matches array
-        * @return string
-        */
-       private static function calculateNewBackgroundPosition($matches) {
-               $value = $matches[2];
-               if (substr($value, -1) === '%') {
-                       $idx = strpos($value, '.');
-                       if ($idx !== false) {
-                               $len = strlen($value) - $idx - 2;
-                               $value = number_format(100 - $value, $len) . '%';
-                       } else {
-                               $value = (100 - $value) . '%';
-                       }
-               }
-               return $matches[1] . $value;
-       }
-}
-
-/**
- * Utility class used by CSSJanus that tokenizes and untokenizes things we want
- * to protect from being janused.
- * @author Roan Kattouw
- */
-class CSSJanusTokenizer {
-       private $regex;
-       private $token;
-       private $originals;
-
-       /**
-        * Constructor
-        * @param string $regex Regular expression whose matches to replace by a token.
-        * @param string $token Token
-        */
-       public function __construct($regex, $token) {
-               $this->regex = $regex;
-               $this->token = $token;
-               $this->originals = array();
-       }
-
-       /**
-        * Replace all occurrences of $regex in $str with a token and remember
-        * the original strings.
-        * @param string $str to tokenize
-        * @return string Tokenized string
-        */
-       public function tokenize($str) {
-               return preg_replace_callback($this->regex, array($this, 'tokenizeCallback'), $str);
-       }
-
-       /**
-        * @param $matches array
-        * @return string
-        */
-       private function tokenizeCallback($matches) {
-               $this->originals[] = $matches[0];
-               return $this->token;
-       }
-
-       /**
-        * Replace tokens with their originals. If multiple strings were tokenized, it's important they be
-        * detokenized in exactly the SAME ORDER.
-        * @param string $str previously run through tokenize()
-        * @return string Original string
-        */
-       public function detokenize($str) {
-               // PHP has no function to replace only the first occurrence or to
-               // replace occurrences of the same string with different values,
-               // so we use preg_replace_callback() even though we don't really need a regex
-               return preg_replace_callback(
-                       '/' . preg_quote($this->token, '/') . '/',
-                       array($this, 'detokenizeCallback'),
-                       $str
-               );
-       }
-
-       /**
-        * @param $matches
-        * @return mixed
-        */
-       private function detokenizeCallback($matches) {
-               $retval = current($this->originals);
-               next($this->originals);
-
-               return $retval;
-       }
-}
diff --git a/includes/libs/Cookie.php b/includes/libs/Cookie.php
new file mode 100644 (file)
index 0000000..56dc6ea
--- /dev/null
@@ -0,0 +1,291 @@
+<?php
+/**
+ * Cookie for HTTP requests.
+ *
+ * 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 HTTP
+ */
+
+class Cookie {
+       protected $name;
+       protected $value;
+       protected $expires;
+       protected $path;
+       protected $domain;
+       protected $isSessionKey = true;
+       // TO IMPLEMENT  protected $secure
+       // TO IMPLEMENT? protected $maxAge (add onto expires)
+       // TO IMPLEMENT? protected $version
+       // TO IMPLEMENT? protected $comment
+
+       function __construct( $name, $value, $attr ) {
+               $this->name = $name;
+               $this->set( $value, $attr );
+       }
+
+       /**
+        * Sets a cookie.  Used before a request to set up any individual
+        * cookies. Used internally after a request to parse the
+        * Set-Cookie headers.
+        *
+        * @param string $value The value of the cookie
+        * @param array $attr Possible key/values:
+        *        expires A date string
+        *        path    The path this cookie is used on
+        *        domain  Domain this cookie is used on
+        * @throws MWException
+        */
+       public function set( $value, $attr ) {
+               $this->value = $value;
+
+               if ( isset( $attr['expires'] ) ) {
+                       $this->isSessionKey = false;
+                       $this->expires = strtotime( $attr['expires'] );
+               }
+
+               if ( isset( $attr['path'] ) ) {
+                       $this->path = $attr['path'];
+               } else {
+                       $this->path = '/';
+               }
+
+               if ( isset( $attr['domain'] ) ) {
+                       if ( self::validateCookieDomain( $attr['domain'] ) ) {
+                               $this->domain = $attr['domain'];
+                       }
+               } else {
+                       throw new InvalidArgumentException( '$attr must contain a domain' );
+               }
+       }
+
+       /**
+        * Return the true if the cookie is valid is valid.  Otherwise,
+        * false.  The uses a method similar to IE cookie security
+        * described here:
+        * http://kuza55.blogspot.com/2008/02/understanding-cookie-security.html
+        * A better method might be to use a blacklist like
+        * http://publicsuffix.org/
+        *
+        * @todo fixme fails to detect 3-letter top-level domains
+        * @todo fixme fails to detect 2-letter top-level domains for single-domain use (probably
+        * not a big problem in practice, but there are test cases)
+        *
+        * @param string $domain The domain to validate
+        * @param string $originDomain (optional) the domain the cookie originates from
+        * @return bool
+        */
+       public static function validateCookieDomain( $domain, $originDomain = null ) {
+               $dc = explode( ".", $domain );
+
+               // Don't allow a trailing dot or addresses without a or just a leading dot
+               if ( substr( $domain, -1 ) == '.' ||
+                       count( $dc ) <= 1 ||
+                       count( $dc ) == 2 && $dc[0] === ''
+               ) {
+                       return false;
+               }
+
+               // Only allow full, valid IP addresses
+               if ( preg_match( '/^[0-9.]+$/', $domain ) ) {
+                       if ( count( $dc ) != 4 ) {
+                               return false;
+                       }
+
+                       if ( ip2long( $domain ) === false ) {
+                               return false;
+                       }
+
+                       if ( $originDomain == null || $originDomain == $domain ) {
+                               return true;
+                       }
+
+               }
+
+               // Don't allow cookies for "co.uk" or "gov.uk", etc, but allow "supermarket.uk"
+               if ( strrpos( $domain, "." ) - strlen( $domain ) == -3 ) {
+                       if ( ( count( $dc ) == 2 && strlen( $dc[0] ) <= 2 )
+                               || ( count( $dc ) == 3 && strlen( $dc[0] ) == "" && strlen( $dc[1] ) <= 2 ) ) {
+                               return false;
+                       }
+                       if ( ( count( $dc ) == 2 || ( count( $dc ) == 3 && $dc[0] == '' ) )
+                               && preg_match( '/(com|net|org|gov|edu)\...$/', $domain ) ) {
+                               return false;
+                       }
+               }
+
+               if ( $originDomain != null ) {
+                       if ( substr( $domain, 0, 1 ) != '.' && $domain != $originDomain ) {
+                               return false;
+                       }
+
+                       if ( substr( $domain, 0, 1 ) == '.'
+                               && substr_compare(
+                                       $originDomain,
+                                       $domain,
+                                       -strlen( $domain ),
+                                       strlen( $domain ),
+                                       true
+                               ) != 0
+                       ) {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
+       /**
+        * Serialize the cookie jar into a format useful for HTTP Request headers.
+        *
+        * @param string $path The path that will be used. Required.
+        * @param string $domain The domain that will be used. Required.
+        * @return string
+        */
+       public function serializeToHttpRequest( $path, $domain ) {
+               $ret = '';
+
+               if ( $this->canServeDomain( $domain )
+                               && $this->canServePath( $path )
+                               && $this->isUnExpired() ) {
+                       $ret = $this->name . '=' . $this->value;
+               }
+
+               return $ret;
+       }
+
+       /**
+        * @param string $domain
+        * @return bool
+        */
+       protected function canServeDomain( $domain ) {
+               if ( $domain == $this->domain
+                       || ( strlen( $domain ) > strlen( $this->domain )
+                               && substr( $this->domain, 0, 1 ) == '.'
+                               && substr_compare(
+                                       $domain,
+                                       $this->domain,
+                                       -strlen( $this->domain ),
+                                       strlen( $this->domain ),
+                                       true
+                               ) == 0
+                       )
+               ) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       /**
+        * @param string $path
+        * @return bool
+        */
+       protected function canServePath( $path ) {
+               return ( $this->path && substr_compare( $this->path, $path, 0, strlen( $this->path ) ) == 0 );
+       }
+
+       /**
+        * @return bool
+        */
+       protected function isUnExpired() {
+               return $this->isSessionKey || $this->expires > time();
+       }
+}
+
+class CookieJar {
+       private $cookie = array();
+
+       /**
+        * Set a cookie in the cookie jar. Make sure only one cookie per-name exists.
+        * @see Cookie::set()
+        * @param string $name
+        * @param string $value
+        * @param array $attr
+        */
+       public function setCookie( $name, $value, $attr ) {
+               /* cookies: case insensitive, so this should work.
+                * We'll still send the cookies back in the same case we got them, though.
+                */
+               $index = strtoupper( $name );
+
+               if ( isset( $this->cookie[$index] ) ) {
+                       $this->cookie[$index]->set( $value, $attr );
+               } else {
+                       $this->cookie[$index] = new Cookie( $name, $value, $attr );
+               }
+       }
+
+       /**
+        * @see Cookie::serializeToHttpRequest
+        * @param string $path
+        * @param string $domain
+        * @return string
+        */
+       public function serializeToHttpRequest( $path, $domain ) {
+               $cookies = array();
+
+               foreach ( $this->cookie as $c ) {
+                       $serialized = $c->serializeToHttpRequest( $path, $domain );
+
+                       if ( $serialized ) {
+                               $cookies[] = $serialized;
+                       }
+               }
+
+               return implode( '; ', $cookies );
+       }
+
+       /**
+        * Parse the content of an Set-Cookie HTTP Response header.
+        *
+        * @param string $cookie
+        * @param string $domain Cookie's domain
+        * @return null
+        */
+       public function parseCookieResponseHeader( $cookie, $domain ) {
+               $len = strlen( 'Set-Cookie:' );
+
+               if ( substr_compare( 'Set-Cookie:', $cookie, 0, $len, true ) === 0 ) {
+                       $cookie = substr( $cookie, $len );
+               }
+
+               $bit = array_map( 'trim', explode( ';', $cookie ) );
+
+               if ( count( $bit ) >= 1 ) {
+                       list( $name, $value ) = explode( '=', array_shift( $bit ), 2 );
+                       $attr = array();
+
+                       foreach ( $bit as $piece ) {
+                               $parts = explode( '=', $piece );
+                               if ( count( $parts ) > 1 ) {
+                                       $attr[strtolower( $parts[0] )] = $parts[1];
+                               } else {
+                                       $attr[strtolower( $parts[0] )] = true;
+                               }
+                       }
+
+                       if ( !isset( $attr['domain'] ) ) {
+                               $attr['domain'] = $domain;
+                       } elseif ( !Cookie::validateCookieDomain( $attr['domain'], $domain ) ) {
+                               return null;
+                       }
+
+                       $this->setCookie( $name, $value, $attr );
+               }
+       }
+}
index 8421672..5d11f84 100644 (file)
@@ -557,7 +557,7 @@ class LogEventsList extends ContextSource {
                if ( $logBody ) {
                        if ( $msgKey[0] ) {
                                $dir = $context->getLanguage()->getDir();
-                               $lang = $context->getLanguage()->getCode();
+                               $lang = $context->getLanguage()->getHtmlCode();
 
                                $s = Xml::openElement( 'div', array(
                                        'class' => "mw-warning-with-logexcerpt mw-content-$dir",
index 7900b2c..cf53f1d 100644 (file)
@@ -1803,6 +1803,9 @@ class Article implements Page {
                        $loglink = '[[Special:Log/delete|' . wfMessage( 'deletionlog' )->text() . ']]';
 
                        $outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
+
+                       wfRunHooks( 'ArticleDeleteAfterSuccess', array( $this->getTitle(), $outputPage ) );
+
                        $outputPage->returnToMain( false );
                } else {
                        $outputPage->setPageTitle(
index 8e5b98a..4629691 100644 (file)
@@ -125,31 +125,11 @@ abstract class Profiler {
        abstract public function profileOut( $functionname );
 
        /**
-        * Mark a DB as in a transaction with one or more writes pending
-        *
-        * Note that there can be multiple connections to a single DB.
-        *
-        * @param string $server DB server
-        * @param string $db DB name
-        * @param string $id Resource ID string of connection
-        */
-       public function transactionWritingIn( $server, $db, $id = '' ) {
-               $this->trxProfiler->transactionWritingIn( $server, $db, $id );
-       }
-
-       /**
-        * Mark a DB as no longer in a transaction
-        *
-        * This will check if locks are possibly held for longer than
-        * needed and log any affected transactions to a special DB log.
-        * Note that there can be multiple connections to a single DB.
-        *
-        * @param string $server DB server
-        * @param string $db DB name
-        * @param string $id Resource ID string of connection
+        * @return TransactionProfiler
+        * @since 1.25
         */
-       public function transactionWritingOut( $server, $db, $id = '' ) {
-               $this->trxProfiler->transactionWritingOut( $server, $db, $id );
+       public function getTransactionProfiler() {
+               return $this->trxProfiler;
        }
 
        /**
index a65e53e..ea13bfb 100644 (file)
@@ -231,7 +231,6 @@ class ProfilerStandard extends Profiler {
                                $this->mStack[] = array_merge( $item,
                                        array( $realTime, $cpuTime,     memory_get_usage() ) );
                        }
-                       $this->trxProfiler->recordFunctionCompletion( $functionname, $realTime - $ortime );
                }
        }
 
index 1d3b65d..e81f579 100644 (file)
@@ -54,12 +54,6 @@ class ProfilerStub extends Profiler {
                return '';
        }
 
-       public function transactionWritingIn( $server, $db, $id = '' ) {
-       }
-
-       public function transactionWritingOut( $server, $db, $id = '' ) {
-       }
-
        public function getRawData() {
                return array();
        }
index 5ee51e3..91b7bb7 100644 (file)
@@ -19,6 +19,7 @@
  *
  * @file
  * @ingroup Profiler
+ * @author Aaron Schulz
  */
 
 /**
@@ -69,19 +70,18 @@ class TransactionProfiler {
         * This method is only to be called by the Profiler class as methods finish
         *
         * @param string $method Function name
-        * @param float $realtime Wal time ellapsed
+        * @param float $realtime Wall time ellapsed
         */
        public function recordFunctionCompletion( $method, $realtime ) {
                if ( !$this->mDBTrxHoldingLocks ) {
                        // Short-circuit
                        return;
-               // @todo hardcoded check is a tad janky (what about FOR UPDATE?)
-               } elseif ( !preg_match( '/^query-m: (?!SELECT)/', $method )
-                       && $realtime < $this->mDBLockThreshold
-               ) {
+               // @todo hardcoded check is a tad janky
+               } elseif ( !preg_match( '/^query-m: /', $method ) && $realtime < 1.0 ) {
                        // Not a DB master query nor slow enough
                        return;
                }
+
                $now = microtime( true );
                foreach ( $this->mDBTrxHoldingLocks as $name => $info ) {
                        // Hacky check to exclude entries from before the first TRX write
index b9d1872..bc16925 100644 (file)
@@ -59,7 +59,7 @@ class SpecialNewFiles extends IncludableSpecialPage {
                if ( !$message->isDisabled() ) {
                        $this->getOutput()->addWikiText(
                                Html::rawElement( 'p',
-                                       array( 'lang' => $wgContLang->getCode(), 'dir' => $wgContLang->getDir() ),
+                                       array( 'lang' => $wgContLang->getHtmlCode(), 'dir' => $wgContLang->getDir() ),
                                        "\n" . $message->plain() . "\n"
                                ),
                                /* $lineStart */ false,
index 6b9173f..97b2f9b 100644 (file)
@@ -808,7 +808,7 @@ class SpecialVersion extends SpecialPage {
                $html .= Html::rawElement( 'td', array( 'class' => 'mw-version-ext-description' ), $description );
                $html .= Html::rawElement( 'td', array( 'class' => 'mw-version-ext-authors' ), $authors );
 
-               $html .= Html::closeElement( 'td' );
+               $html .= Html::closeElement( 'tr' );
 
                return $html;
        }
@@ -1203,7 +1203,7 @@ class SpecialVersion extends SpecialPage {
                $language = $this->getLanguage();
                $thAttribures = array(
                        'dir' => $language->getDir(),
-                       'lang' => $language->getCode()
+                       'lang' => $language->getHtmlCode()
                );
                $out = Html::element(
                                'h2',
index 079c7f8..a278652 100644 (file)
@@ -424,7 +424,7 @@ abstract class UploadBase {
         * @return mixed True of the file is verified, array otherwise.
         */
        protected function verifyFile() {
-               global $wgVerifyMimeType;
+               global $wgVerifyMimeType, $wgDisableUploadScriptChecks;
                wfProfileIn( __METHOD__ );
 
                $status = $this->verifyPartialFile();
@@ -446,6 +446,18 @@ abstract class UploadBase {
                        }
                }
 
+               # check for htmlish code and javascript
+               if ( !$wgDisableUploadScriptChecks ) {
+                       if ( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) {
+                               $svgStatus = $this->detectScriptInSvg( $this->mTempPath, false );
+                               if ( $svgStatus !== false ) {
+                                       wfProfileOut( __METHOD__ );
+
+                                       return $svgStatus;
+                               }
+                       }
+               }
+
                $handler = MediaHandler::getHandler( $mime );
                if ( $handler ) {
                        $handlerStatus = $handler->verifyUpload( $this->mTempPath );
@@ -504,7 +516,7 @@ abstract class UploadBase {
                                return array( 'uploadscripted' );
                        }
                        if ( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) {
-                               $svgStatus = $this->detectScriptInSvg( $this->mTempPath );
+                               $svgStatus = $this->detectScriptInSvg( $this->mTempPath, true );
                                if ( $svgStatus !== false ) {
                                        wfProfileOut( __METHOD__ );
 
@@ -1281,9 +1293,10 @@ abstract class UploadBase {
 
        /**
         * @param string $filename
+        * @param bool $partial
         * @return mixed False of the file is verified (does not contain scripts), array otherwise.
         */
-       protected function detectScriptInSvg( $filename ) {
+       protected function detectScriptInSvg( $filename, $partial ) {
                $this->mSVGNSError = false;
                $check = new XmlTypeCheck(
                        $filename,
@@ -1293,7 +1306,8 @@ abstract class UploadBase {
                );
                if ( $check->wellFormed !== true ) {
                        // Invalid xml (bug 58553)
-                       return array( 'uploadinvalidxml' );
+                       // But only when non-partial (bug 65724)
+                       return $partial ? false : array( 'uploadinvalidxml' );
                } elseif ( $check->filterMatch ) {
                        if ( $this->mSVGNSError ) {
                                return array( 'uploadscriptednamespace', $this->mSVGNSError );
diff --git a/includes/utils/ArrayUtils.php b/includes/utils/ArrayUtils.php
deleted file mode 100644 (file)
index 1e521cb..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-<?php
-/**
- * Methods to play with arrays.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * A collection of static methods to play with arrays.
- *
- * @since 1.21
- */
-class ArrayUtils {
-       /**
-        * Sort the given array in a pseudo-random order which depends only on the
-        * given key and each element value. This is typically used for load
-        * balancing between servers each with a local cache.
-        *
-        * Keys are preserved. The input array is modified in place.
-        *
-        * Note: Benchmarking on PHP 5.3 and 5.4 indicates that for small
-        * strings, md5() is only 10% slower than hash('joaat',...) etc.,
-        * since the function call overhead dominates. So there's not much
-        * justification for breaking compatibility with installations
-        * compiled with ./configure --disable-hash.
-        *
-        * @param array $array Array to sort
-        * @param string $key
-        * @param string $separator A separator used to delimit the array elements and the
-        *     key. This can be chosen to provide backwards compatibility with
-        *     various consistent hash implementations that existed before this
-        *     function was introduced.
-        */
-       public static function consistentHashSort( &$array, $key, $separator = "\000" ) {
-               $hashes = array();
-               foreach ( $array as $elt ) {
-                       $hashes[$elt] = md5( $elt . $separator . $key );
-               }
-               uasort( $array, function ( $a, $b ) use ( $hashes ) {
-                       return strcmp( $hashes[$a], $hashes[$b] );
-               } );
-       }
-
-       /**
-        * Given an array of non-normalised probabilities, this function will select
-        * an element and return the appropriate key
-        *
-        * @param array $weights
-        * @return bool|int|string
-        */
-       public static function pickRandom( $weights ) {
-               if ( !is_array( $weights ) || count( $weights ) == 0 ) {
-                       return false;
-               }
-
-               $sum = array_sum( $weights );
-               if ( $sum == 0 ) {
-                       # No loads on any of them
-                       # In previous versions, this triggered an unweighted random selection,
-                       # but this feature has been removed as of April 2006 to allow for strict
-                       # separation of query groups.
-                       return false;
-               }
-               $max = mt_getrandmax();
-               $rand = mt_rand( 0, $max ) / $max * $sum;
-
-               $sum = 0;
-               foreach ( $weights as $i => $w ) {
-                       $sum += $w;
-                       # Do not return keys if they have 0 weight.
-                       # Note that the "all 0 weight" case is handed above
-                       if ( $w > 0 && $sum >= $rand ) {
-                               break;
-                       }
-               }
-
-               return $i;
-       }
-
-       /**
-        * Do a binary search, and return the index of the largest item that sorts
-        * less than or equal to the target value.
-        *
-        * @since 1.23
-        *
-        * @param array $valueCallback A function to call to get the value with
-        *     a given array index.
-        * @param int $valueCount The number of items accessible via $valueCallback,
-        *     indexed from 0 to $valueCount - 1
-        * @param array $comparisonCallback A callback to compare two values, returning
-        *     -1, 0 or 1 in the style of strcmp().
-        * @param string $target The target value to find.
-        *
-        * @return int|bool The item index of the lower bound, or false if the target value
-        *     sorts before all items.
-        */
-       public static function findLowerBound( $valueCallback, $valueCount,
-               $comparisonCallback, $target
-       ) {
-               if ( $valueCount === 0 ) {
-                       return false;
-               }
-
-               $min = 0;
-               $max = $valueCount;
-               do {
-                       $mid = $min + ( ( $max - $min ) >> 1 );
-                       $item = call_user_func( $valueCallback, $mid );
-                       $comparison = call_user_func( $comparisonCallback, $target, $item );
-                       if ( $comparison > 0 ) {
-                               $min = $mid;
-                       } elseif ( $comparison == 0 ) {
-                               $min = $mid;
-                               break;
-                       } else {
-                               $max = $mid;
-                       }
-               } while ( $min < $max - 1 );
-
-               if ( $min == 0 ) {
-                       $item = call_user_func( $valueCallback, $min );
-                       $comparison = call_user_func( $comparisonCallback, $target, $item );
-                       if ( $comparison < 0 ) {
-                               // Before the first item
-                               return false;
-                       }
-               }
-               return $min;
-       }
-
-       /**
-        * Do array_diff_assoc() on multi-dimensional arrays.
-        *
-        * Note: empty arrays are removed.
-        *
-        * @since 1.23
-        *
-        * @param array $array1 The array to compare from
-        * @param array $array2,... More arrays to compare against
-        * @return array An array containing all the values from array1
-        *               that are not present in any of the other arrays.
-        */
-       public static function arrayDiffAssocRecursive( $array1 ) {
-               $arrays = func_get_args();
-               array_shift( $arrays );
-               $ret = array();
-
-               foreach ( $array1 as $key => $value ) {
-                       if ( is_array( $value ) ) {
-                               $args = array( $value );
-                               foreach ( $arrays as $array ) {
-                                       if ( isset( $array[$key] ) ) {
-                                               $args[] = $array[$key];
-                                       }
-                               }
-                               $valueret = call_user_func_array( __METHOD__, $args );
-                               if ( count( $valueret ) ) {
-                                       $ret[$key] = $valueret;
-                               }
-                       } else {
-                               foreach ( $arrays as $array ) {
-                                       if ( isset( $array[$key] ) && $array[$key] === $value ) {
-                                               continue 2;
-                                       }
-                               }
-                               $ret[$key] = $value;
-                       }
-               }
-
-               return $ret;
-       }
-}
index 3a0492d..9fb4c19 100644 (file)
 
 class MWFunction {
 
-       /**
-        * @deprecated since 1.22; use call_user_func()
-        * @param callable $callback
-        * @return mixed
-        */
-       public static function call( $callback ) {
-               wfDeprecated( __METHOD__, '1.22' );
-               $args = func_get_args();
-
-               return call_user_func_array( 'call_user_func', $args );
-       }
-
-       /**
-        * @deprecated since 1.22; use call_user_func_array()
-        * @param callable $callback
-        * @param array $argsarams
-        * @return mixed
-        */
-       public static function callArray( $callback, $argsarams ) {
-               wfDeprecated( __METHOD__, '1.22' );
-
-               return call_user_func_array( $callback, $argsarams );
-       }
-
        /**
         * @param string $class
         * @param array $args
index c043032..745fb35 100644 (file)
        "sort-ascending": "Сартаваць па ўзрастаньні",
        "nstab-main": "Старонка",
        "nstab-user": "Старонка {{GENDER:{{BASEPAGENAME}}|ўдзельніка|ўдзельніцы}}",
-       "nstab-media": "Мэдыя",
+       "nstab-media": "Ð\9cÑ\83лÑ\8cÑ\82Ñ\8bмÑ\8dдÑ\8bÑ\8f",
        "nstab-special": "Спэцыяльная старонка",
        "nstab-project": "Старонка праекту",
        "nstab-image": "Файл",
        "api-error-stasherror": "Падчас загрузкі файла ў сховішча адбылася памылка.",
        "api-error-stashedfilenotfound": "Схаваны файл ня быў знойдзены пры спробе загрузіць яго з схованкі.",
        "api-error-stashpathinvalid": "Шлях, дзе павінен быў знаходзіцца схаваны файл, апынуўся няслушным.",
+       "api-error-stashfilestorage": "Адбылася памылка пры захаваньні файла ў схованку.",
        "api-error-timeout": "Сэрвэр не адказаў у чаканы тэрмін.",
        "api-error-unclassified": "Узьнікла невядомая памылка",
        "api-error-unknown-code": "Невядомая памылка: «$1».",
index 1b52e6e..3c29c24 100644 (file)
        "autosumm-blank": "পাতা খালি করা হয়েছে",
        "autosumm-replace": "পাতাকে '$1' দিয়ে প্রতিস্থাপিত করা হল",
        "autoredircomment": "[[$1]]-এ পুনর্নির্দেশ করা হল",
-       "autosumm-new": "$1 দিয়ে তৈরি পাতা",
+       "autosumm-new": "\"$1\" দিয়ে পাতা তৈরি",
        "autosumm-newblank": "খালি পাতা তৈরি হয়েছে",
        "size-bytes": "$1 বাইট",
        "size-kilobytes": "$1 কিলোবাইট",
index 0ca7a62..3cd8d75 100644 (file)
        "templatesusedsection": "茲蜀段使其{{PLURAL:$1|模板}}:",
        "template-protected": "(保護)",
        "template-semiprotected": "(半保護)",
-       "recreate-moveddeleted-warn": "'''注意:汝重新創建其茲蜀頁面以前已經乞刪掉了。'''\n\n汝著考慮蜀下到底是伓是合適繼續去編輯茲蜀頁。茲蜀頁其刪除記錄共移動記錄都敆嚽塊共汝看:",
+       "recreate-moveddeleted-warn": "'''注意:汝敆𡅏重新創建舊底已經乞刪唻其頁面。'''\n\n汝應該考慮蜀下繼續去編輯茲蜀頁到底是伓是合適其。茲蜀頁其刪除記錄共移動記錄都敆嚽塊:",
        "undo-summary": "取消[[Special:Contributions/$2|$2]]([[User talk:$2|Tō̤-lâung]])其$1修改",
        "cantcreateaccounttitle": "無能獃開賬戶",
        "viewpagelogs": "看茲頁其歷史",
        "confirmemail_needlogin": "汝著$1來確定汝其電子郵件地址。",
        "confirmemail_loggedin": "汝其電子郵件地址現在已經確定去了。",
        "confirmemail_body": "有人(可能是汝)敆IP地址$1𡅏已經使茲蜀萆電子郵件地址來註冊蜀萆賬戶「$2」去了。\n\n卜想確認茲蜀萆賬戶當真是汝其,固加敆{{SITENAME}}激活電子郵件特點,許敆汝其瀏覽器𡅏拍開茲蜀萆鏈接:\n\n$3\n\n如果汝*無*註冊茲賬戶,單擊茲蜀萆鏈接來取消電子郵件確認:\n\n$5\n\n茲蜀萆確認代碼會敆$4時候過期。",
-       "deletedwhileediting": "'''警告:'''茲蜀頁å·²ç¶\93æ\95\86æ±\9d編輯以å\89\8då\88ªæ\8e\89å\8e»äº\86ï¼\81",
+       "deletedwhileediting": "'''警告:'''茲蜀頁æ\95\86æ±\9d編輯以å\89\8då·²ç¶\93ä¹\9eå\88ªå\94»äº\86ï¼\81",
        "recreate": "重新開",
        "confirm_purge_button": "好",
        "imgmultipageprev": "← 前蜀頁",
index bc9d6ff..8cd1a32 100644 (file)
        "viewsourcetext": "Μπορείτε να δείτε και να αντιγράψετε τον κώδικα αυτής της σελίδας:",
        "viewyourtext": "Μπορείτε να προβάλετε και να αντιγράψετε τον κώδικα των '''επεξεργασιών σας''' σε αυτήν τη σελίδα:",
        "protectedinterface": "Αυτή η σελίδα παρέχει κείμενο διεπαφής για το λογισμικό σε αυτό το wiki, και έχει κλειδωθεί για αποτροπή τυχόν βανδαλισμού.\n\nΓια να προσθέσετε ή να αλλάξετε τις μεταφράσεις για όλα τα wikis, παρακαλούμε χρησιμοποιήστε  [//translatewiki.net/ translatewiki.net], το εγχείρημα τοπικοποίησης του  MediaWiki.",
-       "editinginterface": "'''Προσοχή:''' Επεξεργάζεστε μια σελίδα η οποία χρησιμοποιείται για να παρέχει κείμενο διεπαφής για το λογισμικό. Αλλαγές σε αυτή τη σελίδα θα επηρεάσουν την εμφάνιση της διεπαφής χρήστη για τους άλλους χρήστες. Εάν θέλετε να διορθώσετε τη μετάφραση, μπορείτε να χρησιμοποιήσετε το [//translatewiki.net/ translatewiki.net], το εγχείρημα για με τις μεταφράσεις των μηνυμάτων MediaWiki.",
+       "editinginterface": "<strong>Προειδοποίηση:</strong> Επεξεργάζεστε μια σελίδα η οποία χρησιμοποιείται για να παρέχει κείμενο διεπαφής για το λογισμικό. Αλλαγές σε αυτήν τη σελίδα θα επηρεάσουν την εμφάνιση της διεπαφής χρήστη για τους άλλους χρήστες αυτού του wiki.",
        "cascadeprotected": "Αυτή η σελίδα έχει προστατευθεί από επεξεργασία, επειδή περιλαμβάνεται {{PLURAL:$1|στην ακόλουθη σελίδα, που είναι προστατευμένη|στις ακόλουθες σελίδες, που είναι προστατευμένες}} με ενεργοποιημένη τη «διαδοχική» προστασία στο:\n$2",
        "namespaceprotected": "Δεν έχετε άδεια να επεξεργάζεστε σελίδες στον τομέα '''$1'''.",
        "customcssprotected": "Δεν έχετε δικαιώματα για να επεξεργαστείτε αυτή τη σελίδα CSS, επειδή περιέχει προσωπικές ρυθμίσεις άλλου χρήστη.",
index 7845e7b..458a3ea 100644 (file)
        "viewsourcetext": "Vi povas rigardi kaj kopii la fonton de la paĝo:",
        "viewyourtext": "Vi povas vidi kaj kopii la fonton de '''viaj redaktoj''' al ĉi tiu paĝo:",
        "protectedinterface": "Ĉi tiu paĝo provizas interfacan tekston por la programaro, kaj estas ŝlosita por malebligi misuzon.\nPor aldoni aŭ ŝanĝi tradukojn por ĉiuj vikioj, bonvolu uzi [//translatewiki.net/ translatewiki.net], la projekton por provizi tradukojn por MediaWiki.",
-       "editinginterface": "'''Atentu:''' Vi redaktas paĝon, kiu provizas interfacan tekston por la programaro.\nŜanĝoj de ĉi tiu teksto ŝanĝos aspekton de la interfaco por aliaj uzantoj de ĉi tiu vikio.\nPor aldoni aŭ ŝanĝi tradukojn por ĉiuj vikioj, bonvolu uzi [//translatewiki.net/ translatewiki.net], la projekton por provizi tradukojn por MediaWiki.",
+       "editinginterface": "<strong>Atentu:</strong> Vi redaktas paĝon, kiu provizas interfacan tekston por la programaro.\nŜanĝoj de ĉi tiu teksto ŝanĝos aspekton de la interfaco por aliaj uzantoj de ĉi tiu vikio.\nPor aldoni aŭ ŝanĝi tradukojn por ĉiuj vikioj, bonvolu uzi [//translatewiki.net/ translatewiki.net], la projekton por provizi tradukojn por MediaWiki.",
        "cascadeprotected": "Ĉi tiu paĝo estas protektita kontraŭ redaktado, ĉar ĝi estas inkludita en la {{PLURAL:$1|sekvan paĝon, kiu|sekvajn paĝojn, kiuj}} estas {{PLURAL:$1|protektata|protektataj}} kun la \"kaskada\" opcio ŝaltita sur:\n$2",
        "namespaceprotected": "Vi ne rajtas redakti paĝojn en la '''$1''' nomspaco.",
        "customcssprotected": "Vi ne rajtas redakti ĉi tiun CSS-paĝon, ĉar ĝi enhavas personajn alĝustigojn de alia uzanto.",
        "recentchanges-label-plusminus": "La paĝa grandeco ŝanĝiĝis je ĉi tiu nombro de bajtoj",
        "recentchanges-legend-heading": "'''Klarigo:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (vidu ankaŭ [[Special:NewPages|liston de novaj paĝoj]])",
-       "rcnotefrom": "Malsupre estas ŝanĝoj ekde <strong>$2</strong> ({{PLURAL:$1|lasta|lastaj}} <strong>$1</strong>).",
+       "rcnotefrom": "Malsupre estas la {{PLURAL:$5|ŝanĝo|ŝanĝoj}} ekde <strong>$3, $4</strong> (montrante ĝis <strong>$1</strong>).",
        "rclistfrom": "Montri novajn ŝanĝojn ekde \"$3 $2\"",
        "rcshowhideminor": "$1 redaktetojn",
        "rcshowhideminor-show": "Montri",
        "license": "Permesiloj:",
        "license-header": "Permesiloj:",
        "nolicense": "Neniu elektita",
+       "licenses-edit": "Modifi opciojn de permesilo",
        "license-nopreview": "(Antaŭvido ne montrebla)",
-       "upload_source_url": " (valida, publike atingebla URL-o)",
+       "upload_source_url": " (via elektita dosiero de valida, publike atingebla URL-o)",
        "upload_source_file": "(dosiero elektita de via komputilo)",
        "listfiles-delete": "forigi",
        "listfiles-summary": "Ĉi tiu speciala paĝo montras ĉiujn alŝutitajn dosierojn.\nKiam oni filtras ĝin laŭ uzanto, nur la aktuala versio de la dosiero estos montrita.",
        "pager-older-n": "{{PLURAL:$1|pli malnova 1|pli malnovaj $1}}",
        "suppress": "Superrigardo",
        "querypage-disabled": "Tiu ĉi speciala paĝo estas malfunkciigita pro rendimentaj kialoj.",
+       "apihelp-no-such-module": "Modulo \"$1\" ne estis trovita.",
        "booksources": "Libroservoj",
        "booksources-search-legend": "Serĉi librofontojn",
        "booksources-search": "Serĉi",
        "delete-edit-reasonlist": "Redakti kialojn de forigo",
        "delete-toobig": "Ĉi tiu paĝo havas grandan redakto-historion, pli ol $1 {{PLURAL:$1|version|versiojn}}. Forigo de ĉi tiaj paĝoj estis limigitaj por preventi akcidentan disrompigon de {{SITENAME}}.",
        "delete-warning-toobig": "Ĉi tiu paĝo havas grandan redakto-historion, pli ol $1 {{PLURAL:$1|version|versiojn}}. Forigo de ĝi povas disrompigi operacion de {{SITENAME}}; forigu singarde.",
+       "deleteprotected": "Vi ne povas forigi ĉi tiun paĝon ĉar ĝi estis protektita.",
        "deleting-backlinks-warning": "'''Atentigo:'''\n[[Special:WhatLinksHere/{{FULLPAGENAME}}|Aliaj paĝoj]] ligas al aŭ transkludas tiun ĉi forigotan paĝon.",
        "rollback": "Restarigi antaŭan redakton",
        "rollback_short": "Malfari",
        "ipb-change-block": "Reforbari la uzanton kun ĉi tiuj preferoj",
        "ipb-confirm": "Konfirmi forbaron",
        "badipaddress": "Neniu uzanto, aŭ la IP-adreso estas misformita.",
-       "blockipsuccesssub": "Oni sukcese forbaris la adreson/nomon.",
+       "blockipsuccesssub": "Forbaro sukcesis.",
        "blockipsuccesstext": "[[Special:Contributions/$1|$1]] estas forbarita. <br />\nVidu la [[Special:BlockList|liston de forbaroj]] por kontroli.",
        "ipb-blockingself": "Vi preskaŭ forbaros vin mem! Ĉu vi certas ke vi volas fari ĉi tiel?",
        "ipb-confirmhideuser": "Vi preskaŭ forbaras uzanto kun \"kaŝi uzanton\" ŝalta. Ĉi tiu kaŝi la nomon de uzanto en ĉiuj listoj ka protokoloj. Ĉu vi certas ke vi volas fari ĉi tiel?",
        "unblocked": "[[User:$1|$1]] estas restarigita.",
        "unblocked-range": "$1 estis malforbarita",
        "unblocked-id": "Forbaro $1 estas forigita.",
+       "unblocked-ip": "[[Special:Contributions/$1|$1]] estis malforbarita.",
        "blocklist": "Forbaritaj uzantoj",
        "ipblocklist": "Forbaritaj uzantoj",
        "ipblocklist-legend": "Trovi forbaritan uzanton.",
        "movepagetalktext": "La movo aŭtomate kunportos la diskuto-paĝon, se tia ekzistas, '''krom se:'''\n*Vi movas la paĝon tra nomspacoj (ekz de ''Nomo'' je ''User:Nomo''),\n*Ne malplena diskuto-paĝo jam ekzistas je la nova nomo, aŭ\n*Vi malelektas la suban ŝaltilon.\n\nTiujokaze, vi nepre permane kunigu la diskuto-paĝojn se vi tion deziras.",
        "movearticle": "Alinomigi paĝon",
        "moveuserpage-warning": "'''Averto:''' Vi preskaŭ alinomigas paĝon de uzanto. Bonvolu noti ke nur la paĝo estos alinomigita kaj la uzanto mem ''ne'' estos alinomigita.",
+       "movecategorypage-warning": "<strong>Averto:</strong> Vi baldaŭ movos kategorian paĝon. Bonvolu noti ke, nur la paĝo estos movita, kaj la paĝoj en la malnova kategorio <em>ne</em> transiros en la novan kategorion.",
        "movenologintext": "Vi nepre estu registrita uzanto kaj [[Special:UserLogin|ensalutu]] por rajti movi paĝojn.",
        "movenotallowed": "Vi ne rajtas movi paĝojn.",
        "movenotallowedfile": "Vi ne havas rajton alinomigi dosierojn.",
        "cant-move-user-page": "Vi ne rajtas movi radikajn uzanto-paĝojn.",
        "cant-move-to-user-page": "Vi ne rajtas movi paĝon al uzantopaĝo (krom al uzantosubpaĝo).",
+       "cant-move-category-page": "Vi ne rajtas movi kategoriajn paĝojn.",
+       "cant-move-to-category-page": "Vi ne rajtas movi paĝon al kategoria paĝo.",
        "newtitle": "Al nova titolo",
        "move-watch": "Atenti ĉi tiun paĝon",
        "movepagebtn": "Alinomigi paĝon",
        "tooltip-feed-atom": "Atom-fonto por ĉi tiu paĝo",
        "tooltip-t-contributions": "Rigardi la liston de kontribuoj de tiu ĉi uzanto",
        "tooltip-t-emailuser": "Sendi retmesaĝon al tiu ĉi uzanto",
+       "tooltip-t-info": "Pli da informo pri ĉi tiu paĝo",
        "tooltip-t-upload": "Alŝuti bildojn aŭ dosierojn",
        "tooltip-t-specialpages": "Listo de ĉiuj specialaj paĝoj",
        "tooltip-t-print": "Printebla versio de ĉi tiu paĝo",
        "logentry-rights-rights": "$1 ŝanĝis grupan membrecon por $3 de $4 al $5",
        "logentry-rights-rights-legacy": "$1 ŝanĝis grupan membrecon por $3",
        "logentry-rights-autopromote": "$1 estis aŭtomate {{GENDER:$2|altrangigita}} de $4 al $5",
+       "logentry-upload-upload": "$1 {{GENDER:$2|alŝutis}} $3",
+       "logentry-upload-overwrite": "$1 {{GENDER:$2|alŝutis}} novan version de $3",
        "logentry-upload-revert": "$1 {{GENDER:$2|alŝutis}} $3",
        "rightsnone": "(nenia)",
        "revdelete-summary": "redaktoresumon",
        "mediastatistics-header-multimedia": "Multmediaj",
        "mediastatistics-header-office": "Oficejaj",
        "mediastatistics-header-text": "Tekstaj",
+       "mediastatistics-header-executable": "Plenumeblaj dosieroj",
        "json-error-syntax": "Sintaksa eraro"
 }
index 26c6123..b0c02ce 100644 (file)
@@ -11,7 +11,8 @@
                        "Snakesteuben",
                        "Urhixidur",
                        "לערי ריינהארט",
-                       "아라"
+                       "아라",
+                       "Robin0van0der0vliet"
                ]
        },
        "tog-underline": "Keppelings ûnderstreekje:",
        "listingcontinuesabbrev": "(ferfolch)",
        "index-category": "Yndeksearre siden",
        "noindex-category": "Net-yndeksearre siden",
-       "about": "Ynfo",
+       "about": "Oer",
        "article": "Ynhâld side",
        "newwindow": "(nij finster)",
-       "cancel": "Ofbrekke",
+       "cancel": "Annulearje",
        "moredotdotdot": "Mear...",
        "mypage": "Myn side",
        "mytalk": "Myn oerlis",
        "faqpage": "Project:Faak stelde fragen",
        "namespaces": "Nammeromten",
        "variants": "Farianten",
-       "errorpagetitle": "Fout",
+       "errorpagetitle": "Flater",
        "returnto": "Werom nei \"$1\".",
        "tagline": "Ut {{SITENAME}}",
        "help": "Help",
        "permalink": "Fêste keppeling",
        "print": "Ofdrukke",
        "view": "Lêze",
-       "edit": "Feroarje",
+       "edit": "Bewurkje",
        "create": "Oanmeitsje",
        "editthispage": "Side bewurkje",
        "create-this-page": "Dizze side oanmeitsje",
        "jumptonavigation": "navigaasje",
        "jumptosearch": "sykje",
        "view-pool-error": "Ekskuseare, de tsjinners hawwe it op it stuit te drok.\nTefolle meidoggers probearje dizze side te besjen.\nWachtsje efkes foardatsto op 'e nij tagong ta dizze side probearrest te krijen.\n\n$1",
-       "aboutsite": "Oer de {{SITENAME}}",
+       "aboutsite": "Oer {{SITENAME}}",
        "aboutpage": "Project:Ynfo",
        "copyright": "Ynhâld is beskikber ûnder de $1.",
        "copyrightpage": "{{ns:project}}:Auteursrjocht",
        "badaccess-groups": "De frege hanneling is foarbehâlden oan brûkers yn {{PLURAL:$2|'e groep|ien fan de groepen}}: $1.",
        "versionrequired": "Ferzje $1 fan MediaWiki is eask",
        "versionrequiredtext": "Ferzje $1 fan MediaWiki is eask om dizze side te brûken. Mear ynfo is beskikber op 'e side [[Special:Version|softwareferzje]].",
-       "ok": "Goed",
+       "ok": "OK",
        "retrievedfrom": "Untfongen fan \"$1\"",
        "youhavenewmessages": "Jo hawwe $1 ($2).",
        "youhavenewmessagesmulti": "Jo hawwe nije berjochten op $1",
        "toc": "Ynhâld",
        "showtoc": "sjen litte",
        "hidetoc": "net sjen litte",
+       "confirmable-yes": "Ja",
+       "confirmable-no": "Nee",
        "thisisdeleted": "\"$1\" lêze of werombringe?",
        "viewdeleted": "$1 sjen litte?",
        "restorelink": "$1 wiske {{PLURAL:$1|ferzje|ferzjes}}",
        "nosuchactiontext": "De opdracht yn de URL is ûnjildich.\nMooglik hasto in typefout makke yn de URL of in ferkearde keppeling folge.\nIt soe likegoed in programmatuerflater fan {{SITENAME}} wêze kinne.",
        "nosuchspecialpage": "Unbekende side",
        "nospecialpagetext": "Jo hawwe in Wiki-side opfrege dy't net bekend is by it Wiki-programma.",
-       "error": "Fout",
+       "error": "Flater",
        "databaseerror": "Databankfout",
+       "databaseerror-error": "Flater: $1",
        "laggedslavemode": "Warskôging: Mûglik binne resinte bewurkings noch net trochfierd.",
        "readonly": "Databank is 'Net-skriuwe'.",
        "enterlockreason": "Skriuw wêrom de databank 'net-skriuwe' makke is, en hoenear't men wêr nei alle gedachten wer skriuwe kin.",
        "virus-scanfailed": "scannen is mislearre (koade $1)",
        "virus-unknownscanner": "ûnbekend antivirus:",
        "logouttext": "'''Jo binne no ôfmeld.'''\n\nGuon siden kinne noch foar it ljocht komme, krekt as wiesto noch oanmeld. Asto de cache fan dyn webblêder leechhellest feroaret dat wer.",
-       "yourname": "Jo meidochnamme:",
-       "userlogin-yourname": "Meidoggersnamme",
+       "yourname": "Brûkersnamme:",
+       "userlogin-yourname": "Brûkersnamme",
        "userlogin-yourname-ph": "Jou dyn brûkersnamme",
        "createacct-another-username-ph": "Jou dyn brûkersnamme",
-       "yourpassword": "Jo wachtwurd",
+       "yourpassword": "Wachtwurd:",
        "userlogin-yourpassword": "Wachtwurd",
        "userlogin-yourpassword-ph": "Jou dyn wachtwurd",
        "createacct-yourpassword-ph": "Jou dyn wachtwurd",
        "resetpass_forbidden": "Wachtwurden kinne net feroare wurde",
        "resetpass-no-info": "Jo moatte oanmeld wêze foar't Jo dizze side brûke kinne.",
        "resetpass-submit-loggedin": "Wachtwurd feroarje",
-       "resetpass-submit-cancel": "Ofbrekke",
+       "resetpass-submit-cancel": "Annulearje",
        "resetpass-wrong-oldpass": "It momintele of tydlike wachtwurd is ûnjildich.\nMûglik hawwe Jo Jo wachtwurd al feroare of in nij tydlik wachtwurd oanfrege.",
        "resetpass-temp-password": "Tydlik wachtwurd:",
        "passwordreset-legend": "Wachtwurd weromsette",
-       "passwordreset-username": "Meidoggernamme",
+       "passwordreset-username": "Brûkersnamme:",
        "passwordreset-domain": "Domein:",
        "passwordreset-email": "E-mailadres:",
        "passwordreset-emailtitle": "Akkountdetails op {{SITENAME}}",
        "timezoneregion-indian": "Yndyske Oseaan",
        "timezoneregion-pacific": "Stille Oseaan",
        "allowemail": "Lit my ek netpost fan oare meidoggers krije",
-       "prefs-searchoptions": "Sykynstellings",
+       "prefs-searchoptions": "Sykje",
        "prefs-namespaces": "Nammeromten",
        "default": "standert",
-       "prefs-files": "Triemen",
+       "prefs-files": "Triemmen",
        "prefs-custom-js": "Persoanlik JS",
        "prefs-emailconfirm-label": "Netpostbefêstiging:",
-       "youremail": "Jo netpostadres:",
-       "username": "Meidochnamme:",
+       "youremail": "E-mail:",
+       "username": "{{GENDER:$1|Brûkersnamme}}:",
        "prefs-memberingroups": "Lid fan {{PLURAL:$1|groep|groepen}}:",
        "yourrealname": "Jo wiere namme:",
        "yourlanguage": "Taal:",
        "gender-male": "Man",
        "gender-female": "Frou",
        "prefs-help-gender": "Kar: dit wurdt troch de programmatuer brûkt om de goeie oansprekfoarm te kiezen.\nDizze ynformaasje is foar oare meidoggers te sjen.",
-       "email": "E-post",
+       "email": "E-mail",
        "prefs-help-realname": "Echte namme is net ferplicht; as jo dy opjouwe kin dy namme brûkt wurde om jo erkenning te jaan foar jo wurk.",
        "prefs-help-email": "E-post is opsjoneel, mar makket it mûglik jo wachtwurd te stjoeren as jo it fergetten hawwe.\nJo kinne ek oaren de mûglikheid jaan kontakt mei jo op te nimmen troch in ferwizing op jo brûkers- en oerlisside, sûnder dat jo jo identiteit oer hoege te jaan.",
        "prefs-help-email-required": "Hjir is in e-mailadres foar nedich.",
        "action-userrights": "alle brûkersrjochten bewurkje",
        "action-userrights-interwiki": "brûkersrjochten fan brûkers fan oare wiki's bewurkje",
        "action-siteadmin": "de database ôfslute of iepenstelle",
+       "action-sendemail": "e-mail stjoere:",
        "nchanges": "$1 {{PLURAL:$1|bewurking|bewurkings}}",
+       "enhancedrc-history": "skiednis",
        "recentchanges": "Koartlyn feroare",
        "recentchanges-legend": "Opsjes foar resinte feroarings",
        "recentchanges-summary": "De lêste feroarings fan de {{SITENAME}}.",
        "listusers-creationsort": "Oarderje op dei fan oanmeitsjen",
        "usereditcount": "$1 {{PLURAL:$1|bewurking|bewurkings}}",
        "newpages": "Nije siden",
-       "newpages-username": "Meidoggernamme:",
+       "newpages-username": "Brûkersnamme:",
        "ancientpages": "Alde siden",
        "move": "Werneam",
        "movethispage": "Werneam dizze side",
        "noemailtitle": "Gjin e-postadres",
        "noemailtext": "Dizze meidogger hat gjin jildich e-postadres ynsteld, of hat oanjûn gjin post fan oare meidoggers krije te wollen.",
        "nowikiemailtext": "Dizze brûker wol gjin e-mail ûntfange fan oare brûkers.",
+       "emailusername": "Brûkersnamme:",
        "email-legend": "In e-mail ferstjoere nei in oare brûker fan {{SITENAME}}",
        "emailfrom": "Fan:",
        "emailto": "Oan:",
-       "emailsubject": "Oer",
+       "emailsubject": "Ûnderwerp:",
        "emailmessage": "Berjocht:",
        "emailsend": "Stjoer",
        "emailsent": "Berjocht stjoerd",
        "undelete-search-prefix": "Lit siden sjen dy't begjinne mei:",
        "undelete-search-submit": "Sykje",
        "undelete-no-results": "Gjin oerienkommende siden fûn yn it wisk argyf.",
+       "undelete-show-file-submit": "Ja",
        "namespace": "Nammeromte:",
        "invert": "Seleksje útsein",
        "blanknamespace": "(Haadnammerûmte)",
        "unblocklink": "lit yn",
        "change-blocklink": "blokkade feroarje",
        "contribslink": "bydragen",
+       "emaillink": "e-mail stjoere:",
        "autoblocker": "Jo wiene útsletten om't jo ynternet-adres oerienkomt mei dat fan \"[[User:$1|$1]]\". Foar it útsluten fan dy meidogger waard dizze reden jûn: \"$2\".",
        "blocklogpage": "Utslútloch",
        "blocklogentry": "\"[[$1]]\" útsletten foar $2 $3",
        "allmessagesdefault": "Standerttekst",
        "allmessagescurrent": "Tekst yn de nijste ferzje",
        "allmessagestext": "Dit is in list fan alle systeemberjochten beskikber yn de MediaWiki-nammeromte.\nSjoch: [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation], [//translatewiki.net translatewiki.net].",
+       "allmessages-language": "Taal:",
        "thumbnail-more": "Fergrutsje",
        "filemissing": "Triem net fûn",
        "thumbnail_error": "Flater by it oanmeitsjen fan thumbnail: $1",
        "siteusers": "{{SITENAME}} {{PLURAL:$2|meidogger|meidoggers}} $1",
        "spamprotectiontext": "De side dy't jo fêstlizze woene is blokkearre troch in spam filter. Dit wurdt wierskynlik feroarsake troch in ferwizing nei in ekstern webstee.",
        "spamprotectionmatch": "De neikommende tekst hat it spam filter aktivearre: $1",
+       "pageinfo-contentpage-yes": "Ja",
+       "pageinfo-protect-cascading-yes": "Ja",
        "markaspatrolleddiff": "Markearje as kontroleare",
        "markaspatrolledtext": "Markearje dizze side as kontrolearre",
        "markedaspatrolled": "Markearre as kontrolearre",
        "version-other": "Oare",
        "version-version": "(Ferzje $1)",
        "version-license": "Lisinsje",
+       "version-ext-colheader-version": "Ferzje",
        "version-software": "Ynsteld software",
        "version-software-product": "Produkt",
        "version-software-version": "Ferzje",
        "compare-rev2": "Revyzje 2",
        "compare-submit": "Ferlykje",
        "compare-invalid-title": "Unjildige titel.",
+       "htmlform-no": "Nee",
+       "htmlform-yes": "Ja",
        "revdelete-restricted": "hat beheinings oplein oan behearders",
        "revdelete-unrestricted": "hat beheinings foar behearders goedmakke",
        "rightsnone": "(gjin)",
        "revdelete-summary": "gearfetting bewurkje",
        "feedback-subject": "Underwerp:",
        "feedback-message": "Berjocht:",
-       "feedback-cancel": "Ofbrekke",
+       "feedback-cancel": "Annulearje",
        "feedback-submit": "Feedback ferstjoere",
        "feedback-close": "Dien",
        "searchsuggest-search": "Sykje",
        "expand_templates_ok": "Okee",
-       "expand_templates_remove_comments": "Berjochten fuorthelje"
+       "expand_templates_remove_comments": "Berjochten fuorthelje",
+       "pagelang-language": "Taal"
 }
index e3282c9..e9504f5 100644 (file)
        "api-error-stashfailed": "Ralat dalaman: pelayan tidak dapat menyimpan fail sementara.",
        "api-error-publishfailed": "Ralat dalaman: Pelayan tidak dapat menerbitkan fail sementara.",
        "api-error-stasherror": "Terdapat ralat ketika menyimpan fail yang dimuat naik.",
+       "api-error-stashedfilenotfound": "Fail yang disimpan tidak dijumpai apabila cuba untuk memuat naik dari simpanan.",
+       "api-error-stashpathinvalid": "Laluan di mana fail disimpan sepatutnya didapati tidak sah.",
+       "api-error-stashfilestorage": "Terdapat ralat semasa menyimpan fail dalam simpanan.",
+       "api-error-stashzerolength": "Pelayan tidak dapat menyimpan fail, kerana ia mempunyai panjang sifar.",
        "api-error-timeout": "Pelayan tidak bergerak balas dalam tempoh yang diharapkan.",
        "api-error-unclassified": "Berlakunya ralat yang tidak diketahui",
        "api-error-unknown-code": "Ralat tidak diketahui: \"$1\"",
index e91800e..24a9572 100644 (file)
@@ -25,7 +25,8 @@
                        "Withoutaname",
                        "לערי ריינהארט",
                        "아라",
-                       "Tranquanganh"
+                       "Tranquanganh",
+                       "Max20091"
                ]
        },
        "tog-underline": "Gạch chân liên kết:",
@@ -38,7 +39,7 @@
        "tog-showtoolbar": "Hiển thị thanh định dạng",
        "tog-editondblclick": "Nhấn đúp để sửa đổi trang",
        "tog-editsectiononrightclick": "Bấm chuột phải vào đề mục để sửa đổi phần trang",
-       "tog-watchcreations": "Tự động theo dõi các trang tôi viết mới và các tập tin tôi tải lên",
+       "tog-watchcreations": "Tự động theo dõi các trang tôi viết và các tập tin tôi tải lên",
        "tog-watchdefault": "Tự động theo dõi các trang và tập tin tôi sửa",
        "tog-watchmoves": "Tự động theo dõi các trang và tập tin tôi di chuyển",
        "tog-watchdeletion": "Tự động theo dõi các trang và tập tin tôi xóa",
index 12154de..78f36cd 100644 (file)
        "sort-descending": "降序",
        "sort-ascending": "升序",
        "nstab-main": "页面",
-       "nstab-user": "用户页",
+       "nstab-user": "用户页",
        "nstab-media": "媒体文件页面",
        "nstab-special": "特殊页面",
        "nstab-project": "项目页面",
index b2dfe1e..e53ed54 100644 (file)
@@ -1002,6 +1002,7 @@ return array(
                'dependencies' => array(
                        'jquery.cookie',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
        'mediawiki.toolbar' => array(
                'class' => 'ResourceLoaderEditToolbarModule',
@@ -1604,17 +1605,18 @@ return array(
                        'minerva' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.svg.css',
                ),
                'messages' => array(
+                       'ooui-dialog-message-accept',
+                       'ooui-dialog-message-reject',
+                       'ooui-dialog-process-continue',
+                       'ooui-dialog-process-dismiss',
+                       'ooui-dialog-process-error',
+                       'ooui-dialog-process-retry',
                        'ooui-outline-control-move-down',
                        'ooui-outline-control-move-up',
                        'ooui-outline-control-remove',
                        'ooui-toolbar-more',
                        'ooui-toolgroup-collapse',
                        'ooui-toolgroup-expand',
-                       'ooui-dialog-message-accept',
-                       'ooui-dialog-message-reject',
-                       'ooui-dialog-process-dismiss',
-                       'ooui-dialog-process-error',
-                       'ooui-dialog-process-retry',
                ),
                'dependencies' => array(
                        'es5-shim',
index c62df22..f8a990c 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs v1.1.1 optimised for jQuery
+ * OOjs v1.1.2 optimised for jQuery
  * https://www.mediawiki.org/wiki/OOjs
  *
  * Copyright 2011-2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-09-11T00:40:09Z
+ * Date: 2014-11-06T17:42:36Z
  */
 ( function ( global ) {
 
@@ -506,11 +506,6 @@ oo.isPlainObject = $.isPlainObject;
                        if ( context === undefined || context === null ) {
                                throw new Error( 'Method name "' + method + '" has no context.' );
                        }
-                       if ( !( method in context ) ) {
-                               // Technically the method does not need to exist yet: it could be
-                               // added before call time. But this probably signals a typo.
-                               throw new Error( 'Method not found: "' + method + '"' );
-                       }
                        if ( typeof context[method] !== 'function' ) {
                                // Technically the property could be replaced by a function before
                                // call time. But this probably signals a typo.
@@ -593,7 +588,7 @@ oo.isPlainObject = $.isPlainObject;
 
                validateMethod( method, context );
 
-               if ( !( event in this.bindings ) || !this.bindings[event].length ) {
+               if ( !hasOwn.call( this.bindings, event ) || !this.bindings[event].length ) {
                        // No matching bindings
                        return this;
                }
@@ -632,7 +627,7 @@ oo.isPlainObject = $.isPlainObject;
        oo.EventEmitter.prototype.emit = function ( event ) {
                var i, len, binding, bindings, args, method;
 
-               if ( event in this.bindings ) {
+               if ( hasOwn.call( this.bindings, event ) ) {
                        // Slicing ensures that we don't get tripped up by event handlers that add/remove bindings
                        bindings = this.bindings[event].slice();
                        args = Array.prototype.slice.call( arguments, 1 );