* Updated oyejorge/less.php from v1.7.0.10 to v1.7.0.14.
* Updated monolog from v1.18.2 to 1.22.1.
* Updated wikimedia/composer-merge-plugin from v1.3.1 to v1.4.0.
+* Updated OOjs from v1.1.10 to v2.0.0.
==== New external libraries ====
* Added wikimedia/timestamp v1.0.0.
'Digit2Html' => __DIR__ . '/maintenance/language/digit2html.php',
'DjVuHandler' => __DIR__ . '/includes/media/DjVu.php',
'DjVuImage' => __DIR__ . '/includes/media/DjVuImage.php',
+ 'DnsSrvDiscoverer' => __DIR__ . '/includes/libs/DnsSrvDiscoverer.php',
'DoubleRedirectJob' => __DIR__ . '/includes/jobqueue/jobs/DoubleRedirectJob.php',
'DoubleRedirectsPage' => __DIR__ . '/includes/specials/SpecialDoubleRedirects.php',
'DoubleReplacer' => __DIR__ . '/includes/libs/replacers/DoubleReplacer.php',
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Account_creation';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Account_creation';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Block';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Block';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Manage_authentication_data';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Manage_authentication_data';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:ClearHasMsg';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:ClearHasMsg';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Login';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Login';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Delete';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Delete';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Edit';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Edit';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Email';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Email';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#expandtemplates';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parsing_wikitext#expandtemplates';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Watchlist_feed';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlist_feed';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Data_formats';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Data_formats';
}
}
public function getHelpUrls() {
return [
- 'https://www.mediawiki.org/wiki/API:Main_page',
- 'https://www.mediawiki.org/wiki/API:FAQ',
- 'https://www.mediawiki.org/wiki/API:Quick_start_guide',
+ 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Main_page',
+ 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:FAQ',
+ 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Quick_start_guide',
];
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Import';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Import';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Linkaccount';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Linkaccount';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Login';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Login';
}
/**
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Logout';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Logout';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Tag_management';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Tag_management';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Mergehistory';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Mergehistory';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Move';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Move';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Opensearch';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Opensearch';
}
/**
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Options';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Options';
}
protected function getExamplesMessages() {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Parameter_information';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parameter_information';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#parse';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Parsing_wikitext#parse';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Patrol';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Patrol';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Protect';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Protect';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Purge';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Purge';
}
}
public function getHelpUrls() {
return [
- 'https://www.mediawiki.org/wiki/API:Query',
- 'https://www.mediawiki.org/wiki/API:Meta',
- 'https://www.mediawiki.org/wiki/API:Properties',
- 'https://www.mediawiki.org/wiki/API:Lists',
+ 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Query',
+ 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Meta',
+ 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Properties',
+ 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Lists',
];
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Allcategories';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allcategories';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Alldeletedrevisions';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Alldeletedrevisions';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Allimages';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allimages';
}
}
public function getHelpUrls() {
$name = ucfirst( $this->getModuleName() );
- return "https://www.mediawiki.org/wiki/API:{$name}";
+ return "https://www.mediawiki.org/wiki/Special:MyLanguage/API:{$name}";
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Allmessages';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allmessages';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Allpages';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allpages';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Allrevisions';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allrevisions';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Allusers';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allusers';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Authmanagerinfo';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Authmanagerinfo';
}
}
'code' => 'bl',
'prefix' => 'pl',
'linktbl' => 'pagelinks',
- 'helpurl' => 'https://www.mediawiki.org/wiki/API:Backlinks',
+ 'helpurl' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Backlinks',
],
'embeddedin' => [
'code' => 'ei',
'prefix' => 'tl',
'linktbl' => 'templatelinks',
- 'helpurl' => 'https://www.mediawiki.org/wiki/API:Embeddedin',
+ 'helpurl' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Embeddedin',
],
'imageusage' => [
'code' => 'iu',
'prefix' => 'il',
'linktbl' => 'imagelinks',
- 'helpurl' => 'https://www.mediawiki.org/wiki/API:Imageusage',
+ 'helpurl' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Imageusage',
]
];
public function getHelpUrls() {
$name = ucfirst( $this->getModuleName() );
- return "https://www.mediawiki.org/wiki/API:{$name}";
+ return "https://www.mediawiki.org/wiki/Special:MyLanguage/API:{$name}";
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Blocks';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Blocks';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Categories';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Categories';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Categoryinfo';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Categoryinfo';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Categorymembers';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Categorymembers';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Contributors';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Contributors';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Deletedrevisions';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Deletedrevisions';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Deletedrevs';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Deletedrevs';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Duplicatefiles';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Duplicatefiles';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Exturlusage';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Exturlusage';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Extlinks';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Extlinks';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Filerepoinfo';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Filerepoinfo';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Filearchive';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Filearchive';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Iwbacklinks';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Iwbacklinks';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Iwlinks';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Iwlinks';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Imageinfo';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Imageinfo';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Images';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Images';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Info';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Info';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Langbacklinks';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Langbacklinks';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Langlinks';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Langlinks';
}
}
$this->table = 'pagelinks';
$this->prefix = 'pl';
$this->titlesParam = 'titles';
- $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Links';
+ $this->helpUrl = 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Links';
break;
case self::TEMPLATES:
$this->table = 'templatelinks';
$this->prefix = 'tl';
$this->titlesParam = 'templates';
- $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Templates';
+ $this->helpUrl = 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Templates';
break;
default:
ApiBase::dieDebug( __METHOD__, 'Unknown module name' );
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Logevents';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Logevents';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:mystashedfiles';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:mystashedfiles';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Pagepropnames';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Pagepropnames';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Pageprops';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Pageprops';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Pageswithprop';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Pageswithprop';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Prefixsearch';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Prefixsearch';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Protectedtitles';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Protectedtitles';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Querypage';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Querypage';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Random';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Random';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Recentchanges';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Recentchanges';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Revisions';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Revisions';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Search';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Search';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Siteinfo';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Siteinfo';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Stashimageinfo';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Stashimageinfo';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Tags';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Tags';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Tokens';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Tokens';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Usercontribs';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Usercontribs';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Userinfo';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Userinfo';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Users';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Users';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Watchlist';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlist';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Watchlistraw';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlistraw';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Manage_authentication_data';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Manage_authentication_data';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Manage_authentication_data';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Manage_authentication_data';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Revisiondelete';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Revisiondelete';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Rollback';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Rollback';
}
}
'apiLink' => wfExpandUrl( wfScript( 'api' ), PROTO_CURRENT ),
// Docs link is optional, but recommended.
- 'docs' => 'https://www.mediawiki.org/wiki/API',
+ 'docs' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/API',
// Some APIs may need a blog ID, but it may be left blank.
'blogID' => '',
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:SetNotificationTimestamp';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:SetNotificationTimestamp';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:SetPageLanguage';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:SetPageLanguage';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Tag';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Tag';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Block';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Block';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Undelete';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Undelete';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Upload';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Upload';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:User_group_membership';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:User_group_membership';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Validatepassword';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Validatepassword';
}
}
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Watch';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watch';
}
}
]
},
- "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentation]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API Announcements]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bugs & requests]\n</div>\n<strong>Status:</strong> All features shown on this page should be working, but the API is still in active development, and may change at any time. Subscribe to [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce mailing list] for notice of updates.\n\n<strong>Erroneous requests:</strong> When erroneous requests are sent to the API, an HTTP header will be sent with the key \"MediaWiki-API-Error\" and then both the value of the header and the error code sent back will be set to the same value. For more information see [[mw:API:Errors_and_warnings|API: Errors and warnings]].\n\n<strong>Testing:</strong> For ease of testing API requests, see [[Special:ApiSandbox]].",
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Documentation]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API Announcements]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bugs & requests]\n</div>\n<strong>Status:</strong> All features shown on this page should be working, but the API is still in active development, and may change at any time. Subscribe to [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce mailing list] for notice of updates.\n\n<strong>Erroneous requests:</strong> When erroneous requests are sent to the API, an HTTP header will be sent with the key \"MediaWiki-API-Error\" and then both the value of the header and the error code sent back will be set to the same value. For more information see [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Errors and warnings]].\n\n<strong>Testing:</strong> For ease of testing API requests, see [[Special:ApiSandbox]].",
"apihelp-main-param-action": "Which action to perform.",
"apihelp-main-param-format": "The format of the output.",
- "apihelp-main-param-maxlag": "Maximum lag can be used when MediaWiki is installed on a database replicated cluster. To save actions causing any more site replication lag, this parameter can make the client wait until the replication lag is less than the specified value. In case of excessive lag, error code <samp>maxlag</samp> is returned with a message like <samp>Waiting for $host: $lag seconds lagged</samp>.<br />See [[mw:Manual:Maxlag_parameter|Manual: Maxlag parameter]] for more information.",
+ "apihelp-main-param-maxlag": "Maximum lag can be used when MediaWiki is installed on a database replicated cluster. To save actions causing any more site replication lag, this parameter can make the client wait until the replication lag is less than the specified value. In case of excessive lag, error code <samp>maxlag</samp> is returned with a message like <samp>Waiting for $host: $lag seconds lagged</samp>.<br />See [[mw:Special:MyLanguage/Manual:Maxlag_parameter|Manual: Maxlag parameter]] for more information.",
"apihelp-main-param-smaxage": "Set the <code>s-maxage</code> HTTP cache control header to this many seconds. Errors are never cached.",
"apihelp-main-param-maxage": "Set the <code>max-age</code> HTTP cache control header to this many seconds. Errors are never cached.",
"apihelp-main-param-assert": "Verify the user is logged in if set to <kbd>user</kbd>, or has the bot user right if <kbd>bot</kbd>.",
"apihelp-block-param-autoblock": "Automatically block the last used IP address, and any subsequent IP addresses they try to login from.",
"apihelp-block-param-noemail": "Prevent user from sending email through the wiki. (Requires the <code>blockemail</code> right).",
"apihelp-block-param-hidename": "Hide the username from the block log. (Requires the <code>hideuser</code> right).",
- "apihelp-block-param-allowusertalk": "Allow the user to edit their own talk page (depends on <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
+ "apihelp-block-param-allowusertalk": "Allow the user to edit their own talk page (depends on <var>[[mw:Special:MyLanguage/Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
"apihelp-block-param-reblock": "If the user is already blocked, overwrite the existing block.",
"apihelp-block-param-watchuser": "Watch the user's or IP address's user and talk pages.",
"apihelp-block-param-tags": "Change tags to apply to the entry in the block log.",
"apihelp-opensearch-param-search": "Search string.",
"apihelp-opensearch-param-limit": "Maximum number of results to return.",
"apihelp-opensearch-param-namespace": "Namespaces to search.",
- "apihelp-opensearch-param-suggest": "Do nothing if <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> is false.",
+ "apihelp-opensearch-param-suggest": "Do nothing if <var>[[mw:Special:MyLanguage/Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> is false.",
"apihelp-opensearch-param-redirects": "How to handle redirects:\n;return:Return the redirect itself.\n;resolve:Return the target page. May return fewer than $1limit results.\nFor historical reasons, the default is \"return\" for $1format=json and \"resolve\" for other formats.",
"apihelp-opensearch-param-format": "The format of the output.",
"apihelp-opensearch-param-warningsaserror": "If warnings are raised with <kbd>format=json</kbd>, return an API error instead of ignoring them.",
"apihelp-query+alldeletedrevisions-param-user": "Only list revisions by this user.",
"apihelp-query+alldeletedrevisions-param-excludeuser": "Don't list revisions by this user.",
"apihelp-query+alldeletedrevisions-param-namespace": "Only list pages in this namespace.",
- "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>Note:</strong> Due to [[mw:Manual:$wgMiserMode|miser mode]], using <var>$1user</var> and <var>$1namespace</var> together may result in fewer than <var>$1limit</var> results returned before continuing; in extreme cases, zero results may be returned.",
+ "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>Note:</strong> Due to [[mw:Special:MyLanguage/Manual:$wgMiserMode|miser mode]], using <var>$1user</var> and <var>$1namespace</var> together may result in fewer than <var>$1limit</var> results returned before continuing; in extreme cases, zero results may be returned.",
"apihelp-query+alldeletedrevisions-param-generatetitles": "When being used as a generator, generate titles rather than revision IDs.",
"apihelp-query+alldeletedrevisions-example-user": "List the last 50 deleted contributions by user <kbd>Example</kbd>.",
"apihelp-query+alldeletedrevisions-example-ns-main": "List the first 50 deleted revisions in the main namespace.",
"apihelp-query+filearchive-example-simple": "Show a list of all deleted files.",
"apihelp-query+filerepoinfo-description": "Return meta information about image repositories configured on the wiki.",
- "apihelp-query+filerepoinfo-param-prop": "Which repository properties to get (there may be more available on some wikis):\n;apiurl:URL to the repository API - helpful for getting image info from the host.\n;name:The key of the repository - used in e.g. <var>[[mw:Manual:$wgForeignFileRepos|$wgForeignFileRepos]]</var> and [[Special:ApiHelp/query+imageinfo|imageinfo]] return values.\n;displayname:The human-readable name of the repository wiki.\n;rooturl:Root URL for image paths.\n;local:Whether that repository is the local one or not.",
+ "apihelp-query+filerepoinfo-param-prop": "Which repository properties to get (there may be more available on some wikis):\n;apiurl:URL to the repository API - helpful for getting image info from the host.\n;name:The key of the repository - used in e.g. <var>[[mw:Special:MyLanguage/Manual:$wgForeignFileRepos|$wgForeignFileRepos]]</var> and [[Special:ApiHelp/query+imageinfo|imageinfo]] return values.\n;displayname:The human-readable name of the repository wiki.\n;rooturl:Root URL for image paths.\n;local:Whether that repository is the local one or not.",
"apihelp-query+filerepoinfo-example-simple": "Get information about file repositories.",
"apihelp-query+fileusage-description": "Find all pages that use the given files.",
"apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "Returns wiki rights (license) information if available.",
"apihelp-query+siteinfo-paramvalue-prop-restrictions": "Returns information on available restriction (protection) types.",
"apihelp-query+siteinfo-paramvalue-prop-languages": "Returns a list of languages MediaWiki supports (optionally localised by using <var>$1inlanguagecode</var>).",
- "apihelp-query+siteinfo-paramvalue-prop-languagevariants": "Returns a list of language codes for which [[mw:LanguageConverter|LanguageConverter]] is enabled, and the variants supported for each.",
+ "apihelp-query+siteinfo-paramvalue-prop-languagevariants": "Returns a list of language codes for which [[mw:Special:MyLanguage/LanguageConverter|LanguageConverter]] is enabled, and the variants supported for each.",
"apihelp-query+siteinfo-paramvalue-prop-skins": "Returns a list of all enabled skins (optionally localised by using <var>$1inlanguagecode</var>, otherwise in the content language).",
"apihelp-query+siteinfo-paramvalue-prop-extensiontags": "Returns a list of parser extension tags.",
"apihelp-query+siteinfo-paramvalue-prop-functionhooks": "Returns a list of parser function hooks.",
- "apihelp-query+siteinfo-paramvalue-prop-showhooks": "Returns a list of all subscribed hooks (contents of <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "Returns a list of all subscribed hooks (contents of <var>[[mw:Special:MyLanguage/Manual:$wgHooks|$wgHooks]]</var>).",
"apihelp-query+siteinfo-paramvalue-prop-variables": "Returns a list of variable IDs.",
"apihelp-query+siteinfo-paramvalue-prop-protocols": "Returns a list of protocols that are allowed in external links.",
"apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Returns the default values for user preferences.",
"apihelp-query+usercontribs-paramvalue-prop-flags": "Adds flags of the edit.",
"apihelp-query+usercontribs-paramvalue-prop-patrolled": "Tags patrolled edits.",
"apihelp-query+usercontribs-paramvalue-prop-tags": "Lists tags for the edit.",
- "apihelp-query+usercontribs-param-show": "Show only items that meet these criteria, e.g. non minor edits only: <kbd>$2show=!minor</kbd>.\n\nIf <kbd>$2show=patrolled</kbd> or <kbd>$2show=!patrolled</kbd> is set, revisions older than <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|second|seconds}}) won't be shown.",
+ "apihelp-query+usercontribs-param-show": "Show only items that meet these criteria, e.g. non minor edits only: <kbd>$2show=!minor</kbd>.\n\nIf <kbd>$2show=patrolled</kbd> or <kbd>$2show=!patrolled</kbd> is set, revisions older than <var>[[mw:Special:MyLanguage/Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|second|seconds}}) won't be shown.",
"apihelp-query+usercontribs-param-tag": "Only list revisions tagged with this tag.",
"apihelp-query+usercontribs-param-toponly": "Only list changes which are the latest revision.",
"apihelp-query+usercontribs-example-user": "Show contributions of user <kbd>Example</kbd>.",
"apihelp-removeauthenticationdata-example-simple": "Attempt to remove the current user's data for <kbd>FooAuthenticationRequest</kbd>.",
"apihelp-resetpassword-description": "Send a password reset email to a user.",
- "apihelp-resetpassword-description-noroutes": "No password reset routes are available.\n\nEnable routes in <var>[[mw:Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var> to use this module.",
+ "apihelp-resetpassword-description-noroutes": "No password reset routes are available.\n\nEnable routes in <var>[[mw:Special:MyLanguage/Manual:$wgPasswordResetRoutes|$wgPasswordResetRoutes]]</var> to use this module.",
"apihelp-resetpassword-param-user": "User being reset.",
"apihelp-resetpassword-param-email": "Email address of the user being reset.",
"apihelp-resetpassword-example-user": "Send a password reset email to user <kbd>Example</kbd>.",
"apihelp-setnotificationtimestamp-example-allpages": "Reset the notification status for pages in the <kbd>{{ns:user}}</kbd> namespace.",
"apihelp-setpagelanguage-description": "Change the language of a page.",
- "apihelp-setpagelanguage-description-disabled": "Changing the language of a page is not allowed on this wiki.\n\nEnable <var>[[mw:Manual:$wgPageLanguageUseDB|$wgPageLanguageUseDB]]</var> to use this action.",
+ "apihelp-setpagelanguage-description-disabled": "Changing the language of a page is not allowed on this wiki.\n\nEnable <var>[[mw:Special:MyLanguage/Manual:$wgPageLanguageUseDB|$wgPageLanguageUseDB]]</var> to use this action.",
"apihelp-setpagelanguage-param-title": "Title of the page whose language you wish to change. Cannot be used together with <var>$1pageid</var>.",
"apihelp-setpagelanguage-param-pageid": "Page ID of the page whose language you wish to change. Cannot be used together with <var>$1title</var>.",
"apihelp-setpagelanguage-param-lang": "Language code of the language to change the page to. Use <kbd>default</kbd> to reset the page to the wiki's default content language.",
"apihelp-xmlfm-description": "Output data in XML format (pretty-print in HTML).",
"api-format-title": "MediaWiki API result",
- "api-format-prettyprint-header": "This is the HTML representation of the $1 format. HTML is good for debugging, but is unsuitable for application use.\n\nSpecify the <var>format</var> parameter to change the output format. To see the non-HTML representation of the $1 format, set <kbd>format=$2</kbd>.\n\nSee the [[mw:API|complete documentation]], or the [[Special:ApiHelp/main|API help]] for more information.",
- "api-format-prettyprint-header-only-html": "This is an HTML representation intended for debugging, and is unsuitable for application use.\n\nSee the [[mw:API|complete documentation]], or the [[Special:ApiHelp/main|API help]] for more information.",
+ "api-format-prettyprint-header": "This is the HTML representation of the $1 format. HTML is good for debugging, but is unsuitable for application use.\n\nSpecify the <var>format</var> parameter to change the output format. To see the non-HTML representation of the $1 format, set <kbd>format=$2</kbd>.\n\nSee the [[mw:Special:MyLanguage/API|complete documentation]], or the [[Special:ApiHelp/main|API help]] for more information.",
+ "api-format-prettyprint-header-only-html": "This is an HTML representation intended for debugging, and is unsuitable for application use.\n\nSee the [[mw:Special:MyLanguage/API|complete documentation]], or the [[Special:ApiHelp/main|API help]] for more information.",
"api-format-prettyprint-status": "This response would be returned with HTTP status $1 $2.",
"api-pageset-param-titles": "A list of titles to work on.",
"api-help-param-default-empty": "Default: <span class=\"apihelp-empty\">(empty)</span>",
"api-help-param-token": "A \"$1\" token retrieved from [[Special:ApiHelp/query+tokens|action=query&meta=tokens]]",
"api-help-param-token-webui": "For compatibility, the token used in the web UI is also accepted.",
- "api-help-param-disabled-in-miser-mode": "Disabled due to [[mw:Manual:$wgMiserMode|miser mode]].",
- "api-help-param-limited-in-miser-mode": "<strong>Note:</strong> Due to [[mw:Manual:$wgMiserMode|miser mode]], using this may result in fewer than <var>$1limit</var> results returned before continuing; in extreme cases, zero results may be returned.",
+ "api-help-param-disabled-in-miser-mode": "Disabled due to [[mw:Special:MyLanguage/Manual:$wgMiserMode|miser mode]].",
+ "api-help-param-limited-in-miser-mode": "<strong>Note:</strong> Due to [[mw:Special:MyLanguage/Manual:$wgMiserMode|miser mode]], using this may result in fewer than <var>$1limit</var> results returned before continuing; in extreme cases, zero results may be returned.",
"api-help-param-direction": "In which direction to enumerate:\n;newer:List oldest first. Note: $1start has to be before $1end.\n;older:List newest first (default). Note: $1start has to be later than $1end.",
"api-help-param-continue": "When more results are available, use this to continue.",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(no description)</span>",
--- /dev/null
+<?php
+/**
+ * Service discovery using DNS SRV records
+ *
+ * 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
+ */
+
+/**
+ * @since 1.29
+ */
+class DnsSrvDiscoverer {
+ /**
+ * @var string
+ */
+ private $domain;
+
+ /**
+ * @param string $domain
+ */
+ public function __construct( $domain ) {
+ $this->domain = $domain;
+ }
+
+ /**
+ * Fetch the servers with a DNS SRV request
+ *
+ * @return array
+ */
+ public function getServers() {
+ $result = [];
+ foreach ( $this->getDnsRecords() as $record ) {
+ $result[] = [
+ 'target' => $record['target'],
+ 'port' => $record['port'],
+ 'pri' => $record['pri'],
+ 'weight' => $record['weight'],
+ ];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Pick a server according to the priority fields.
+ * Note that weight is currently ignored.
+ *
+ * @param array $servers from getServers
+ * @return array|bool
+ */
+ public function pickServer( array $servers ) {
+ if ( !$servers ) {
+ return false;
+ }
+
+ $srvsByPrio = [];
+ foreach ( $servers as $server ) {
+ $srvsByPrio[$server['pri']][] = $server;
+ }
+
+ $min = min( array_keys( $srvsByPrio ) );
+ if ( count( $srvsByPrio[$min] ) == 1 ) {
+ return $srvsByPrio[$min][0];
+ } else {
+ // Choose randomly
+ $rand = mt_rand( 0, count( $srvsByPrio[$min] ) - 1 );
+
+ return $srvsByPrio[$min][$rand];
+ }
+ }
+
+ /**
+ * @return array[]
+ */
+ protected function getDnsRecords() {
+ return dns_get_record( $this->domain, DNS_SRV );
+ }
+}
'special-characters-group-thai',
'special-characters-group-lao',
'special-characters-group-khmer',
+ 'special-characters-group-canadianaboriginal',
'special-characters-title-endash',
'special-characters-title-emdash',
'special-characters-title-minus'
* @param string $name
*/
protected function renderAfterPortlet( $name ) {
+ echo $this->getAfterPortlet( $name );
+ }
+
+ /**
+ * Allows extensions to hook into known portlets and add stuff to them
+ *
+ * @param string $name
+ *
+ * @return string html
+ * @since 1.29
+ */
+ protected function getAfterPortlet( $name ) {
+ $html = '';
$content = '';
Hooks::run( 'BaseTemplateAfterPortlet', [ $this, $name, &$content ] );
if ( $content !== '' ) {
- echo "<div class='after-portlet after-portlet-$name'>$content</div>";
+ $html = Html::rawElement(
+ 'div',
+ [ 'class' => [ 'after-portlet', 'after-portlet-' . $name ] ],
+ $content
+ );
}
+
+ return $html;
}
/**
return $footericons;
}
+ /**
+ * Renderer for getFooterIcons and getFooterLinks
+ *
+ * @param string $iconStyle $option for getFooterIcons: "icononly", "nocopyright"
+ * @param string $linkStyle $option for getFooterLinks: "flat"
+ *
+ * @return string html
+ * @since 1.29
+ */
+ protected function getFooter( $iconStyle = 'icononly', $linkStyle = 'flat' ) {
+ $validFooterIcons = $this->getFooterIcons( $iconStyle );
+ $validFooterLinks = $this->getFooterLinks( $linkStyle );
+
+ $html = '';
+
+ if ( count( $validFooterIcons ) + count( $validFooterLinks ) > 0 ) {
+ $html .= Html::openElement( 'div', [
+ 'id' => 'footer-bottom',
+ 'role' => 'contentinfo',
+ 'lang' => $this->get( 'userlang' ),
+ 'dir' => $this->get( 'dir' )
+ ] );
+ $footerEnd = Html::closeElement( 'div' );
+ } else {
+ $footerEnd = '';
+ }
+ foreach ( $validFooterIcons as $blockName => $footerIcons ) {
+ $html .= Html::openElement( 'div', [
+ 'id' => 'f-' . Sanitizer::escapeId( $blockName ) . 'ico',
+ 'class' => 'footer-icons'
+ ] );
+ foreach ( $footerIcons as $icon ) {
+ $html .= $this->getSkin()->makeFooterIcon( $icon );
+ }
+ $html .= Html::closeElement( 'div' );
+ }
+ if ( count( $validFooterLinks ) > 0 ) {
+ $html .= Html::openElement( 'ul', [ 'id' => 'f-list', 'class' => 'footer-places' ] );
+ foreach ( $validFooterLinks as $aLink ) {
+ $html .= Html::rawElement(
+ 'li',
+ [ 'id' => Sanitizer::escapeId( $aLink ) ],
+ $this->get( $aLink )
+ );
+ }
+ $html .= Html::closeElement( 'ul' );
+ }
+
+ $html .= $this->clear() . $footerEnd;
+
+ return $html;
+ }
+
+ /**
+ * Get a div with the core visualClear class, for clearing floats
+ *
+ * @return string html
+ * @since 1.29
+ */
+ protected function clear() {
+ return Html::element( 'div', [ 'class' => 'visualClear' ] );
+ }
+
/**
* Get the suggested HTML for page status indicators: icons (or short text snippets) usually
* displayed in the top-right corner of the page, outside of the main content.
}
/**
- * Output the basic end-page trail including bottomscripts, reporttime, and
+ * Output getTrail
+ */
+ function printTrail() {
+ echo $this->getTrail();
+ }
+
+ /**
+ * Get the basic end-page trail including bottomscripts, reporttime, and
* debug stuff. This should be called right before outputting the closing
* body and html tags.
+ *
+ * @return string
+ * @since 1.29
*/
- function printTrail() {
-?>
-<?php echo MWDebug::getDebugHTML( $this->getSkin()->getContext() ); ?>
-<?php $this->html( 'bottomscripts' ); /* JS call to runBodyOnloadHook */ ?>
-<?php $this->html( 'reporttime' ) ?>
-<?php
+ function getTrail() {
+ $html = MWDebug::getDebugHTML( $this->getSkin()->getContext() );
+ $html .= $this->get( 'bottomscripts' );
+ $html .= $this->get( 'reporttime' );
+
+ return $html;
}
}
"userrights-groupsmember": "Member of:",
"userrights-groupsmember-auto": "Implicit member of:",
"userrights-groupsmember-type": "$1",
- "userrights-groups-help": "You may alter the groups this user is in:\n* A checked box means the user is in that group.\n* An unchecked box means the user is not in that group.\n* A * indicates that you cannot remove the group once you have added it, or vice versa.\n* A # indicates that you can only put back the expiration time of this group; you cannot bring it forward.",
+ "userrights-groups-help": "You may alter the groups this user is in:\n* A checked box means the user is in that group.\n* An unchecked box means the user is not in that group.\n* A * indicates that you cannot remove the group once you have added it, or vice versa.\n* A # indicates that you can only put back the expiration time of this group membership; you cannot bring it forward.",
"userrights-reason": "Reason:",
"userrights-no-interwiki": "You do not have permission to edit user rights on other wikis.",
"userrights-nodatabase": "Database $1 does not exist or is not local.",
"userrights-expiry-options": "1 day:1 day,1 week:1 week,1 month:1 month,3 months:3 months,6 months:6 months,1 year:1 year",
"userrights-invalid-expiry": "The expiry time for group \"$1\" is invalid.",
"userrights-expiry-in-past": "The expiry time for group \"$1\" is in the past.",
- "userrights-cannot-shorten-expiry": "You cannot bring forward the expiry of group \"$1\". Only users with permission to add and remove this group can bring forward expiry times.",
+ "userrights-cannot-shorten-expiry": "You cannot bring forward the expiry of membership in group \"$1\". Only users with permission to add and remove this group can bring forward expiry times.",
"userrights-conflict": "Conflict of user rights changes! Please review and confirm your changes.",
"group": "Group:",
"group-user": "Users",
"special-characters-group-thai": "Thai",
"special-characters-group-lao": "Lao",
"special-characters-group-khmer": "Khmer",
+ "special-characters-group-canadianaboriginal": "Canadian Aboriginal",
"special-characters-title-endash": "en dash",
"special-characters-title-emdash": "em dash",
"special-characters-title-minus": "minus sign",
"userrights-groupsmember": "Used when editing user groups in [[Special:Userrights]].\n\nThe message is followed by a list of group names.\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER",
"userrights-groupsmember-auto": "Used when editing user groups in [[Special:Userrights]]. The message is followed by a list of group names.\n\n\"Implicit\" is for groups that the user was automatically added to (such as \"autoconfirmed\"); cf. {{msg-mw|userrights-groupsmember}}\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER",
"userrights-groupsmember-type": "{{optional}}\nParameters:\n* $1 - list of group names\n* $2 - list of group member names. Used with labels {{msg-mw|Userrights-groupsmember}} and {{msg-mw|Userrights-groupsmember-auto}}",
- "userrights-groups-help": "Instructions displayed on [[Special:UserRights]]. Parameters:\n* $1 - (Optional) a username, can be used for GENDER",
+ "userrights-groups-help": "Instructions displayed on [[Special:UserRights]]. \"Bring forward\" is a phrasal verb meaning \"move to an earlier time\". \"Put back\" means the opposite. Parameters:\n* $1 - (Optional) a username, can be used for GENDER",
"userrights-reason": "Text beside log field when editing user groups\n\n{{Identical|Reason}}",
"userrights-no-interwiki": "Error message when editing user groups",
"userrights-nodatabase": "Error message when editing user groups.\n\n\"Local\" means databases/wikis of the same farm/cluster; that is, meta, enwiki, dewiki, commons, etc are all local databases of the Wikimedia Foundation.\n\nSee [{{canonicalurl:meta:Special:Log|type=rights}} meta:Special:Log?type=rights] for a usage of local databases: username@barwiki\n\nParameters:\n* $1 - database name",
"special-characters-group-thai": "The name of the [[w:Thai alphabet|Thai]] character set (alphabet).",
"special-characters-group-lao": "{{Identical|Lao}}",
"special-characters-group-khmer": "{{Identical|Khmer}}",
+ "special-characters-group-canadianaboriginal": "The name of the [[w:Canadian Aboriginal syllabics|Canadian Aboriginal]] character set (alphabet).",
"special-characters-title-endash": "Title tooltip for the en dash character (–); See https://en.wikipedia.org/wiki/Dash",
"special-characters-title-emdash": "Title tooltip for the em dash character (—); See https://en.wikipedia.org/wiki/Dash",
"special-characters-title-minus": "Title tooltip for the minus sign character (−), not to be confused with a hyphen",
}
public function execute() {
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
+ $services = MediaWikiServices::getInstance();
+ $lbFactory = $services->getDBLoadBalancerFactory();
+ $stats = $services->getStatsdDataFactory();
+ $lbsByType = [
+ 'main' => $lbFactory->getAllMainLBs(),
+ 'external' => $lbFactory->getAllExternalLBs()
+ ];
- $lbs = $lbFactory->getAllMainLBs() + $lbFactory->getAllExternalLBs();
- foreach ( $lbs as $cluster => $lb ) {
- if ( $lb->getServerCount() <= 1 ) {
- continue;
- }
- $lags = $lb->getLagTimes();
- foreach ( $lags as $serverIndex => $lag ) {
- $host = $lb->getServerName( $serverIndex );
- if ( IP::isValid( $host ) ) {
- $ip = $host;
- $host = gethostbyaddr( $host );
- } else {
- $ip = gethostbyname( $host );
+ foreach ( $lbsByType as $type => $lbs ) {
+ foreach ( $lbs as $cluster => $lb ) {
+ if ( $lb->getServerCount() <= 1 ) {
+ continue;
}
+ $lags = $lb->getLagTimes();
+ foreach ( $lags as $serverIndex => $lag ) {
+ $host = $lb->getServerName( $serverIndex );
+ if ( IP::isValid( $host ) ) {
+ $ip = $host;
+ $host = gethostbyaddr( $host );
+ } else {
+ $ip = gethostbyname( $host );
+ }
- $starLen = min( intval( $lag ), 40 );
- $stars = str_repeat( '*', $starLen );
- $this->output( sprintf( "%10s %20s %3d %s\n", $ip, $host, $lag, $stars ) );
+ $starLen = min( intval( $lag ), 40 );
+ $stars = str_repeat( '*', $starLen );
+ $this->output( sprintf( "%10s %20s %3d %s\n", $ip, $host, $lag, $stars ) );
- if ( $this->hasOption( 'report' ) ) {
- $stats->gauge( "loadbalancer.lag.$cluster.$host", $lag );
+ if ( $this->hasOption( 'report' ) ) {
+ $group = ( $type === 'external' ) ? 'external' : $cluster;
+ $stats->gauge( "loadbalancer.lag.$group.$host", intval( $lag * 1e3 ) );
+ }
}
}
}
};
</script>
<script>
- // Emulate startup.js
- var mwPerformance = { mark: function () {} };
+ // Mock startup.js
+ var mwPerformance = { mark: function () {} },
+ mwNow = Date.now;
function startUp() {
mw.config = new mw.Map();
}
</script>
<script src="modules/lib/jquery/jquery.js"></script>
- <script src="modules/lib/phpjs-sha1/sha1.js"></script>
<script src="modules/src/mediawiki/mediawiki.js"></script>
<script src="modules/src/mediawiki/mediawiki.errorLogger.js"></script>
- <script src="modules/src/mediawiki/mediawiki.startUp.js"></script>
<script src="modules/lib/oojs/oojs.jquery.js"></script>
<script src="modules/lib/oojs-ui/oojs-ui-core.js"></script>
<script src="modules/lib/oojs-ui/oojs-ui-widgets.js"></script>
background: #fff;
}
</style>
- <link rel="stylesheet" href="modules/src/oojs-ui/oojs-ui-local.css">
+ <link rel="stylesheet" href="modules/src/oojs-ui-local.css">
<link rel="stylesheet" href="modules/lib/oojs-ui/oojs-ui-core-mediawiki.css">
<link rel="stylesheet" href="modules/lib/oojs-ui/oojs-ui-widgets-mediawiki.css">
<link rel="stylesheet" href="modules/lib/oojs-ui/oojs-ui-toolbars-mediawiki.css">
/*!
- * OOjs v1.1.10 optimised for jQuery
+ * OOjs v2.0.0 optimised for jQuery
* https://www.mediawiki.org/wiki/OOjs
*
- * Copyright 2011-2015 OOjs Team and other contributors.
+ * Copyright 2011-2017 OOjs Team and other contributors.
* Released under the MIT license
- * http://oojs.mit-license.org
+ * https://oojs.mit-license.org
*
- * Date: 2015-11-11T16:49:11Z
+ * Date: 2017-04-05T02:18:04Z
*/
( function ( global ) {
'use strict';
-/*exported toString */
+/* exported toString */
var
/**
* Namespace for all classes, static methods and static properties.
oo = {},
// Optimisation: Local reference to Object.prototype.hasOwnProperty
hasOwn = oo.hasOwnProperty,
- toString = oo.toString,
- // Object.create() is impossible to fully polyfill, so don't require it
- createObject = Object.create || ( function () {
- // Reusable constructor function
- function Empty() {}
- return function ( prototype, properties ) {
- var obj;
- Empty.prototype = prototype;
- obj = new Empty();
- if ( properties && hasOwn.call( properties, 'constructor' ) ) {
- obj.constructor = properties.constructor.value;
- }
- return obj;
- };
- } )();
+ toString = oo.toString;
/* Class Methods */
oo.inheritClass = function ( targetFn, originFn ) {
var targetConstructor;
+ if ( !originFn ) {
+ throw new Error( 'inheritClass: Origin is not a function (actually ' + originFn + ')' );
+ }
if ( targetFn.prototype instanceof originFn ) {
- throw new Error( 'Target already inherits from origin' );
+ throw new Error( 'inheritClass: Target already inherits from origin' );
}
targetConstructor = targetFn.prototype.constructor;
// by IE 8 and below (bug 63303).
// Provide .parent as alias for code supporting older browsers which
// allows people to comply with their style guide.
+ // eslint-disable-next-line dot-notation
targetFn[ 'super' ] = targetFn.parent = originFn;
- targetFn.prototype = createObject( originFn.prototype, {
+ targetFn.prototype = Object.create( originFn.prototype, {
// Restore constructor property of targetFn
constructor: {
value: targetConstructor,
// Extend static properties - always initialize both sides
oo.initClass( originFn );
- targetFn.static = createObject( originFn.static );
+ targetFn.static = Object.create( originFn.static );
};
/**
oo.mixinClass = function ( targetFn, originFn ) {
var key;
+ if ( !originFn ) {
+ throw new Error( 'mixinClass: Origin is not a function (actually ' + originFn + ')' );
+ }
+
// Copy prototype properties
for ( key in originFn.prototype ) {
if ( key !== 'constructor' && hasOwn.call( originFn.prototype, key ) ) {
}
};
+/**
+ * Test whether one class is a subclass of another, without instantiating it.
+ *
+ * Every class is considered a subclass of Object and of itself.
+ *
+ * @param {Function} testFn The class to be tested
+ * @param {Function} baseFn The base class
+ * @return {boolean} Whether testFn is a subclass of baseFn (or equal to it)
+ */
+oo.isSubclass = function ( testFn, baseFn ) {
+ return testFn === baseFn || testFn.prototype instanceof baseFn;
+};
+
/* Object Methods */
/**
* Get a deeply nested property of an object using variadic arguments, protecting against
* undefined property errors.
*
- * `quux = oo.getProp( obj, 'foo', 'bar', 'baz' );` is equivalent to `quux = obj.foo.bar.baz;`
+ * `quux = OO.getProp( obj, 'foo', 'bar', 'baz' );` is equivalent to `quux = obj.foo.bar.baz;`
* except that the former protects against JS errors if one of the intermediate properties
* is undefined. Instead of throwing an error, this function will return undefined in
* that case.
oo.setProp = function ( obj ) {
var i,
prop = obj;
- if ( Object( obj ) !== obj ) {
+ if ( Object( obj ) !== obj || arguments.length < 2 ) {
return;
}
for ( i = 1; i < arguments.length - 2; i++ ) {
prop[ arguments[ arguments.length - 2 ] ] = arguments[ arguments.length - 1 ];
};
+/**
+ * Delete a deeply nested property of an object using variadic arguments, protecting against
+ * undefined property errors, and deleting resulting empty objects.
+ *
+ * @param {Object} obj
+ * @param {...Mixed} [keys]
+ */
+oo.deleteProp = function ( obj ) {
+ var i,
+ prop = obj,
+ props = [ prop ];
+ if ( Object( obj ) !== obj || arguments.length < 2 ) {
+ return;
+ }
+ for ( i = 1; i < arguments.length - 1; i++ ) {
+ if ( prop[ arguments[ i ] ] === undefined || Object( prop[ arguments[ i ] ] ) !== prop[ arguments[ i ] ] ) {
+ return;
+ }
+ prop = prop[ arguments[ i ] ];
+ props.push( prop );
+ }
+ delete prop[ arguments[ i ] ];
+ // Walk back through props removing any plain empty objects
+ while ( ( prop = props.pop() ) && oo.isPlainObject( prop ) && !Object.keys( prop ).length ) {
+ delete props[ props.length - 1 ][ arguments[ props.length ] ];
+ }
+};
+
/**
* Create a new object that is an instance of the same
* constructor as the input, inherits from the same object
oo.cloneObject = function ( origin ) {
var key, r;
- r = createObject( origin.constructor.prototype );
+ r = Object.create( origin.constructor.prototype );
for ( key in origin ) {
if ( hasOwn.call( origin, key ) ) {
right = arr.length;
while ( left < right ) {
// Equivalent to Math.floor( ( left + right ) / 2 ) but much faster
- /*jshint bitwise:false */
+ // eslint-disable-next-line no-bitwise
mid = ( left + right ) >> 1;
cmpResult = searchFunc( arr[ mid ] );
if ( cmpResult < 0 ) {
normalized[ keys[ i ] ] = val[ keys[ i ] ];
}
return normalized;
-
- // Primitive values and arrays get stable hashes
- // by default. Lets those be stringified as-is.
} else {
+ // Primitive values and arrays get stable hashes
+ // by default. Lets those be stringified as-is.
return val;
}
};
return simpleArrayCombine( a, b, false );
};
-/*global $ */
+/* global $ */
oo.isPlainObject = $.isPlainObject;
-/*global hasOwn */
+/* global hasOwn */
( function () {
* Don't call this directly unless you know what you're doing.
* Use #addItems instead.
*
- * @private
+ * This method can be extended in child classes to produce
+ * different behavior when an item is inserted. For example,
+ * inserted items may also be attached to the DOM or may
+ * interact with some other nodes in certain ways. Extending
+ * this method is allowed, but if overriden, the aggregation
+ * of events must be preserved, or behavior of emitted events
+ * will be broken.
+ *
+ * If you are extending this method, please make sure the
+ * parent method is called.
+ *
+ * @protected
* @param {OO.EventEmitter} item Items to add
* @param {number} index Index to add items at
* @return {number} The index the item was added at
// Insert item at the insertion index
index = this.insertItem( items[ i ], insertionIndex );
- this.emit( 'add', items[ i ], insertionIndex );
+ this.emit( 'add', items[ i ], index );
}
return this;
};
-/*global hasOwn */
+/* global hasOwn */
/**
* @class OO.Registry
}
};
-/*global createObject */
-
/**
* @class OO.Factory
* @extends OO.Registry
*/
oo.Factory = function OoFactory() {
// Parent constructor
- oo.Factory.parent.call( this );
+ oo.Factory.super.call( this );
};
/* Inheritance */
}
// Parent method
- oo.Factory.parent.prototype.register.call( this, name, constructor );
+ oo.Factory.super.prototype.register.call( this, name, constructor );
};
/**
}
// Parent method
- oo.Factory.parent.prototype.unregister.call( this, name );
+ oo.Factory.super.prototype.unregister.call( this, name );
};
/**
// the constructor's prototype (which also makes it an "instanceof" the constructor),
// then invoke the constructor with the object as context, and return it (ignoring
// the constructor's return value).
- obj = createObject( constructor.prototype );
+ obj = Object.create( constructor.prototype );
constructor.apply( obj, args );
return obj;
};
-/*jshint node:true */
+/* eslint-env node */
if ( typeof module !== 'undefined' && module.exports ) {
module.exports = oo;
} else {
var result;
// Check if we're already dealing with an array of colors
- if ( color && $.isArray( color ) && color.length === 3 ) {
+ if ( color && Array.isArray( color ) && color.length === 3 ) {
return color;
}
return false;
}
for ( i = 0; i < arrThis.length; i++ ) {
- if ( $.isArray( arrThis[ i ] ) ) {
+ if ( Array.isArray( arrThis[ i ] ) ) {
if ( !$.compareArray( arrThis[ i ], arrAgainst[ i ] ) ) {
return false;
}
],
"khmer": [
"ក", "ខ", "គ", "ឃ", "ង", "ច", "ឆ", "ជ", "ឈ", "ញ", "ដ", "ឋ", "ឌ", "ឍ", "ណ", "ត", "ថ", "ទ", "ធ", "ន", "ប", "ផ", "ព", "ភ", "ម", "យ", "រ", "ល", "វ", "ស", "ហ", "ឡ", "អ", "ឣ", "ឤ", "ឥ", "ឦ", "ឧ", "ឨ", "ឩ", "ឪ", "ឫ", "ឬ", "ឭ", "ឮ", "ឯ", "ឰ", "ឱ", "ឲ", "ឳ", "្", "឴", "឵", "ា", "ិ", "ី", "ឹ", "ឺ", "ុ", "ូ", "ួ", "ើ", "ឿ", "ៀ", "េ", "ែ", "ៃ", "ោ", "ៅ", "ំ", "ះ", "ៈ", "៉", "៊", "់", "៌", "៍", "៎", "៏", "័", "៑", "៓", "៝", "ៜ", "០", "១", "២", "៣", "៤", "៥", "៦", "៧", "៨", "៩", "៛", "។", "៕", "៖", "ៗ", "៘", "៙", "៚", "៰", "៱", "៲", "៳", "៴", "៵", "៶", "៷", "៸", "៹", "᧠", "᧡", "᧢", "᧣", "᧤", "᧥", "᧦", "᧧", "᧨", "᧩", "᧪", "᧫", "᧬", "᧭", "᧮", "᧯", "᧰", "᧱", "᧲", "᧳", "᧴", "᧵", "᧶", "᧷", "᧸", "᧹", "᧺", "᧻", "᧼", "᧽", "᧾", "᧿"
+ ],
+ "canadianaboriginal": [
+ "ᐁ", "ᐂ", "ᐃ", "ᐄ", "ᐅ", "ᐆ", "ᐇ", "ᐈ", "ᐉ", "ᐊ", "ᐋ", "ᐌ", "ᐍ", "ᐎ", "ᐏ", "ᐐ",
+ "ᐑ", "ᐒ", "ᐓ", "ᐔ", "ᐕ", "ᐖ", "ᐗ", "ᐘ", "ᐙ", "ᐚ", "ᐛ", "ᐜ", "ᐝ", "ᐞ", "ᐟ", "ᐠ",
+ "ᐡ", "ᐢ", "ᐣ", "ᐤ", "ᐥ", "ᐦ", "ᐧ", "ᐨ", "ᐩ", "ᐪ", "ᐫ", "ᐬ", "ᐭ", "ᐮ", "ᐯ", "ᐰ",
+ "ᐱ", "ᐲ", "ᐳ", "ᐴ", "ᐵ", "ᐶ", "ᐷ", "ᐸ", "ᐹ", "ᐺ", "ᐻ", "ᐼ", "ᐽ", "ᐾ", "ᐿ", "ᑀ",
+ "ᑁ", "ᑂ", "ᑃ", "ᑄ", "ᑅ", "ᑆ", "ᑇ", "ᑈ", "ᑉ", "ᑊ", "ᑋ", "ᑌ", "ᑍ", "ᑎ", "ᑏ", "ᑐ",
+ "ᑑ", "ᑒ", "ᑓ", "ᑔ", "ᑕ", "ᑖ", "ᑗ", "ᑘ", "ᑙ", "ᑚ", "ᑛ", "ᑜ", "ᑝ", "ᑞ", "ᑟ", "ᑠ",
+ "ᑡ", "ᑢ", "ᑣ", "ᑤ", "ᑥ", "ᑦ", "ᑧ", "ᑨ", "ᑩ", "ᑪ", "ᑫ", "ᑬ", "ᑭ", "ᑮ", "ᑯ", "ᑰ",
+ "ᑱ", "ᑲ", "ᑳ", "ᑴ", "ᑵ", "ᑶ", "ᑷ", "ᑸ", "ᑹ", "ᑺ", "ᑻ", "ᑼ", "ᑽ", "ᑾ", "ᑿ", "ᒀ",
+ "ᒁ", "ᒂ", "ᒃ", "ᒄ", "ᒅ", "ᒆ", "ᒇ", "ᒈ", "ᒉ", "ᒊ", "ᒋ", "ᒌ", "ᒍ", "ᒎ", "ᒏ", "ᒐ",
+ "ᒑ", "ᒒ", "ᒓ", "ᒔ", "ᒕ", "ᒖ", "ᒗ", "ᒘ", "ᒙ", "ᒚ", "ᒛ", "ᒜ", "ᒝ", "ᒞ", "ᒟ", "ᒠ",
+ "ᒡ", "ᒢ", "ᒣ", "ᒤ", "ᒥ", "ᒦ", "ᒧ", "ᒨ", "ᒩ", "ᒪ", "ᒫ", "ᒬ", "ᒭ", "ᒮ", "ᒯ", "ᒰ",
+ "ᒱ", "ᒲ", "ᒳ", "ᒴ", "ᒵ", "ᒶ", "ᒷ", "ᒸ", "ᒹ", "ᒺ", "ᒻ", "ᒼ", "ᒽ", "ᒾ", "ᒿ", "ᓀ",
+ "ᓁ", "ᓂ", "ᓃ", "ᓄ", "ᓅ", "ᓆ", "ᓇ", "ᓈ", "ᓉ", "ᓊ", "ᓋ", "ᓌ", "ᓍ", "ᓎ", "ᓏ", "ᓐ",
+ "ᓑ", "ᓒ", "ᓓ", "ᓔ", "ᓕ", "ᓖ", "ᓗ", "ᓘ", "ᓙ", "ᓚ", "ᓛ", "ᓜ", "ᓝ", "ᓞ", "ᓟ", "ᓠ",
+ "ᓡ", "ᓢ", "ᓣ", "ᓤ", "ᓥ", "ᓦ", "ᓧ", "ᓨ", "ᓩ", "ᓪ", "ᓫ", "ᓬ", "ᓭ", "ᓮ", "ᓯ", "ᓰ",
+ "ᓱ", "ᓲ", "ᓳ", "ᓴ", "ᓵ", "ᓶ", "ᓷ", "ᓸ", "ᓹ", "ᓺ", "ᓻ", "ᓼ", "ᓽ", "ᓾ", "ᓿ", "ᔀ",
+ "ᔁ", "ᔂ", "ᔃ", "ᔄ", "ᔅ", "ᔆ", "ᔇ", "ᔈ", "ᔉ", "ᔊ", "ᔋ", "ᔌ", "ᔍ", "ᔎ", "ᔏ", "ᔐ",
+ "ᔑ", "ᔒ", "ᔓ", "ᔔ", "ᔕ", "ᔖ", "ᔗ", "ᔘ", "ᔙ", "ᔚ", "ᔛ", "ᔜ", "ᔝ", "ᔞ", "ᔟ", "ᔠ",
+ "ᔡ", "ᔢ", "ᔣ", "ᔤ", "ᔥ", "ᔦ", "ᔧ", "ᔨ", "ᔩ", "ᔪ", "ᔫ", "ᔬ", "ᔭ", "ᔮ", "ᔯ", "ᔰ",
+ "ᔱ", "ᔲ", "ᔳ", "ᔴ", "ᔵ", "ᔶ", "ᔷ", "ᔸ", "ᔹ", "ᔺ", "ᔻ", "ᔼ", "ᔽ", "ᔾ", "ᔿ", "ᕀ",
+ "ᕁ", "ᕂ", "ᕃ", "ᕄ", "ᕅ", "ᕆ", "ᕇ", "ᕈ", "ᕉ", "ᕊ", "ᕋ", "ᕌ", "ᕍ", "ᕎ", "ᕏ", "ᕐ",
+ "ᕑ", "ᕒ", "ᕓ", "ᕔ", "ᕕ", "ᕖ", "ᕗ", "ᕘ", "ᕙ", "ᕚ", "ᕛ", "ᕜ", "ᕝ", "ᕞ", "ᕟ", "ᕠ",
+ "ᕡ", "ᕢ", "ᕣ", "ᕤ", "ᕥ", "ᕦ", "ᕧ", "ᕨ", "ᕩ", "ᕪ", "ᕫ", "ᕬ", "ᕭ", "ᕮ", "ᕯ", "ᕰ",
+ "ᕱ", "ᕲ", "ᕳ", "ᕴ", "ᕵ", "ᕶ", "ᕷ", "ᕸ", "ᕹ", "ᕺ", "ᕻ", "ᕼ", "ᕽ", "ᕾ", "ᕿ", "ᖀ",
+ "ᖁ", "ᖂ", "ᖃ", "ᖄ", "ᖅ", "ᖆ", "ᖇ", "ᖈ", "ᖉ", "ᖊ", "ᖋ", "ᖌ", "ᖍ", "ᖎ", "ᖏ", "ᖐ",
+ "ᖑ", "ᖒ", "ᖓ", "ᖔ", "ᖕ", "ᖖ", "ᖗ", "ᖘ", "ᖙ", "ᖚ", "ᖛ", "ᖜ", "ᖝ", "ᖞ", "ᖟ", "ᖠ",
+ "ᖡ", "ᖢ", "ᖣ", "ᖤ", "ᖥ", "ᖦ", "ᖧ", "ᖨ", "ᖩ", "ᖪ", "ᖫ", "ᖬ", "ᖭ", "ᖮ", "ᖯ", "ᖰ",
+ "ᖱ", "ᖲ", "ᖳ", "ᖴ", "ᖵ", "ᖶ", "ᖷ", "ᖸ", "ᖹ", "ᖺ", "ᖻ", "ᖼ", "ᖽ", "ᖾ", "ᖿ", "ᗀ",
+ "ᗁ", "ᗂ", "ᗃ", "ᗄ", "ᗅ", "ᗆ", "ᗇ", "ᗈ", "ᗉ", "ᗊ", "ᗋ", "ᗌ", "ᗍ", "ᗎ", "ᗏ", "ᗐ",
+ "ᗑ", "ᗒ", "ᗓ", "ᗔ", "ᗕ", "ᗖ", "ᗗ", "ᗘ", "ᗙ", "ᗚ", "ᗛ", "ᗜ", "ᗝ", "ᗞ", "ᗟ", "ᗠ",
+ "ᗡ", "ᗢ", "ᗣ", "ᗤ", "ᗥ", "ᗦ", "ᗧ", "ᗨ", "ᗩ", "ᗪ", "ᗫ", "ᗬ", "ᗭ", "ᗮ", "ᗯ", "ᗰ",
+ "ᗱ", "ᗲ", "ᗳ", "ᗴ", "ᗵ", "ᗶ", "ᗷ", "ᗸ", "ᗹ", "ᗺ", "ᗻ", "ᗼ", "ᗽ", "ᗾ", "ᗿ", "ᘀ",
+ "ᘁ", "ᘂ", "ᘃ", "ᘄ", "ᘅ", "ᘆ", "ᘇ", "ᘈ", "ᘉ", "ᘊ", "ᘋ", "ᘌ", "ᘍ", "ᘎ", "ᘏ", "ᘐ",
+ "ᘑ", "ᘒ", "ᘓ", "ᘔ", "ᘕ", "ᘖ", "ᘗ", "ᘘ", "ᘙ", "ᘚ", "ᘛ", "ᘜ", "ᘝ", "ᘞ", "ᘟ", "ᘠ",
+ "ᘡ", "ᘢ", "ᘣ", "ᘤ", "ᘥ", "ᘦ", "ᘧ", "ᘨ", "ᘩ", "ᘪ", "ᘫ", "ᘬ", "ᘭ", "ᘮ", "ᘯ", "ᘰ",
+ "ᘱ", "ᘲ", "ᘳ", "ᘴ", "ᘵ", "ᘶ", "ᘷ", "ᘸ", "ᘹ", "ᘺ", "ᘻ", "ᘼ", "ᘽ", "ᘾ", "ᘿ", "ᙀ",
+ "ᙁ", "ᙂ", "ᙃ", "ᙄ", "ᙅ", "ᙆ", "ᙇ", "ᙈ", "ᙉ", "ᙊ", "ᙋ", "ᙌ", "ᙍ", "ᙎ", "ᙏ", "ᙐ",
+ "ᙑ", "ᙒ", "ᙓ", "ᙔ", "ᙕ", "ᙖ", "ᙗ", "ᙘ", "ᙙ", "ᙚ", "ᙛ", "ᙜ", "ᙝ", "ᙞ", "ᙟ", "ᙠ",
+ "ᙡ", "ᙢ", "ᙣ", "ᙤ", "ᙥ", "ᙦ", "ᙧ", "ᙨ", "ᙩ", "ᙪ", "ᙫ", "ᙬ", "᙭", "᙮", "ᙯ", "ᙰ",
+ "ᙱ", "ᙲ", "ᙳ", "ᙴ", "ᙵ", "ᙶ"
]
}
// Override margin-top and -bottom rules from FieldLayout
margin: 0 !important; /* stylelint-disable-line declaration-no-important */
}
+
+ .oo-ui-checkboxInputWidget {
+ // Workaround for IE11 rendering issues. T162098
+ display: block;
+ }
}
&-highlightButton {
break;
default:
- if ( !$.isArray( pi.type ) ) {
+ if ( !Array.isArray( pi.type ) ) {
throw new Error( 'Unknown parameter type ' + pi.type );
}
break;
default:
- if ( $.isArray( pi.parameters[ i ].type ) ) {
+ if ( Array.isArray( pi.parameters[ i ].type ) ) {
flag = false;
count = pi.parameters[ i ].type.length;
}
* button object in a list of variadic arguments.
*/
addButtons: function ( buttons ) {
- if ( !$.isArray( buttons ) ) {
+ if ( !Array.isArray( buttons ) ) {
buttons = slice.call( arguments );
}
if ( isReady ) {
for ( i = 0; i < queue.length; i++ ) {
button = queue[ i ];
- if ( $.isArray( button ) ) {
+ if ( Array.isArray( button ) ) {
// Forwarded arguments array from mw.toolbar.addButton
insertButton.apply( toolbar, button );
} else {
var categories = [];
$.each( res.query.pages, function ( index, page ) {
- if ( !page.missing && $.isArray( page.categories ) ) {
+ if ( !page.missing && Array.isArray( page.categories ) ) {
categories.push.apply( categories, page.categories.map( function ( category ) {
return category.title;
} ) );
// Handle common MediaWiki API idioms for passing parameters
for ( key in parameters ) {
// Multiple values are pipe-separated
- if ( $.isArray( parameters[ key ] ) ) {
+ if ( Array.isArray( parameters[ key ] ) ) {
if ( !useUS || parameters[ key ].join( '' ).indexOf( '|' ) === -1 ) {
parameters[ key ] = parameters[ key ].join( '|' );
} else {
{
formatversion: 2,
action: 'watch',
- titles: $.isArray( pages ) ? pages.join( '|' ) : String( pages )
+ titles: Array.isArray( pages ) ? pages.join( '|' ) : String( pages )
},
addParams
)
return apiPromise
.then( function ( data ) {
// If a single page was given (not an array) respond with a single item as well.
- return $.isArray( pages ) ? data.watch : data.watch[ 0 ];
+ return Array.isArray( pages ) ? data.watch : data.watch[ 0 ];
} )
.promise( { abort: apiPromise.abort } );
}
funcs = [];
fields = [];
for ( i = 1; i < l; i++ ) {
- if ( !$.isArray( spec[ i ] ) ) {
+ if ( !Array.isArray( spec[ i ] ) ) {
throw new Error( op + ' parameters must be arrays' );
}
v = hideIfParse( $el, spec[ i ] );
if ( l !== 2 ) {
throw new Error( 'NOT takes exactly one parameter' );
}
- if ( !$.isArray( spec[ 1 ] ) ) {
+ if ( !Array.isArray( spec[ 1 ] ) ) {
throw new Error( 'NOT parameters must be arrays' );
}
v = hideIfParse( $el, spec[ 1 ] );
var i, len,
pages = this.pages;
- titles = $.isArray( titles ) ? titles : [ titles ];
+ titles = Array.isArray( titles ) ? titles : [ titles ];
state = state === undefined ? true : !!state;
for ( i = 0, len = titles.length; i < len; i++ ) {
// Only copy direct properties, not inherited ones
if ( uri.hasOwnProperty( prop ) ) {
// Deep copy object properties
- if ( $.isArray( uri[ prop ] ) || $.isPlainObject( uri[ prop ] ) ) {
+ if ( Array.isArray( uri[ prop ] ) || $.isPlainObject( uri[ prop ] ) ) {
this[ prop ] = $.extend( true, {}, uri[ prop ] );
} else {
this[ prop ] = uri[ prop ];
q[ k ] = [ q[ k ] ];
}
// Add to the array
- if ( $.isArray( q[ k ] ) ) {
+ if ( Array.isArray( q[ k ] ) ) {
q[ k ].push( v );
}
}
var args = [];
$.each( this.query, function ( key, val ) {
var k = Uri.encode( key ),
- vals = $.isArray( val ) ? val : [ val ];
+ vals = Array.isArray( val ) ? val : [ val ];
$.each( vals, function ( i, v ) {
if ( v === null ) {
args.push( k );
// Grep module's CSS
if (
- $.isPlainObject( module.style ) && $.isArray( module.style.css ) &&
+ $.isPlainObject( module.style ) && Array.isArray( module.style.css ) &&
pattern.test( module.style.css.join( '' ) )
) {
// Module's CSS source matches
function appendWithoutParsing( $parent, children ) {
var i, len;
- if ( !$.isArray( children ) ) {
+ if ( !Array.isArray( children ) ) {
children = [ children ];
}
// eslint-disable-next-line new-cap
parser = new mw.jqueryMsg.parser( options ),
key = args[ 0 ],
- argsArray = $.isArray( args[ 1 ] ) ? args[ 1 ] : slice.call( args, 1 );
+ argsArray = Array.isArray( args[ 1 ] ) ? args[ 1 ] : slice.call( args, 1 );
try {
return parser.parse( key, argsArray );
} catch ( e ) {
var results, i;
fallback = arguments.length > 1 ? fallback : null;
- if ( $.isArray( selection ) ) {
+ if ( Array.isArray( selection ) ) {
results = {};
for ( i = 0; i < selection.length; i++ ) {
if ( typeof selection[ i ] === 'string' ) {
*/
exists: function ( selection ) {
var i;
- if ( $.isArray( selection ) ) {
+ if ( Array.isArray( selection ) ) {
for ( i = 0; i < selection.length; i++ ) {
if ( typeof selection[ i ] !== 'string' || !hasOwn.call( this.values, selection[ i ] ) ) {
return false;
/* eslint-disable no-console */
log = ( function () {
- // Also update the restoration of methods in mediawiki.log.js
- // when adding or removing methods here.
+ /**
+ * Write a verbose message to the browser's console in debug mode.
+ *
+ * This method is mainly intended for verbose logging. It is a no-op in production mode.
+ * In ResourceLoader debug mode, it will use the browser's console if available, with
+ * fallback to creating a console interface in the DOM and logging messages there.
+ *
+ * See {@link mw.log} for other logging methods.
+ *
+ * @member mw
+ * @param {...string} msg Messages to output to console.
+ */
var log = function () {},
console = window.console;
+ // Note: Keep list of methods in sync with restoration in mediawiki.log.js
+ // when adding or removing mw.log methods below!
+
/**
+ * Collection of methods to help log messages to the console.
+ *
* @class mw.log
* @singleton
*/
/**
- * Write a message to the console's warning channel.
- * Actions not supported by the browser console are silently ignored.
+ * Write a message to the browser console's warning channel.
+ *
+ * This method is a no-op in browsers that don't implement the Console API.
*
* @param {...string} msg Messages to output to console
*/
$.noop;
/**
- * Write a message to the console's error channel.
+ * Write a message to the browser console's error channel.
*
- * Most browsers provide a stacktrace by default if the argument
- * is a caught Error object.
+ * Most browsers also print a stacktrace when calling this method if the
+ * argument is an Error object.
+ *
+ * This method is a no-op in browsers that don't implement the Console API.
*
* @since 1.26
* @param {Error|...string} msg Messages to output to console
$.noop;
/**
- * Create a property in a host object that, when accessed, will produce
+ * Create a property on a host object that, when accessed, will produce
* a deprecation warning in the console.
*
* @param {Object} obj Host object of deprecated property
return mw.message.apply( mw.message, arguments ).toString();
},
- /**
- * No-op dummy placeholder for {@link mw.log} in debug mode.
- *
- * @method
- */
+ // Expose mw.log
log: log,
/**
cssBuffer = '',
cssBufferTimer = null,
cssCallbacks = $.Callbacks(),
- isIE9 = document.documentMode === 9,
rAF = window.requestAnimationFrame || setTimeout;
function getMarker() {
* @param {Function} [callback]
*/
function addEmbeddedCSS( cssText, callback ) {
- var $style, styleEl;
-
function fireCallbacks() {
var oldCallbacks = cssCallbacks;
// Reset cssCallbacks variable so it's not polluted by any calls to
cssBuffer = '';
}
- // By default, always create a new <style>. Appending text to a <style> tag is
- // is a performance anti-pattern as it requires CSS to be reparsed (T47810).
- //
- // Support: IE 6-9
- // Try to re-use existing <style> tags due to the IE stylesheet limit (T33676).
- if ( isIE9 ) {
- $style = $( getMarker() ).prev();
- // Verify that the element before the marker actually is a <style> tag created
- // by mw.loader (not some other style tag, or e.g. a <meta> tag).
- if ( $style.data( 'ResourceLoaderDynamicStyleTag' ) ) {
- styleEl = $style[ 0 ];
- styleEl.appendChild( document.createTextNode( cssText ) );
- fireCallbacks();
- return;
- }
- // Else: No existing tag to reuse. Continue below and create the first one.
- }
-
- $style = $( newStyleTag( cssText, getMarker() ) );
-
- if ( isIE9 ) {
- $style.data( 'ResourceLoaderDynamicStyleTag', true );
- }
+ $( newStyleTag( cssText, getMarker() ) );
fireCallbacks();
}
el.media = media;
}
// If you end up here from an IE exception "SCRIPT: Invalid property value.",
- // see #addEmbeddedCSS, T33676, and T49277 for details.
+ // see #addEmbeddedCSS, T33676, T43331, and T49277 for details.
el.href = url;
$( getMarker() ).before( el );
legacyWait.always( function () {
try {
- if ( $.isArray( script ) ) {
+ if ( Array.isArray( script ) ) {
nestedAddScript( script, markModuleReady, 0 );
} else if ( typeof script === 'function' ) {
// Pass jQuery twice so that the signature of the closure which wraps
// Array of css strings in key 'css',
// or back-compat array of urls from media-type
- if ( $.isArray( value ) ) {
+ if ( Array.isArray( value ) ) {
for ( i = 0; i < value.length; i++ ) {
if ( key === 'bc-url' ) {
// back-compat: { <media>: [url, ..] }
// "https://example.org/x.js", "http://example.org/x.js", "//example.org/x.js", "/x.js"
if ( /^(https?:)?\/?\//.test( modules ) ) {
if ( type === 'text/css' ) {
- // Support: IE 7-8
- // Use properties instead of attributes as IE throws security
- // warnings when inserting a <link> tag with a protocol-relative
- // URL set though attributes - when on HTTPS. See T43331.
l = document.createElement( 'link' );
l.rel = 'stylesheet';
l.href = modules;
var original = mw.log,
slice = Array.prototype.slice;
- /**
- * Logs a message to the console in debug mode.
- *
- * In the case the browser does not have a console API, a console is created on-the-fly by appending
- * a `<div id="mw-log-console">` element to the bottom of the body and then appending this and future
- * messages to that, instead of the console.
- *
- * @member mw.log
- * @param {...string} msg Messages to output to console.
- */
mw.log = function () {
// Turn arguments into an array
var args = slice.call( arguments ),
--- /dev/null
+<?php
+
+class DnsSrvDiscovererTest extends PHPUnit_Framework_TestCase {
+ /**
+ * @covers DnsSrvDiscoverer
+ * @dataProvider provideRecords
+ */
+ public function testPickServer( $params, $expected ) {
+ $discoverer = new DnsSrvDiscoverer( '_etcd._tcp.eqiad.wmnet' );
+ $record = $discoverer->pickServer( $params );
+
+ $this->assertEquals( $expected, $record );
+
+ }
+
+ public static function provideRecords() {
+ return [
+ [
+ [ // record list
+ [
+ 'target' => 'conf1003.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 0,
+ 'weight' => 1,
+ ],
+ [
+ 'target' => 'conf1002.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 1,
+ 'weight' => 1,
+ ],
+ [
+ 'target' => 'conf1001.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 2,
+ 'weight' => 1,
+ ],
+ ], // selected record
+ [
+ 'target' => 'conf1003.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 0,
+ 'weight' => 1,
+ ]
+ ],
+ [
+ [ // record list
+ [
+ 'target' => 'conf1003or2.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 0,
+ 'weight' => 1,
+ ],
+ [
+ 'target' => 'conf1003or2.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 0,
+ 'weight' => 1,
+ ],
+ [
+ 'target' => 'conf1001.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 2,
+ 'weight' => 1,
+ ],
+ [
+ 'target' => 'conf1004.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 2,
+ 'weight' => 1,
+ ],
+ [
+ 'target' => 'conf1005.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 3,
+ 'weight' => 1,
+ ],
+ ], // selected record
+ [
+ 'target' => 'conf1003or2.eqiad.wmnet',
+ 'port' => 'SRV',
+ 'pri' => 0,
+ 'weight' => 1,
+ ]
+ ],
+ ];
+ }
+}
}
function among( actual, expected, message ) {
- if ( $.isArray( expected ) ) {
+ if ( Array.isArray( expected ) ) {
assert.ok( $.inArray( actual, expected ) !== -1, message + ' (got ' + actual + '; expected one of ' + expected.join( ', ' ) + ')' );
} else {
assert.equal( actual, expected, message );
assert.ok( true, 'QUnit expected() count dummy' );
},
function ( e, dependencies ) {
- assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
+ assert.strictEqual( Array.isArray( dependencies ), true, 'Expected array of dependencies' );
assert.deepEqual( dependencies, [ 'test.module7' ], 'Error callback called with module test.module7' );
}
);
assert.ok( true, 'QUnit expected() count dummy' );
},
function ( e, dependencies ) {
- assert.strictEqual( $.isArray( dependencies ), true, 'Expected array of dependencies' );
+ assert.strictEqual( Array.isArray( dependencies ), true, 'Expected array of dependencies' );
dependencies.sort();
assert.deepEqual(
dependencies,