summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Evans <grknight@gentoo.org>2020-10-02 14:42:51 -0400
committerBrian Evans <grknight@gentoo.org>2020-10-02 14:42:51 -0400
commit5334b7f3e15752d167fd8290efd69e9944025a8b (patch)
tree58e2920e10976a206b4198c98a2b7f546794555b
parentUpdate AntiSpoof to 1.35 (diff)
downloadextensions-5334b7f3e15752d167fd8290efd69e9944025a8b.tar.gz
extensions-5334b7f3e15752d167fd8290efd69e9944025a8b.tar.bz2
extensions-5334b7f3e15752d167fd8290efd69e9944025a8b.zip
Update CheckUser to 1.35
Signed-off-by: Brian Evans <grknight@gentoo.org>
-rw-r--r--CheckUser/.eslintrc.json26
-rw-r--r--CheckUser/.gitignore1
-rw-r--r--CheckUser/.phan/config.php25
-rw-r--r--CheckUser/.phpcs.xml3
-rw-r--r--CheckUser/.stylelintrc.json6
-rw-r--r--CheckUser/CheckUser.alias.php13
-rw-r--r--CheckUser/Gruntfile.js24
-rw-r--r--CheckUser/composer.json17
-rw-r--r--CheckUser/cu_changes.sql2
-rw-r--r--CheckUser/cu_log.sql4
-rw-r--r--CheckUser/extension.json222
-rw-r--r--CheckUser/gitinfo.json1
-rw-r--r--CheckUser/i18n/af.json6
-rw-r--r--CheckUser/i18n/ang.json4
-rw-r--r--CheckUser/i18n/ann.json13
-rw-r--r--CheckUser/i18n/api/ar.json31
-rw-r--r--CheckUser/i18n/api/ast.json31
-rw-r--r--CheckUser/i18n/api/ba.json25
-rw-r--r--CheckUser/i18n/api/bg.json30
-rw-r--r--CheckUser/i18n/api/bn.json8
-rw-r--r--CheckUser/i18n/api/bs.json10
-rw-r--r--CheckUser/i18n/api/da.json13
-rw-r--r--CheckUser/i18n/api/de.json32
-rw-r--r--CheckUser/i18n/api/en-gb.json25
-rw-r--r--CheckUser/i18n/api/en.json32
-rw-r--r--CheckUser/i18n/api/es-formal.json9
-rw-r--r--CheckUser/i18n/api/es.json33
-rw-r--r--CheckUser/i18n/api/fa.json29
-rw-r--r--CheckUser/i18n/api/fr.json32
-rw-r--r--CheckUser/i18n/api/gl.json33
-rw-r--r--CheckUser/i18n/api/got.json9
-rw-r--r--CheckUser/i18n/api/gu.json10
-rw-r--r--CheckUser/i18n/api/he.json30
-rw-r--r--CheckUser/i18n/api/hi.json9
-rw-r--r--CheckUser/i18n/api/hu.json28
-rw-r--r--CheckUser/i18n/api/ia.json29
-rw-r--r--CheckUser/i18n/api/id.json25
-rw-r--r--CheckUser/i18n/api/it.json33
-rw-r--r--CheckUser/i18n/api/ja.json31
-rw-r--r--CheckUser/i18n/api/ka.json10
-rw-r--r--CheckUser/i18n/api/ko.json33
-rw-r--r--CheckUser/i18n/api/ksh.json24
-rw-r--r--CheckUser/i18n/api/lb.json8
-rw-r--r--CheckUser/i18n/api/lt.json19
-rw-r--r--CheckUser/i18n/api/mai.json8
-rw-r--r--CheckUser/i18n/api/mk.json30
-rw-r--r--CheckUser/i18n/api/mr.json14
-rw-r--r--CheckUser/i18n/api/ms.json10
-rw-r--r--CheckUser/i18n/api/nb.json30
-rw-r--r--CheckUser/i18n/api/ne.json12
-rw-r--r--CheckUser/i18n/api/nl.json31
-rw-r--r--CheckUser/i18n/api/pl.json33
-rw-r--r--CheckUser/i18n/api/pt-br.json31
-rw-r--r--CheckUser/i18n/api/pt.json29
-rw-r--r--CheckUser/i18n/api/qqq.json32
-rw-r--r--CheckUser/i18n/api/roa-tara.json29
-rw-r--r--CheckUser/i18n/api/ru.json32
-rw-r--r--CheckUser/i18n/api/scn.json25
-rw-r--r--CheckUser/i18n/api/sd.json8
-rw-r--r--CheckUser/i18n/api/sh.json29
-rw-r--r--CheckUser/i18n/api/sl.json29
-rw-r--r--CheckUser/i18n/api/sv.json32
-rw-r--r--CheckUser/i18n/api/th.json8
-rw-r--r--CheckUser/i18n/api/tr.json33
-rw-r--r--CheckUser/i18n/api/uk.json31
-rw-r--r--CheckUser/i18n/api/vi.json24
-rw-r--r--CheckUser/i18n/api/zh-hans.json31
-rw-r--r--CheckUser/i18n/api/zh-hant.json33
-rw-r--r--CheckUser/i18n/ar.json81
-rw-r--r--CheckUser/i18n/arz.json3
-rw-r--r--CheckUser/i18n/ast.json45
-rw-r--r--CheckUser/i18n/az.json74
-rw-r--r--CheckUser/i18n/azb.json3
-rw-r--r--CheckUser/i18n/ba.json36
-rw-r--r--CheckUser/i18n/bcc.json5
-rw-r--r--CheckUser/i18n/bcl.json6
-rw-r--r--CheckUser/i18n/be-tarask.json5
-rw-r--r--CheckUser/i18n/be.json4
-rw-r--r--CheckUser/i18n/bg.json35
-rw-r--r--CheckUser/i18n/bn.json85
-rw-r--r--CheckUser/i18n/br.json11
-rw-r--r--CheckUser/i18n/bs.json8
-rw-r--r--CheckUser/i18n/ca.json16
-rw-r--r--CheckUser/i18n/ce.json7
-rw-r--r--CheckUser/i18n/ckb.json13
-rw-r--r--CheckUser/i18n/co.json4
-rw-r--r--CheckUser/i18n/cs.json17
-rw-r--r--CheckUser/i18n/csb.json4
-rw-r--r--CheckUser/i18n/cy.json1
-rw-r--r--CheckUser/i18n/da.json45
-rw-r--r--CheckUser/i18n/de.json133
-rw-r--r--CheckUser/i18n/diq.json31
-rw-r--r--CheckUser/i18n/dsb.json1
-rw-r--r--CheckUser/i18n/el.json16
-rw-r--r--CheckUser/i18n/en-gb.json41
-rw-r--r--CheckUser/i18n/en.json132
-rw-r--r--CheckUser/i18n/eo.json7
-rw-r--r--CheckUser/i18n/es-formal.json5
-rw-r--r--CheckUser/i18n/es.json150
-rw-r--r--CheckUser/i18n/et.json1
-rw-r--r--CheckUser/i18n/eu.json12
-rw-r--r--CheckUser/i18n/fa.json43
-rw-r--r--CheckUser/i18n/fi.json23
-rw-r--r--CheckUser/i18n/fit.json9
-rw-r--r--CheckUser/i18n/fr.json149
-rw-r--r--CheckUser/i18n/frp.json1
-rw-r--r--CheckUser/i18n/fy.json9
-rw-r--r--CheckUser/i18n/ga.json1
-rw-r--r--CheckUser/i18n/gan-hans.json4
-rw-r--r--CheckUser/i18n/gcr.json8
-rw-r--r--CheckUser/i18n/gl.json41
-rw-r--r--CheckUser/i18n/got.json4
-rw-r--r--CheckUser/i18n/gsw.json1
-rw-r--r--CheckUser/i18n/gu.json7
-rw-r--r--CheckUser/i18n/ha.json4
-rw-r--r--CheckUser/i18n/he.json136
-rw-r--r--CheckUser/i18n/hi.json13
-rw-r--r--CheckUser/i18n/hr.json38
-rw-r--r--CheckUser/i18n/hsb.json1
-rw-r--r--CheckUser/i18n/hu.json37
-rw-r--r--CheckUser/i18n/hy.json11
-rw-r--r--CheckUser/i18n/hyw.json8
-rw-r--r--CheckUser/i18n/ia.json35
-rw-r--r--CheckUser/i18n/id.json40
-rw-r--r--CheckUser/i18n/ie.json8
-rw-r--r--CheckUser/i18n/ilo.json1
-rw-r--r--CheckUser/i18n/io.json21
-rw-r--r--CheckUser/i18n/is.json5
-rw-r--r--CheckUser/i18n/it.json149
-rw-r--r--CheckUser/i18n/ja.json99
-rw-r--r--CheckUser/i18n/jv.json53
-rw-r--r--CheckUser/i18n/ka.json10
-rw-r--r--CheckUser/i18n/kjp.json10
-rw-r--r--CheckUser/i18n/kk-arab.json4
-rw-r--r--CheckUser/i18n/kk-cyrl.json1
-rw-r--r--CheckUser/i18n/kk-latn.json4
-rw-r--r--CheckUser/i18n/km.json3
-rw-r--r--CheckUser/i18n/ko.json98
-rw-r--r--CheckUser/i18n/krc.json4
-rw-r--r--CheckUser/i18n/ksh.json28
-rw-r--r--CheckUser/i18n/ku-latn.json9
-rw-r--r--CheckUser/i18n/kw.json8
-rw-r--r--CheckUser/i18n/lb.json50
-rw-r--r--CheckUser/i18n/li.json9
-rw-r--r--CheckUser/i18n/lld.json9
-rw-r--r--CheckUser/i18n/lt.json19
-rw-r--r--CheckUser/i18n/lv.json13
-rw-r--r--CheckUser/i18n/lzh.json4
-rw-r--r--CheckUser/i18n/mai.json9
-rw-r--r--CheckUser/i18n/mk.json145
-rw-r--r--CheckUser/i18n/ml.json6
-rw-r--r--CheckUser/i18n/mr.json17
-rw-r--r--CheckUser/i18n/mrh.json8
-rw-r--r--CheckUser/i18n/ms.json14
-rw-r--r--CheckUser/i18n/mt.json7
-rw-r--r--CheckUser/i18n/my.json11
-rw-r--r--CheckUser/i18n/nah.json4
-rw-r--r--CheckUser/i18n/nap.json8
-rw-r--r--CheckUser/i18n/nb.json132
-rw-r--r--CheckUser/i18n/nds-nl.json8
-rw-r--r--CheckUser/i18n/nds.json5
-rw-r--r--CheckUser/i18n/ne.json30
-rw-r--r--CheckUser/i18n/nl.json80
-rw-r--r--CheckUser/i18n/nn.json1
-rw-r--r--CheckUser/i18n/oc.json9
-rw-r--r--CheckUser/i18n/or.json3
-rw-r--r--CheckUser/i18n/pag.json4
-rw-r--r--CheckUser/i18n/pam.json4
-rw-r--r--CheckUser/i18n/pl.json138
-rw-r--r--CheckUser/i18n/pms.json1
-rw-r--r--CheckUser/i18n/ps.json2
-rw-r--r--CheckUser/i18n/pt-br.json142
-rw-r--r--CheckUser/i18n/pt.json73
-rw-r--r--CheckUser/i18n/qqq.json147
-rw-r--r--CheckUser/i18n/rif.json4
-rw-r--r--CheckUser/i18n/ro.json8
-rw-r--r--CheckUser/i18n/roa-tara.json41
-rw-r--r--CheckUser/i18n/ru.json98
-rw-r--r--CheckUser/i18n/rue.json1
-rw-r--r--CheckUser/i18n/rup.json4
-rw-r--r--CheckUser/i18n/ryu.json9
-rw-r--r--CheckUser/i18n/sah.json1
-rw-r--r--CheckUser/i18n/sat.json8
-rw-r--r--CheckUser/i18n/scn.json22
-rw-r--r--CheckUser/i18n/sd.json8
-rw-r--r--CheckUser/i18n/sh.json60
-rw-r--r--CheckUser/i18n/si.json1
-rw-r--r--CheckUser/i18n/sk.json20
-rw-r--r--CheckUser/i18n/skr-arab.json11
-rw-r--r--CheckUser/i18n/sl.json35
-rw-r--r--CheckUser/i18n/sq.json2
-rw-r--r--CheckUser/i18n/sr-ec.json126
-rw-r--r--CheckUser/i18n/sr-el.json1
-rw-r--r--CheckUser/i18n/stq.json1
-rw-r--r--CheckUser/i18n/sv.json150
-rw-r--r--CheckUser/i18n/szl.json5
-rw-r--r--CheckUser/i18n/ta.json1
-rw-r--r--CheckUser/i18n/te.json18
-rw-r--r--CheckUser/i18n/tg-cyrl.json6
-rw-r--r--CheckUser/i18n/th.json67
-rw-r--r--CheckUser/i18n/ti.json8
-rw-r--r--CheckUser/i18n/tk.json1
-rw-r--r--CheckUser/i18n/tl.json1
-rw-r--r--CheckUser/i18n/tly.json9
-rw-r--r--CheckUser/i18n/to.json4
-rw-r--r--CheckUser/i18n/tr.json176
-rw-r--r--CheckUser/i18n/trv.json6
-rw-r--r--CheckUser/i18n/tt-cyrl.json4
-rw-r--r--CheckUser/i18n/udm.json7
-rw-r--r--CheckUser/i18n/ug-arab.json1
-rw-r--r--CheckUser/i18n/uk.json133
-rw-r--r--CheckUser/i18n/ur.json4
-rw-r--r--CheckUser/i18n/vec.json17
-rw-r--r--CheckUser/i18n/vi.json38
-rw-r--r--CheckUser/i18n/vo.json1
-rw-r--r--CheckUser/i18n/wa.json1
-rw-r--r--CheckUser/i18n/war.json3
-rw-r--r--CheckUser/i18n/wuu.json4
-rw-r--r--CheckUser/i18n/xmf.json16
-rw-r--r--CheckUser/i18n/yue.json12
-rw-r--r--CheckUser/i18n/zh-hans.json81
-rw-r--r--CheckUser/i18n/zh-hant.json147
-rw-r--r--CheckUser/i18n/zh-hk.json3
-rw-r--r--CheckUser/includes/CheckUserEncryptedData.php4
-rw-r--r--CheckUser/includes/CheckUserHooks.php280
-rw-r--r--CheckUser/includes/CheckUserLogPager.php50
-rw-r--r--CheckUser/includes/ServiceWiring.php132
-rw-r--r--CheckUser/includes/api/ApiQueryCheckUser.php101
-rw-r--r--CheckUser/includes/api/ApiQueryCheckUserLog.php7
-rw-r--r--CheckUser/includes/specials/SpecialCheckUser.php1803
-rw-r--r--CheckUser/includes/specials/SpecialCheckUserLog.php27
-rw-r--r--CheckUser/maintenance/importCheckUserLogs.php12
-rw-r--r--CheckUser/maintenance/populateCheckUserTable.php19
-rw-r--r--CheckUser/maintenance/purgeOldData.php11
-rw-r--r--CheckUser/modules/ext.checkUser.investigate.styles/investigate.less234
-rw-r--r--CheckUser/modules/ext.checkUser.investigate/blockform.js74
-rw-r--r--CheckUser/modules/ext.checkUser.investigate/copy.js83
-rw-r--r--CheckUser/modules/ext.checkUser.investigate/init.js20
-rw-r--r--CheckUser/modules/ext.checkUser.investigate/tables.js283
-rw-r--r--CheckUser/modules/ext.checkUser.investigateblock.styles/investigateblock.less24
-rw-r--r--CheckUser/modules/ext.checkUser.investigateblock/investigateblock.js33
-rw-r--r--CheckUser/modules/ext.checkUser/caMultiLock.js42
-rw-r--r--CheckUser/modules/ext.checkUser/cidr.js226
-rw-r--r--CheckUser/modules/ext.checkuser.caMultiLock.js35
-rw-r--r--CheckUser/modules/ext.checkuser.cidr.js259
-rw-r--r--CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js127
-rw-r--r--CheckUser/modules/ext.guidedTour.tour.checkuserinvestigateform/checkuserinvestigateform.js40
-rw-r--r--CheckUser/package-lock.json5151
-rw-r--r--CheckUser/package.json11
-rw-r--r--CheckUser/src/ChangeService.php142
-rw-r--r--CheckUser/src/ComparePager.php337
-rw-r--r--CheckUser/src/ComparePagerFactory.php50
-rw-r--r--CheckUser/src/CompareService.php220
-rw-r--r--CheckUser/src/DurationManager.php63
-rw-r--r--CheckUser/src/EventLogger.php45
-rw-r--r--CheckUser/src/GuidedTour/TourLauncher.php74
-rw-r--r--CheckUser/src/Hook/CheckUserFormatRowHook.php22
-rw-r--r--CheckUser/src/Hook/CheckUserSubtitleLinksHook.php20
-rw-r--r--CheckUser/src/Hook/HookRunner.php42
-rw-r--r--CheckUser/src/HookHandler/Preferences.php28
-rw-r--r--CheckUser/src/InvestigateLogPager.php101
-rw-r--r--CheckUser/src/InvestigateLogPagerFactory.php42
-rw-r--r--CheckUser/src/PagerFactory.php12
-rw-r--r--CheckUser/src/PreliminaryCheckPager.php308
-rw-r--r--CheckUser/src/PreliminaryCheckPagerFactory.php57
-rw-r--r--CheckUser/src/PreliminaryCheckService.php194
-rw-r--r--CheckUser/src/SpecialInvestigate.php1020
-rw-r--r--CheckUser/src/SpecialInvestigateBlock.php349
-rw-r--r--CheckUser/src/SpecialInvestigateLog.php112
-rw-r--r--CheckUser/src/TimelinePager.php185
-rw-r--r--CheckUser/src/TimelinePagerFactory.php62
-rw-r--r--CheckUser/src/TimelineRowFormatter.php368
-rw-r--r--CheckUser/src/TimelineRowFormatterFactory.php76
-rw-r--r--CheckUser/src/TimelineService.php29
-rw-r--r--CheckUser/src/TokenManager.php181
-rw-r--r--CheckUser/src/TokenQueryManager.php82
-rw-r--r--CheckUser/src/ToolLinksMessages.php17
-rw-r--r--CheckUser/src/UserManager.php27
-rw-r--r--CheckUser/tests/phpunit/ComparePagerTest.php164
-rw-r--r--CheckUser/tests/phpunit/CompareServiceTest.php376
-rw-r--r--CheckUser/tests/phpunit/DurationManagerTest.php72
-rw-r--r--CheckUser/tests/phpunit/PreliminaryCheckPagerTest.php117
-rw-r--r--CheckUser/tests/phpunit/PreliminaryCheckServiceTest.php228
-rw-r--r--CheckUser/tests/phpunit/SpecialCheckUserTest.php88
-rw-r--r--CheckUser/tests/phpunit/TimelineServiceTest.php119
-rw-r--r--CheckUser/tests/phpunit/TokenManagerTest.php67
-rw-r--r--CheckUser/tests/phpunit/TokenQueryManagerTest.php74
-rw-r--r--CheckUser/version4
288 files changed, 18159 insertions, 2817 deletions
diff --git a/CheckUser/.eslintrc.json b/CheckUser/.eslintrc.json
index c882b462..d4172e97 100644
--- a/CheckUser/.eslintrc.json
+++ b/CheckUser/.eslintrc.json
@@ -1,23 +1,11 @@
{
- "extends": "wikimedia",
- "env": {
- "browser": true,
- "jquery": true,
- "qunit": true
- },
- "globals": {
- "mediaWiki": false
- },
+ "root": true,
+ "extends": [
+ "wikimedia/client",
+ "wikimedia/jquery",
+ "wikimedia/mediawiki"
+ ],
"rules": {
- "comma-dangle": 0,
- "computed-property-spacing": 0,
- "indent": 0,
- "no-multi-spaces": 0,
- "no-undef": 0,
- "no-use-before-define": 0,
- "one-var": 0,
- "space-infix-ops": 0,
- "vars-on-top": 0,
- "wrap-iife": 0
+ "no-jquery/no-global-selector": "off"
}
}
diff --git a/CheckUser/.gitignore b/CheckUser/.gitignore
index 0676034c..a9c17893 100644
--- a/CheckUser/.gitignore
+++ b/CheckUser/.gitignore
@@ -21,3 +21,4 @@ project.index
## Sublime
sublime-*
sftp-config.json
+/.eslintcache
diff --git a/CheckUser/.phan/config.php b/CheckUser/.phan/config.php
new file mode 100644
index 00000000..837b5111
--- /dev/null
+++ b/CheckUser/.phan/config.php
@@ -0,0 +1,25 @@
+<?php
+
+$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
+
+$cfg['directory_list'] = array_merge(
+ $cfg['directory_list'],
+ [
+ '../../extensions/Renameuser',
+ '../../extensions/CentralAuth',
+ '../../extensions/EventLogging',
+ '../../extensions/GuidedTour',
+ ]
+);
+
+$cfg['exclude_analysis_directory_list'] = array_merge(
+ $cfg['exclude_analysis_directory_list'],
+ [
+ '../../extensions/Renameuser',
+ '../../extensions/CentralAuth',
+ '../../extensions/EventLogging',
+ '../../extensions/GuidedTour',
+ ]
+);
+
+return $cfg;
diff --git a/CheckUser/.phpcs.xml b/CheckUser/.phpcs.xml
index 553b0829..1090030b 100644
--- a/CheckUser/.phpcs.xml
+++ b/CheckUser/.phpcs.xml
@@ -5,13 +5,12 @@
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic" />
<exclude name="MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName" />
<exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" />
- <exclude name="Squiz.Scope.MethodScope.Missing" />
<exclude name="MediaWiki.ControlStructures.AssignmentInControlStructures.AssignmentInControlStructures" />
</rule>
<rule ref="Generic.Files.LineLength">
<exclude-pattern>CheckUser\.alias\.php</exclude-pattern>
</rule>
<file>.</file>
- <arg name="extensions" value="php,php5,inc" />
+ <arg name="extensions" value="php,inc" />
<arg name="encoding" value="UTF-8" />
</ruleset>
diff --git a/CheckUser/.stylelintrc.json b/CheckUser/.stylelintrc.json
new file mode 100644
index 00000000..9edef147
--- /dev/null
+++ b/CheckUser/.stylelintrc.json
@@ -0,0 +1,6 @@
+{
+ "extends": "stylelint-config-wikimedia",
+ "rules": {
+ "selector-class-pattern": "^(mw|oo-ui|ext-checkuser)-"
+ }
+}
diff --git a/CheckUser/CheckUser.alias.php b/CheckUser/CheckUser.alias.php
index 45be75bf..05978cbf 100644
--- a/CheckUser/CheckUser.alias.php
+++ b/CheckUser/CheckUser.alias.php
@@ -12,6 +12,9 @@ $specialPageAliases = [];
$specialPageAliases['en'] = [
'CheckUser' => [ 'CheckUser' ],
'CheckUserLog' => [ 'CheckUserLog' ],
+ 'Investigate' => [ 'Investigate' ],
+ 'InvestigateBlock' => [ 'InvestigateBlock' ],
+ 'InvestigateLog' => [ 'InvestigateLog' ],
];
/** Arabic (العربية) */
@@ -131,6 +134,8 @@ $specialPageAliases['eo'] = [
$specialPageAliases['es'] = [
'CheckUser' => [ 'ComprobarUsuario', 'Comprobar_usuario', 'VerificarUsuario', 'Verificar_usuario' ],
'CheckUserLog' => [ 'Registro_de_comprobación_de_usuarios', 'Registro_de_verificación_de_usuarios' ],
+ 'Investigate' => [ 'Investigar', 'Investigación' ],
+ 'InvestigateLog' => [ 'Registro_de_investigaciones' ],
];
/** Basque (euskara) */
@@ -181,6 +186,8 @@ $specialPageAliases['gu'] = [
$specialPageAliases['he'] = [
'CheckUser' => [ 'בדיקת_משתמש' ],
'CheckUserLog' => [ 'יומן_בדיקת_משתמשים' ],
+ 'Investigate' => [ 'חקירה' ],
+ 'InvestigateLog' => [ 'יומן_חקירות' ],
];
/** Hindi (हिन्दी) */
@@ -400,14 +407,16 @@ $specialPageAliases['sq'] = [
'CheckUser' => [ 'KontrolloPërdorues' ],
];
-/** Serbian (Cyrillic script) (српски (ћирилица)‎) */
+/** Serbian (Cyrillic script) (српски (ћирилица)) */
$specialPageAliases['sr-ec'] = [
'CheckUser' => [ 'Провери_корисника', 'ПровериКорисника' ],
+ 'CheckUserLog' => [ 'Дневник_чекјузера', 'ДневникЧекјузера' ],
];
-/** Serbian (Latin script) (srpski (latinica)‎) */
+/** Serbian (Latin script) (srpski (latinica)) */
$specialPageAliases['sr-el'] = [
'CheckUser' => [ 'Proveri_korisnika', 'ProveriKorisnika' ],
+ 'CheckUserLog' => [ 'Dnevnik_čekjuzera', 'DnevnikČekjuzera' ],
];
/** Swedish (svenska) */
diff --git a/CheckUser/Gruntfile.js b/CheckUser/Gruntfile.js
index 7db269d2..75a9a1dc 100644
--- a/CheckUser/Gruntfile.js
+++ b/CheckUser/Gruntfile.js
@@ -8,29 +8,27 @@
module.exports = function ( grunt ) {
var conf = grunt.file.readJSON( 'extension.json' );
grunt.loadNpmTasks( 'grunt-eslint' );
- grunt.loadNpmTasks( 'grunt-jsonlint' );
grunt.loadNpmTasks( 'grunt-banana-checker' );
+ grunt.loadNpmTasks( 'grunt-stylelint' );
grunt.initConfig( {
eslint: {
+ options: {
+ cache: true
+ },
all: [
- '*.js',
- 'modules/**/*.js',
- '!node_modules/**',
- '!vendor/**'
+ '*.{js,json}',
+ 'modules/**/*.{js,json}'
]
},
- banana: conf.MessagesDirs,
- jsonlint: {
+ stylelint: {
all: [
- '*.json',
- '**/*.json',
- '!node_modules/**',
- '!vendor/**'
+ 'modules/**/*.{css,less}'
]
- }
+ },
+ banana: conf.MessagesDirs
} );
- grunt.registerTask( 'test', [ 'eslint', 'jsonlint', 'banana' ] );
+ grunt.registerTask( 'test', [ 'eslint', 'banana', 'stylelint' ] );
grunt.registerTask( 'default', 'test' );
};
diff --git a/CheckUser/composer.json b/CheckUser/composer.json
index 7a62b001..50a9b603 100644
--- a/CheckUser/composer.json
+++ b/CheckUser/composer.json
@@ -1,9 +1,10 @@
{
"require-dev": {
- "jakub-onderka/php-parallel-lint": "1.0.0",
- "mediawiki/mediawiki-codesniffer": "22.0.0",
- "jakub-onderka/php-console-highlighter": "0.3.2",
- "mediawiki/minus-x": "0.3.1"
+ "mediawiki/mediawiki-codesniffer": "31.0.0",
+ "mediawiki/mediawiki-phan-config": "0.10.3",
+ "mediawiki/minus-x": "1.1.0",
+ "php-parallel-lint/php-console-highlighter": "0.5.0",
+ "php-parallel-lint/php-parallel-lint": "1.2.0"
},
"scripts": {
"test": [
@@ -12,11 +13,11 @@
"minus-x check ."
],
"fix": [
- "phpcbf",
- "minus-x fix ."
+ "minus-x fix .",
+ "phpcbf"
]
},
- "extra": {
- "phan-taint-check-plugin": "1.5.0"
+ "require": {
+ "firebase/php-jwt": "~5.2.0"
}
}
diff --git a/CheckUser/cu_changes.sql b/CheckUser/cu_changes.sql
index 00057889..e88b52c8 100644
--- a/CheckUser/cu_changes.sql
+++ b/CheckUser/cu_changes.sql
@@ -29,7 +29,7 @@ CREATE TABLE /*_*/cu_changes (
-- rev_id of the prior revision, for generating diff links.
cuc_last_oldid int(10) unsigned NOT NULL default '0',
- -- Edit/new/log
+ -- RecentChange type identifiers: RC_EDIT, RC_NEW or RC_LOG
cuc_type tinyint(3) unsigned NOT NULL default '0',
-- Event timestamp
diff --git a/CheckUser/cu_log.sql b/CheckUser/cu_log.sql
index ac98c7b7..91583be3 100644
--- a/CheckUser/cu_log.sql
+++ b/CheckUser/cu_log.sql
@@ -15,7 +15,9 @@ CREATE TABLE /*_*/cu_log (
-- Reason given
cul_reason varchar(255) binary not null,
- -- String indicating the type of query, may be "userips", "ipedits", "ipusers", "ipedits-xff", "ipusers-xff"
+ -- String indicating the type of query, may be:
+ -- "useredits", "userips", "ipedits", "ipusers", "ipedits-xff", "ipusers-xff"
+ -- or "investigate" if the check was performed from Special:Investigate
cul_type varbinary(30) not null,
-- Integer target, interpretation depends on cul_type
diff --git a/CheckUser/extension.json b/CheckUser/extension.json
index 3ca0ad76..72336eb3 100644
--- a/CheckUser/extension.json
+++ b/CheckUser/extension.json
@@ -1,6 +1,6 @@
{
"name": "CheckUser",
- "version": "2.4",
+ "version": "2.5",
"author": [
"Tim Starling",
"Aaron Schulz"
@@ -10,7 +10,10 @@
"license-name": "GPL-2.0-or-later",
"type": "specialpage",
"requires": {
- "MediaWiki": ">= 1.31.0"
+ "MediaWiki": ">= 1.35.0",
+ "platform": {
+ "ext-openssl": "*"
+ }
},
"ExtensionMessagesFiles": {
"CheckUserAliases": "CheckUser.alias.php"
@@ -49,81 +52,184 @@
},
"CheckUserGBtoollink": {
"value": false,
- "description": "Whether to add links for glboally blocking accounts shown in Special:CheckUser results"
+ "description": "Whether to add links for globally blocking accounts shown in Special:CheckUser results"
},
"CheckUserLogLogins": {
"value": false,
"description": "Whether login attempts should be logged in CheckUser logs"
+ },
+ "CheckUserLogSuccessfulBotLogins": {
+ "value": true,
+ "description": "Whether successful login attempts of accounts in the 'bot' user group should be logged in CheckUser logs (assuming wgCheckUserLogLogins is also true)"
+ },
+ "CheckUserEnableSpecialInvestigate": {
+ "value": false,
+ "description": "Enables Special:Investigate"
+ },
+ "CheckUserLogAdditionalRights": {
+ "value": [],
+ "description": "Additional rights to be used when adding CheckUser log entries"
+ },
+ "CheckUserMaximumRowCount": {
+ "value": 5000,
+ "description": "Maximum number of rows in cu_changes to be used in any query"
}
},
"APIListModules": {
"checkuser": "ApiQueryCheckUser",
"checkuserlog": "ApiQueryCheckUserLog"
},
+ "HookHandlers": {
+ "preferences": {
+ "class": "MediaWiki\\CheckUser\\HookHandler\\Preferences"
+ }
+ },
"Hooks": {
"RecentChange_save": [
- "CheckUserHooks::updateCheckUserData"
- ],
- "EmailUser": [
- "CheckUserHooks::updateCUEmailData"
- ],
- "User::mailPasswordInternal": [
- "CheckUserHooks::updateCUPasswordResetData"
- ],
- "LocalUserCreated": [
- "CheckUserHooks::onLocalUserCreated"
- ],
- "UserMergeAccountFields": [
- "CheckUserHooks::onUserMergeAccountFields"
- ],
- "RenameUserSQL": [
- "CheckUserHooks::onRenameUserSQL"
- ],
- "ArticleEditUpdatesDeleteFromRecentchanges": [
+ "CheckUserHooks::updateCheckUserData",
"CheckUserHooks::maybePruneIPData"
],
- "ParserTestTables": [
- "CheckUserHooks::checkUserParserTestTables"
- ],
- "LoadExtensionSchemaUpdates": [
- "CheckUserHooks::onLoadExtensionSchemaUpdates"
- ],
- "ContributionsToolLinks": [
- "CheckUserHooks::checkUserContributionsLinks"
- ],
- "PerformRetroactiveAutoblock": [
- "CheckUserHooks::doRetroactiveAutoblock"
- ],
- "AuthManagerLoginAuthenticateAudit": [
- "CheckUserHooks::onAuthManagerLoginAuthenticateAudit"
- ]
+ "EmailUser": "CheckUserHooks::updateCUEmailData",
+ "User::mailPasswordInternal": "CheckUserHooks::updateCUPasswordResetData",
+ "LocalUserCreated": "CheckUserHooks::onLocalUserCreated",
+ "UserMergeAccountFields": "CheckUserHooks::onUserMergeAccountFields",
+ "RenameUserSQL": "CheckUserHooks::onRenameUserSQL",
+ "ParserTestTables": "CheckUserHooks::checkUserParserTestTables",
+ "LoadExtensionSchemaUpdates": "CheckUserHooks::onLoadExtensionSchemaUpdates",
+ "ContributionsToolLinks": "CheckUserHooks::checkUserContributionsLinks",
+ "PerformRetroactiveAutoblock": "CheckUserHooks::doRetroactiveAutoblock",
+ "AuthManagerLoginAuthenticateAudit": "CheckUserHooks::onAuthManagerLoginAuthenticateAudit",
+ "SpecialPage_initList": "CheckUserHooks::onSpecialPage_initList",
+ "GetPreferences": "preferences"
},
"MessagesDirs": {
"CheckUser": [
- "i18n"
+ "i18n",
+ "i18n/api"
]
},
+ "attributes": {
+ "EventLogging": {
+ "Schemas": {
+ "SpecialInvestigate": 20261100
+ }
+ }
+ },
"ResourceModules": {
"ext.checkUser": {
- "scripts": "modules/ext.checkuser.cidr.js",
+ "localBasePath": "modules/ext.checkUser",
+ "remoteExtPath": "CheckUser/modules/ext.checkUser",
+ "scripts": [
+ "cidr.js",
+ "caMultiLock.js"
+ ],
"dependencies": [
"mediawiki.util"
+ ],
+ "messages": [
+ "checkuser-centralauth-multilock"
+ ]
+ },
+ "ext.checkUser.investigate.styles": {
+ "localBasePath": "modules/ext.checkUser.investigate.styles/",
+ "remoteExtPath": "CheckUser/modules/ext.checkUser.investigate.styles/",
+ "styles": [
+ "investigate.less"
]
},
- "ext.checkUser.caMultiLock": {
- "scripts": "modules/ext.checkuser.caMultiLock.js",
+ "ext.checkUser.investigate": {
+ "localBasePath": "modules/ext.checkUser.investigate",
+ "remoteExtPath": "CheckUser/modules/ext.checkUser.investigate",
+ "packageFiles": [
+ "init.js",
+ "tables.js",
+ "copy.js",
+ "blockform.js",
+ {
+ "name": "message.json",
+ "callback": "MediaWiki\\CheckUser\\ToolLinksMessages::getParsedMessage",
+ "callbackParam": "checkuser-investigate-compare-toollinks"
+ }
+ ],
"dependencies": [
- "mediawiki.util"
+ "jquery.tablesorter",
+ "oojs-ui-widgets",
+ "oojs-ui.styles.icons-editing-core",
+ "oojs-ui.styles.icons-editing-advanced",
+ "oojs-ui.styles.icons-interactions",
+ "oojs-ui.styles.icons-moderation",
+ "oojs-ui.styles.icons-user",
+ "mediawiki.storage",
+ "mediawiki.Title",
+ "mediawiki.Uri",
+ "mediawiki.widgets"
],
"messages": [
- "checkuser-centralauth-multilock"
+ "checkuser-investigate-compare-copy-button-label",
+ "checkuser-investigate-compare-copy-message-label",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label",
+ "checkuser-investigate-compare-table-button-add-user-targets-label",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label",
+ "checkuser-investigate-compare-table-button-checks-label",
+ "checkuser-investigate-compare-table-button-contribs-label",
+ "checkuser-investigate-compare-table-button-filter-label",
+ "checkuser-investigate-subtitle-cancel-button-label",
+ "checkuser-investigate-subtitle-continue-button-label"
+ ]
+ },
+ "ext.checkUser.investigateblock.styles": {
+ "localBasePath": "modules/ext.checkUser.investigateblock.styles",
+ "remoteExtPath": "CheckUser/modules/ext.checkUser.investigateblock.styles",
+ "styles": [
+ "investigateblock.less"
+ ]
+ },
+ "ext.checkUser.investigateblock": {
+ "localBasePath": "modules/ext.checkUser.investigateblock",
+ "remoteExtPath": "CheckUser/modules/ext.checkUser.investigateblock",
+ "packageFiles": [
+ "investigateblock.js"
+ ],
+ "dependencies": [
+ "oojs-ui-widgets"
+ ]
+ },
+ "ext.guidedTour.tour.checkuserinvestigateform": {
+ "localBasePath": "modules/ext.guidedTour.tour.checkuserinvestigateform",
+ "remoteExtPath": "CheckUser/modules/ext.guidedTour.tour.checkuserinvestigateform",
+ "scripts": [
+ "checkuserinvestigateform.js"
+ ],
+ "dependencies": "ext.guidedTour",
+ "messages": [
+ "checkuser-investigate-tour-targets-title",
+ "checkuser-investigate-tour-targets-desc"
+ ]
+ },
+ "ext.guidedTour.tour.checkuserinvestigate": {
+ "localBasePath": "modules/ext.guidedTour.tour.checkuserinvestigate",
+ "remoteExtPath": "CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate",
+ "scripts": [
+ "checkuserinvestigate.js"
+ ],
+ "dependencies": [
+ "ext.guidedTour",
+ "ext.checkUser.investigate"
+ ],
+ "messages": [
+ "checkuser-investigate-tour-useragents-title",
+ "checkuser-investigate-tour-useragents-desc",
+ "checkuser-investigate-tour-addusertargets-title",
+ "checkuser-investigate-tour-addusertargets-desc",
+ "checkuser-investigate-tour-filterip-title",
+ "checkuser-investigate-tour-filterip-desc",
+ "checkuser-investigate-tour-block-title",
+ "checkuser-investigate-tour-block-desc",
+ "checkuser-investigate-tour-copywikitext-title",
+ "checkuser-investigate-tour-copywikitext-desc"
]
}
},
- "ResourceFileModulePaths": {
- "localBasePath": "",
- "remoteExtPath": "CheckUser"
- },
"GroupPermissions": {
"checkuser": {
"checkuser": true,
@@ -135,8 +241,18 @@
"checkuser-log"
],
"SpecialPages": {
- "CheckUser": "SpecialCheckUser",
- "CheckUserLog": "SpecialCheckUserLog"
+ "CheckUser": {
+ "class": "SpecialCheckUser",
+ "services": [
+ "LinkBatchFactory"
+ ]
+ },
+ "CheckUserLog": {
+ "class": "SpecialCheckUserLog",
+ "services": [
+ "LinkBatchFactory"
+ ]
+ }
},
"AutoloadClasses": {
"CheckUserHooks": "includes/CheckUserHooks.php",
@@ -148,5 +264,15 @@
"ApiQueryCheckUserLog": "includes/api/ApiQueryCheckUserLog.php",
"PopulateCheckUserTable": "maintenance/populateCheckUserTable.php"
},
+ "ServiceWiringFiles": [
+ "includes/ServiceWiring.php"
+ ],
+ "AutoloadNamespaces": {
+ "MediaWiki\\CheckUser\\": "src/"
+ },
+ "TestAutoloadNamespaces": {
+ "MediaWiki\\CheckUser\\Test\\": "tests/phpunit/"
+ },
+ "load_composer_autoloader": true,
"manifest_version": 2
}
diff --git a/CheckUser/gitinfo.json b/CheckUser/gitinfo.json
deleted file mode 100644
index fa9b2f97..00000000
--- a/CheckUser/gitinfo.json
+++ /dev/null
@@ -1 +0,0 @@
-{"headSHA1": "27be3bc174bd036f4218bdac592c85d59819369c\n", "head": "27be3bc174bd036f4218bdac592c85d59819369c\n", "remoteURL": "https://gerrit.wikimedia.org/r/mediawiki/extensions/CheckUser", "branch": "27be3bc174bd036f4218bdac592c85d59819369c\n", "headCommitDate": "1539634554"} \ No newline at end of file
diff --git a/CheckUser/i18n/af.json b/CheckUser/i18n/af.json
index a3df7db4..9a2f601b 100644
--- a/CheckUser/i18n/af.json
+++ b/CheckUser/i18n/af.json
@@ -2,6 +2,7 @@
"@metadata": {
"authors": [
"Arnobarnard",
+ "Joris Darlington Quarshie",
"Naudefj",
"SPQRobin",
"පසිඳු කාවින්ද"
@@ -55,7 +56,6 @@
"checkuser-block-limit": "Te veel gebruikers gekies.",
"checkuser-block-noreason": "U moet 'n rede vir die blokkades verskaf.",
"checkuser-noreason": "U moet 'n rede vir hierdie navraag verskaf.",
- "checkuser-accounts": "$1 nuwe {{PLURAL:$1|gebruiker|gebruikers}}",
"checkuser-too-many": "Te veel resultate (volgens skatting). Maak die IP-reeks kleiner.\nHieronder word die gebruikte IP-adresse weergegee (maksimum 5000, op IP-adres gesorteer):",
"checkuser-user-nonexistent": "Die gespesifiseerde gebruiker bestaan nie.",
"checkuser-search": "Soek",
@@ -68,5 +68,7 @@
"checkuser-autocreate-action": "is outomaties geskep",
"checkuser-create-action": "is geskep",
"checkuser-email-action": "het 'n e-pos aan gebruiker \"$1\" gestuur",
- "checkuser-reset-action": "herstel gebruiker \"$1\" se wagwoord"
+ "checkuser-reset-action": "herstel gebruiker \"$1\" se wagwoord",
+ "checkuser-investigate-notice-no-results": "Daar is geen resultate nie.",
+ "checkuser-investigate-targets-placeholder": "Gebruikersnaam of 1.1.1.1"
}
diff --git a/CheckUser/i18n/ang.json b/CheckUser/i18n/ang.json
index e37b9066..7808f7ca 100644
--- a/CheckUser/i18n/ang.json
+++ b/CheckUser/i18n/ang.json
@@ -1,4 +1,6 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser-reason": "Racu:"
}
diff --git a/CheckUser/i18n/ann.json b/CheckUser/i18n/ann.json
new file mode 100644
index 00000000..f7ebcb9e
--- /dev/null
+++ b/CheckUser/i18n/ann.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Katelem"
+ ]
+ },
+ "checkuser-investigateblock-email-label": "Gban inyi ikaria etip-olik",
+ "checkuser-investigateblock-notice-position-label": "Irek",
+ "checkuser-investigate-subtitle-block-button-label": "Gban",
+ "checkuser-investigate-subtitle-cancel-button-label": "Gwak",
+ "checkuser-investigate-subtitle-continue-button-label": "Fo isi",
+ "checkuser-investigate-tour-block-title": "Ìre oweek igbagban?"
+}
diff --git a/CheckUser/i18n/api/ar.json b/CheckUser/i18n/api/ar.json
new file mode 100644
index 00000000..00c283aa
--- /dev/null
+++ b/CheckUser/i18n/api/ar.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Meno25",
+ "ديفيد",
+ "علاء"
+ ]
+ },
+ "apihelp-query+checkuser-description": "تحقق من عناوين الأيبي التي يتم استخدامها بواسطة اسم مستخدم معين أو أي أسماء مستخدمين يتم استخدامها بواسطة عنوان أيبي محدد.",
+ "apihelp-query+checkuser-summary": "تحقق من عناوين الأيبي التي يتم استخدامها بواسطة اسم مستخدم معين أو أي أسماء مستخدمين يتم استخدامها بواسطة عنوان أيبي محدد.",
+ "apihelp-query+checkuser-param-request": "نوع طلب تدقيق المستخدم:\n;userips: الحصول على عنوان الأيبي للمستخدم المستهدف.\n;edits: الحصول على التغييرات من عنوان الأيبي أو نطاق الأيبي المستهدف.\n;ipusers: الحصول على المستخدمين من عنوان الأيبي أو نطاق الأيبي المستهدف.",
+ "apihelp-query+checkuser-param-target": "اسم المستخدم أو عنوان أيبي أو نطاق CIDR للتحقق.",
+ "apihelp-query+checkuser-param-reason": "السبب للتحقق.",
+ "apihelp-query+checkuser-param-limit": "حد الصفوف",
+ "apihelp-query+checkuser-param-timecond": "الحد الزمني لبيانات المستخدم (مثل \"-2 weeks\" أو \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "استخدم بيانات XFF بدلاً من عنوان الآيبي.",
+ "apihelp-query+checkuser-example-1": "لتحقق من عناوين الآيبي لـ[[User:Example]]",
+ "apihelp-query+checkuser-example-2": "تدقيق تعديلات من 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "الحصول على إدخالات من سجل تدقيق المستخدم.",
+ "apihelp-query+checkuserlog-summary": "الحصول على إدخالات من سجل تدقيق المستخدم.",
+ "apihelp-query+checkuserlog-param-user": "اسم المستخدم لمدقق المستخدم.",
+ "apihelp-query+checkuserlog-param-target": "تم تدقيق مستخدم أو عنوان أيبي أو نطاق CIDR للتحقق.",
+ "apihelp-query+checkuserlog-param-limit": "حد الصفوف",
+ "apihelp-query+checkuserlog-param-from": "الطابع الزمني لبدء العد منه.",
+ "apihelp-query+checkuserlog-param-to": "الطابع الزمني لإنهاء التعداد.",
+ "apihelp-query+checkuserlog-example-1": "عرض تدقيقات [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "عرض تدقيقات 192.0.2.0/24 بعد 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "يجب عليك تحديد سبب لهذا التدقيق.",
+ "apierror-checkuser-timelimit": "تحتاج إلى استخدام الحد الزمني الصحيح (مثل \"-2 weeks\" أو \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "وضع الطلب غير صالح"
+}
diff --git a/CheckUser/i18n/api/ast.json b/CheckUser/i18n/api/ast.json
new file mode 100644
index 00000000..14d46259
--- /dev/null
+++ b/CheckUser/i18n/api/ast.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Macofe",
+ "McDutchie",
+ "Xuacu"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Comprobar qué direiciones IP usa un usuariu determináu o que nomes d'usuariu usa una IP determinada.",
+ "apihelp-query+checkuser-summary": "Comprobar qué direiciones IP usa un usuariu determináu o que nomes d'usuariu usa una IP determinada.",
+ "apihelp-query+checkuser-param-request": "Tipu de solicitú CheckUser:\n;userips: Devolver la direición IP del usuariu destín.\n;edits: Devolver los cambios de la direición o rangu IP de destín.\n;ipusers: Devolver los usuarios de la direición o rangu IP de destín.",
+ "apihelp-query+checkuser-param-target": "Nome d'usuariu, direición IP, o rangu CIDR a comprobar.",
+ "apihelp-query+checkuser-param-reason": "Motivu de la comprobación.",
+ "apihelp-query+checkuser-param-limit": "Llende de fileres.",
+ "apihelp-query+checkuser-param-timecond": "Llende de tiempu de datos del usuariu (p. ex. \"-2 weeks\" o \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Usar datos XFF en llugar de direiciones IP.",
+ "apihelp-query+checkuser-example-1": "Comprobar les direiciones IP pa [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Comprobar les ediciones dende 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Recibir entraes del rexistru de CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Recibir entraes del rexistru de CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Nome d'usuariu de CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Usuariu, direición IP o rangu CIDR comprobáu.",
+ "apihelp-query+checkuserlog-param-limit": "Llende de fileres.",
+ "apihelp-query+checkuserlog-param-from": "La marca horaria dende la que principiar la enumeración.",
+ "apihelp-query+checkuserlog-param-to": "La marca horaria na que finar la enumeración.",
+ "apihelp-query+checkuserlog-example-1": "Amosar les comprobaciones de [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Amosar les comprobaciones de 192.0.2.0/24 después de 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Tienes de dar un motivu pa la comprobación.",
+ "apierror-checkuser-timelimit": "Tienes d'usar una llende de tiempu correuta (como «-2 weeks» o «2 weeks ago»).",
+ "apierror-checkuser-invalidmode": "Mou de solicitú inválidu"
+}
diff --git a/CheckUser/i18n/api/ba.json b/CheckUser/i18n/api/ba.json
new file mode 100644
index 00000000..83a4c1c9
--- /dev/null
+++ b/CheckUser/i18n/api/ba.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sagan",
+ "Ләйсән"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Ҡатнашыусы ниндәй IP-адрес ҡуллыныуын йәки ниндәй исемдәр ошоIP-адресты ҡулланыуын тикшерегеҙ.",
+ "apihelp-query+checkuser-param-request": "Чекюзерға һорау ебәреү тибы:\n;userips:Ҡулланыусының IP-адресын алырға .\n; edits:IP-адресынан йәки диапазонынан алынған үҙгәртеүҙәр турыһында мәғлүмәт аларға.\n;ipusers: IP-адресындаға йәки диапозонындағы ҡулланыусыларҙы белергә.",
+ "apihelp-query+checkuser-param-target": "Ҡатнашыу IP-адрес йәки CIDR-диапазоны тикшереү өсөн.",
+ "apihelp-query+checkuser-param-reason": "Тикшереү сәбәбе.",
+ "apihelp-query+checkuser-param-limit": "Юл һанын сикләү.",
+ "apihelp-query+checkuser-param-timecond": "Ҡатнашыусы өсөн ваҡыт сикләүе (мәҫәлән, «-2 weeks» йәки «2 weeks ago»).",
+ "apihelp-query+checkuser-param-xff": "IP-адрес урынына XFF мәғлүмәттәрен ҡулланырға.",
+ "apihelp-query+checkuser-example-1": "IP-адресты тикшерергә [[User:Example]]",
+ "apihelp-query+checkuser-example-2": " 192.0.2.0/24 төҙәтеүҙәрен тикшерергә",
+ "apihelp-query+checkuserlog-description": "Ҡатнашыусыларҙы тикшереү журналынан яҙма алырға (CheckUser).",
+ "apihelp-query+checkuserlog-param-user": "Чекюзер ҡулланыусы исемлеге.",
+ "apihelp-query+checkuserlog-param-target": "IP-адрес йәки CIDR-диапазоны тикшерелелгән ҡатнашыусы.",
+ "apihelp-query+checkuserlog-param-limit": "Юл һанын сикләү.",
+ "apihelp-query+checkuserlog-param-from": "Иҫәп күсереү башланған ваҡыт билдәһе",
+ "apihelp-query+checkuserlog-param-to": "Иҫәп күсереү тамамланған ваҡыт билдәһе",
+ "apihelp-query+checkuserlog-example-1": "Тикшереүҙәрҙә күрһәтергә [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "192.0.2.0/24 башлап 2011-10-15T23:00:00Z тиклем тикшереүҙе күрһәтергә"
+}
diff --git a/CheckUser/i18n/api/bg.json b/CheckUser/i18n/api/bg.json
new file mode 100644
index 00000000..97bb625d
--- /dev/null
+++ b/CheckUser/i18n/api/bg.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "StanProg",
+ "Vlad5250"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Проверява кои IP-адреси използват дадено потребителско име или кои потребителски имена използват даден IP-адрес.",
+ "apihelp-query+checkuser-summary": "Проверява кои IP-адреси използват дадено потребителско име или кои потребителски имена използват даден IP-адрес.",
+ "apihelp-query+checkuser-param-request": "Тип на заявка с CheckUser:\n;userips: Връща IP-адреса на целеви потребител.\n;edits: Връща промените от целевия IP-адрес или диапазон.\n;ipusers: Връща потребителите от целевия IP-адрес или диапазон.",
+ "apihelp-query+checkuser-param-target": "Потребителско име, IP-адрес или CIDR-диапазон за проверка.",
+ "apihelp-query+checkuser-param-reason": "Причина за проверката.",
+ "apihelp-query+checkuser-param-limit": "Ограничение на редовете.",
+ "apihelp-query+checkuser-param-timecond": "Ограничение на времето за потребителските данни (например „-2 weeks“ или „2 weeks ago“).",
+ "apihelp-query+checkuser-param-xff": "Използване на XFF-данни вместо IP-адрес.",
+ "apihelp-query+checkuser-example-1": "Проверява IP-адресите на [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Проверява редакции от 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Връща записи от дневника на CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Връща записи от дневника на CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Потребителско име на проверяващия (CheckUser).",
+ "apihelp-query+checkuserlog-param-target": "Проверен потребител, IP-адрес или CIDR-диапазон.",
+ "apihelp-query+checkuserlog-param-limit": "Ограничение на редовете.",
+ "apihelp-query+checkuserlog-param-from": "Времева отметка, от която да започва изброяването.",
+ "apihelp-query+checkuserlog-param-to": "Времева отметка, при която да спира изброяването.",
+ "apihelp-query+checkuserlog-example-1": "Показва на проверки на [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Показва проверки на 192.0.2.0/24 след 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Трябва да укажете причина за проверка.",
+ "apierror-checkuser-timelimit": "Трябва да използвате правилно ограничение по врене (напр. „-2 weeks“ или „2 weeks ago“).",
+ "apierror-checkuser-invalidmode": "Невалиден режим на заявката"
+}
diff --git a/CheckUser/i18n/api/bn.json b/CheckUser/i18n/api/bn.json
new file mode 100644
index 00000000..bd269f72
--- /dev/null
+++ b/CheckUser/i18n/api/bn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "আফতাবুজ্জামান"
+ ]
+ },
+ "apihelp-query+checkuser-param-reason": "পরীক্ষার কারণ।"
+}
diff --git a/CheckUser/i18n/api/bs.json b/CheckUser/i18n/api/bs.json
new file mode 100644
index 00000000..c136c80b
--- /dev/null
+++ b/CheckUser/i18n/api/bs.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Srdjan m",
+ "Srđan"
+ ]
+ },
+ "apihelp-query+checkuser-param-timecond": "Vremensko ograničenje za korisničke podatke (npr, \"-2 weeks\" ili \"2 weeks ago\").",
+ "apierror-checkuser-timelimit": "Morate koristiti ispravno vremensko ograničenje (npr, \"-2 weeks\" ili \"2 weeks ago\")."
+}
diff --git a/CheckUser/i18n/api/da.json b/CheckUser/i18n/api/da.json
new file mode 100644
index 00000000..4c71ca37
--- /dev/null
+++ b/CheckUser/i18n/api/da.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cgtdk",
+ "Saederup92"
+ ]
+ },
+ "apihelp-query+checkuser-param-target": "Brugernavn, ip-adresse eller CIDR-interval at tjekke.",
+ "apihelp-query+checkuser-param-reason": "Begrundelse for tjek.",
+ "apihelp-query+checkuser-example-2": "Tjek redigeringer fra 192.0.2.0/24",
+ "apihelp-query+checkuserlog-param-user": "Brugernavnet på tjekbrugeren.",
+ "apierror-checkuser-missingsummary": "Du skal angive en begrundelse for tjekket."
+}
diff --git a/CheckUser/i18n/api/de.json b/CheckUser/i18n/api/de.json
new file mode 100644
index 00000000..8f509daf
--- /dev/null
+++ b/CheckUser/i18n/api/de.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "FF11",
+ "McDutchie",
+ "Metalhead64",
+ "Tiin"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Überprüfen, welche IP-Adressen durch einen bestimmten Benutzernamen oder welche Benutzernamen von einer bestimmten IP-Adresse verwendet werden.",
+ "apihelp-query+checkuser-summary": "Überprüfen, welche IP-Adressen durch einen bestimmten Benutzernamen oder welche Benutzernamen von einer bestimmten IP-Adresse verwendet werden.",
+ "apihelp-query+checkuser-param-request": "Art der CheckUser-Anfrage:\n;userips:Ermittelt die IP-Adresse des Ziel-Benutzers.\n;edits:Ermittelt Änderungen der Ziel-IP-Adresse oder des Adressbereichs.\n;ipusers:Ermittelt den Benutzer der Ziel-IP-Adresse oder des Adressbereichs.",
+ "apihelp-query+checkuser-param-target": "Zu überprüfender Benutzername, CIDR-Bereich oder zu überprüfende IP-Adresse.",
+ "apihelp-query+checkuser-param-reason": "Grund für die Überprüfung.",
+ "apihelp-query+checkuser-param-limit": "Zeilenlimit.",
+ "apihelp-query+checkuser-param-timecond": "Zeitlimit der Benutzerdaten (wie „-2 weeks“ oder „2 weeks ago“).",
+ "apihelp-query+checkuser-param-xff": "XFF-Daten anstelle der IP-Adresse verwenden.",
+ "apihelp-query+checkuser-example-1": "IP-Adressen für [[User:Example]] überprüfen",
+ "apihelp-query+checkuser-example-2": "Bearbeitungen von 192.0.2.0/24 überprüfen",
+ "apihelp-query+checkuserlog-description": "Einträge aus dem CheckUser-Logbuch abrufen.",
+ "apihelp-query+checkuserlog-summary": "Ruft Einträge aus dem Checkuser-Logbuch ab.",
+ "apihelp-query+checkuserlog-param-user": "Benutzername des zu überprüfenden Benutzers.",
+ "apihelp-query+checkuserlog-param-target": "Überprüfter Benutzer, CIDR-Bereich oder überprüfte IP-Adresse.",
+ "apihelp-query+checkuserlog-param-limit": "Zeilenlimit.",
+ "apihelp-query+checkuserlog-param-from": "Der Zeitstempel, bei dem die Aufzählung beginnen soll.",
+ "apihelp-query+checkuserlog-param-to": "Der Zeitstempel, bei dem die Aufzählung enden soll.",
+ "apihelp-query+checkuserlog-example-1": "Prüfungen von [[User:Example]] anzeigen",
+ "apihelp-query+checkuserlog-example-2": "Zeigt Überprüfungen von 192.0.2.0/24 nach 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Du musst zur Überprüfung einen Grund angeben.",
+ "apierror-checkuser-timelimit": "Du musst das korrekte Zeitlimit verwenden (wie „-2 weeks“ oder „2 weeks ago“).",
+ "apierror-checkuser-invalidmode": "Ungültiger Abfragemodus"
+}
diff --git a/CheckUser/i18n/api/en-gb.json b/CheckUser/i18n/api/en-gb.json
new file mode 100644
index 00000000..84ddae6d
--- /dev/null
+++ b/CheckUser/i18n/api/en-gb.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chase me ladies, I'm the Cavalry",
+ "Macofe"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Check which IP addresses are used by a given username, or which usernames are used by a given IP.",
+ "apihelp-query+checkuser-param-request": "Type of CheckUser request:\n;userips:Get IP address of target user.\n;edits:Get changes from target IP address or range.\n;ipusers:Get users from target IP address or range.",
+ "apihelp-query+checkuser-param-target": "Username, IP address, or CIDR range to check.",
+ "apihelp-query+checkuser-param-reason": "Reason to check.",
+ "apihelp-query+checkuser-param-limit": "Limit of rows.",
+ "apihelp-query+checkuser-param-timecond": "Time limit of user data (like \"-2 weeks\" or \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Use XFF data instead of IP address.",
+ "apihelp-query+checkuser-example-1": "Check IP addresses for [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Check edits from 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Get entries from the CheckUser log.",
+ "apihelp-query+checkuserlog-param-user": "Username of the CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Checked user, IP address, or CIDR range.",
+ "apihelp-query+checkuserlog-param-limit": "Limit of rows.",
+ "apihelp-query+checkuserlog-param-from": "The timestamp to start enumerating from.",
+ "apihelp-query+checkuserlog-param-to": "The timestamp to end enumerating.",
+ "apihelp-query+checkuserlog-example-1": "Show checks of [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Show checks of 192.0.2.0/24 after 2011-10-15T23:00:00Z"
+}
diff --git a/CheckUser/i18n/api/en.json b/CheckUser/i18n/api/en.json
new file mode 100644
index 00000000..ea701dcd
--- /dev/null
+++ b/CheckUser/i18n/api/en.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tim Starling",
+ "Aaron Schulz",
+ "John Du Hart",
+ "Zoranzoki21"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Check which IP addresses are used by a given username or which usernames are used by a given IP address.",
+ "apihelp-query+checkuser-summary": "Check which IP addresses are used by a given username or which usernames are used by a given IP address.",
+ "apihelp-query+checkuser-param-request": "Type of CheckUser request:\n;userips:Get IP address of target user.\n;edits:Get changes from target IP address or range.\n;ipusers:Get users from target IP address or range.",
+ "apihelp-query+checkuser-param-target": "Username, IP address, or CIDR range to check.",
+ "apihelp-query+checkuser-param-reason": "Reason to check.",
+ "apihelp-query+checkuser-param-limit": "Limit of rows.",
+ "apihelp-query+checkuser-param-timecond": "Time limit of user data (like \"-2 weeks\" or \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Use XFF data instead of IP address.",
+ "apihelp-query+checkuser-example-1": "Check IP addresses for [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Check edits from 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Get entries from the CheckUser log.",
+ "apihelp-query+checkuserlog-summary": "Get entries from the CheckUser log.",
+ "apihelp-query+checkuserlog-param-user": "Username of the CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Checked user, IP address, or CIDR range.",
+ "apihelp-query+checkuserlog-param-limit": "Limit of rows.",
+ "apihelp-query+checkuserlog-param-from": "The timestamp to start enumerating from.",
+ "apihelp-query+checkuserlog-param-to": "The timestamp to end enumerating.",
+ "apihelp-query+checkuserlog-example-1": "Show checks of [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Show checks of 192.0.2.0/24 after 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "You must define reason for check.",
+ "apierror-checkuser-timelimit": "You need use correct time limit (like \"-2 weeks\" or \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Invalid request mode"
+}
diff --git a/CheckUser/i18n/api/es-formal.json b/CheckUser/i18n/api/es-formal.json
new file mode 100644
index 00000000..2d4ce1aa
--- /dev/null
+++ b/CheckUser/i18n/api/es-formal.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "MarcoAurelio"
+ ]
+ },
+ "apierror-checkuser-missingsummary": "Debe introducir una razón para la comprobación.",
+ "apierror-checkuser-timelimit": "Necesita introducir un plazo máximo de tiempo correcto (como \"-2 weeks\" o \"2 weeks ago\")."
+}
diff --git a/CheckUser/i18n/api/es.json b/CheckUser/i18n/api/es.json
new file mode 100644
index 00000000..a4f2f8c8
--- /dev/null
+++ b/CheckUser/i18n/api/es.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fitoschido",
+ "JasterTDC",
+ "Macofe",
+ "MarcoAurelio",
+ "Ryo567"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Comprueba qué direcciones IP utiliza el nombre de usuario dado o qué nombres de usuario han utilizado una dirección IP específica.",
+ "apihelp-query+checkuser-summary": "Comprobar qué direcciones IP han sido usadas por un determinado usuario o qué usuarios han usado una determinada dirección IP.",
+ "apihelp-query+checkuser-param-request": "Tipos de solicitudes:\n;userips:Obtener las direcciones IP del usuario a verificar.\n;edits:Obtener las ediciones hechas desde una determinada dirección IP o rango de IPs.\n;ipusers:Obtener los usuarios que han usado una determinada dirección IP o rango de IPs.",
+ "apihelp-query+checkuser-param-target": "Nombre de usuario, dirección IP o intervalo CIDR que comprobar.",
+ "apihelp-query+checkuser-param-reason": "Motivo para comprobar.",
+ "apihelp-query+checkuser-param-limit": "Límite de filas.",
+ "apihelp-query+checkuser-param-timecond": "Límite de tiempo de datos del usuario (p. ej. \"-2 weeks\" o \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Utiliza datos XFF en lugar de direcciones IP.",
+ "apihelp-query+checkuser-example-1": "Comprobar direcciones IP para [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Comprobar ediciones desde 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Obtener entradas del registro de verificación de usuarios.",
+ "apihelp-query+checkuserlog-summary": "Obtener entradas del registro de verificación de usuarios.",
+ "apihelp-query+checkuserlog-param-user": "Nombre del usuario con permiso de verificador de usuarios.",
+ "apihelp-query+checkuserlog-param-target": "Se ha comprobado el usuario, dirección IP o CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "Límite de filas.",
+ "apihelp-query+checkuserlog-param-from": "El cronomarcador para comenzar la enumeración.",
+ "apihelp-query+checkuserlog-param-to": "El cronomarcador para finalizar la enumeración.",
+ "apihelp-query+checkuserlog-example-1": "Mostrar verificaciones de [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Mostrar verificaciones de 192.0.2.0/24 después del 15 de octubre de 2011 a las 23:00:00",
+ "apierror-checkuser-missingsummary": "Debes introducir una razón para la comprobación.",
+ "apierror-checkuser-timelimit": "Necesitas introducir un plazo máximo de tiempo correcto (como \"-2 weeks\" o \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Modo de solicitud no válido"
+}
diff --git a/CheckUser/i18n/api/fa.json b/CheckUser/i18n/api/fa.json
new file mode 100644
index 00000000..58df7c02
--- /dev/null
+++ b/CheckUser/i18n/api/fa.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Huji"
+ ]
+ },
+ "apihelp-query+checkuser-description": "بررسی کنید کدام نشانی‌های آی‌پی توسط یک حساب استفاده شده‌اند، یا کدام حساب‌ها توسط یک نشانی آی‌پی به کار رفته‌اند.",
+ "apihelp-query+checkuser-summary": "بررسی کنید کدام نشانی‌های آی‌پی توسط یک حساب استفاده شده‌اند، یا کدام حساب‌ها توسط یک نشانی آی‌پی به کار رفته‌اند.",
+ "apihelp-query+checkuser-param-request": "انواع درخواست‌های بازرسی کاربر:\n;userips: گرفتن نشانی آی‌پی کاربر هدف.\n;edits: گرفتن فهرست تغییرات مرتبط با یک نشانی یا بازهٔ آی‌پی\n;ipusers: گرفتن کاربرهای مرتبط با یک نشانی یا بازهٔ آی‌پی",
+ "apihelp-query+checkuser-param-target": "نام کاربر، بازهٔ آی‌پی، یا بازهٔ سی‌آی‌دی‌آر که بازرسی می‌شود.",
+ "apihelp-query+checkuser-param-reason": "دلیل بازرسی.",
+ "apihelp-query+checkuser-param-limit": "محدودهٔ سطرها.",
+ "apihelp-query+checkuser-param-timecond": "محدودهٔ زمانی دادهٔ کاربر (مثلاً «‎-2 weeks» یا «‎2 weeks ago»).",
+ "apihelp-query+checkuser-param-xff": "به جای نشانی آی‌پی از اطلاعات اکس‌اف‌اف استفاده شود.",
+ "apihelp-query+checkuser-example-1": "بازرسی نشانی‌های آی‌پی برای [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "بازرسی ویرایش‌های انجام شده از 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "دریافت موارد از سیاههٔ بازرسی.",
+ "apihelp-query+checkuserlog-summary": "دریافت موارد از سیاههٔ بازرسی.",
+ "apihelp-query+checkuserlog-param-user": "نام کاربری بازرس.",
+ "apihelp-query+checkuserlog-param-target": "بازرسی کاربر، نشانی آی‌پی، یا بازهٔ سی‌آی‌دی‌آر.",
+ "apihelp-query+checkuserlog-param-limit": "محدودیت ردیف‌ها.",
+ "apihelp-query+checkuserlog-param-from": "برچسب زمان برای شروع شمارش.",
+ "apihelp-query+checkuserlog-param-to": "برچسب زمان برای پایان شمارش.",
+ "apihelp-query+checkuserlog-example-1": "نمایش بازرسی‌های [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "نمایش بازرسی‌های 192.0.2.0/24 پس از 2011‎-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "باید دلیل بازرسی را مشخص کنید.",
+ "apierror-checkuser-timelimit": "باید بازهٔ زمانی درست استفاده کنید (نظیر «‎2 weeks ago» یا «‎-2 weeks»).",
+ "apierror-checkuser-invalidmode": "شیوهٔ درخواست نامعتبر"
+}
diff --git a/CheckUser/i18n/api/fr.json b/CheckUser/i18n/api/fr.json
new file mode 100644
index 00000000..cb17d1b4
--- /dev/null
+++ b/CheckUser/i18n/api/fr.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "Element303",
+ "Gomoko",
+ "McDutchie",
+ "Wladek92"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Vérifier quelles adresses IP sont utilisées par un nom d’utilisateur donné ou quels noms d’utilisateur sont utilisés par une adresse IP donnée.",
+ "apihelp-query+checkuser-summary": "Vérifier quelles adresses IP sont utilisées pour un nom d’utilisateur donné, ou quels noms d’utilisateur sont utilisés pour une adresse IP donnée.",
+ "apihelp-query+checkuser-param-request": "Type de demande CheckUser :\n;userips:Obtenir l’adresse IP de l’utilisateur cible.\n;edits:Obtenir les modifications de l’adresse IP ou de la plage cible.\n;ipusers:Obtenir les utilisateurs de l’adresse IP ou de la plage cible.",
+ "apihelp-query+checkuser-param-target": "Nom d'utilisateur, adresse IP ou plage CIDR à vérifier.",
+ "apihelp-query+checkuser-param-reason": "Motif de vérification.",
+ "apihelp-query+checkuser-param-limit": "Limite de lignes.",
+ "apihelp-query+checkuser-param-timecond": "Limite de temps des données de l'utilisateur (comme \"-2 weeks\" ou \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Utiliser des données XFF au lieu d'adresse IP.",
+ "apihelp-query+checkuser-example-1": "Vérifier les adresses IP pour [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Vérifier les modifications pour 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Obtenir les entrées du journal CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Obtenir les entrées du journal de vérification des utilisateurs.",
+ "apihelp-query+checkuserlog-param-user": "Nom d’utilisateur de CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Utilisateur, adresse IP ou plage CIDR vérifié.",
+ "apihelp-query+checkuserlog-param-limit": "Limite de lignes.",
+ "apihelp-query+checkuserlog-param-from": "L’horodatage auquel démarrer l’énumération.",
+ "apihelp-query+checkuserlog-param-to": "L’horodatage auquel arrêter l’énumération.",
+ "apihelp-query+checkuserlog-example-1": "Afficher les vérifications de [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Afficher les vérifications de 192.0.2.0/24 après 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Vous devez définir la raison pour laquelle le contrôle est fait.",
+ "apierror-checkuser-timelimit": "Vous devez utiliser une limite de temps correcte (comme \"-2 weeks\" ou \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Mode de requête invalide"
+}
diff --git a/CheckUser/i18n/api/gl.json b/CheckUser/i18n/api/gl.json
new file mode 100644
index 00000000..070b8285
--- /dev/null
+++ b/CheckUser/i18n/api/gl.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Banjo",
+ "Elisardojm",
+ "Fisterraeomar",
+ "Macofe",
+ "McDutchie"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Comprobar que enderezos IP son empregados por un usuario concreto ou que nomes de usuario son empregados por un IP específico.",
+ "apihelp-query+checkuser-summary": "Comprobar que enderezos IP son empregados por un usuario concreto ou que nomes de usuario son empregados por un IP específico.",
+ "apihelp-query+checkuser-param-request": "Tipo da petición CheckUser:\n;userips: Retornar o enderezo IP do usuario obxetivo.\n;edits: Retornar os cambios do enderezo IP ou rango obxetivo.\n;ipusers: Retornar os usuarios do enderezo IP ou rango obxetivo.",
+ "apihelp-query+checkuser-param-target": "Nome de usuario, dirección IP, ou rango CIDR a comprobar.",
+ "apihelp-query+checkuser-param-reason": "Motivo para a comprobación.",
+ "apihelp-query+checkuser-param-limit": "Límite de filas.",
+ "apihelp-query+checkuser-param-timecond": "Límite de tempo dos datos de usuario (coma \"-2 weeks\" ou \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Usar datos XFF no canto do enderezo IP.",
+ "apihelp-query+checkuser-example-1": "Comprobar enderezos IP para [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Comprobar as edicións de 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Retornar entradas do rexistro de CheckUser",
+ "apihelp-query+checkuserlog-summary": "Retornar entradas do rexistro de CheckUser",
+ "apihelp-query+checkuserlog-param-user": "Nome de usuario do CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Usuario comprobado, enderezo IP, ou rango CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "Límite de filas.",
+ "apihelp-query+checkuserlog-param-from": "Selo de tempo no que comezar a enumeración.",
+ "apihelp-query+checkuserlog-param-to": "Selo de tempo para rematar a enumeración.",
+ "apihelp-query+checkuserlog-example-1": "Amosar as comprobacións de [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Amosar as comprobacións de 192.0.2.0/24 despois de 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Debes definir un motivo para comprobar.",
+ "apierror-checkuser-timelimit": "Debe usar un límite de tempo correcto (como \"-2 weeks\" ou \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Modo de petición non válido"
+}
diff --git a/CheckUser/i18n/api/got.json b/CheckUser/i18n/api/got.json
new file mode 100644
index 00000000..14c7c110
--- /dev/null
+++ b/CheckUser/i18n/api/got.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gothicspeaker"
+ ]
+ },
+ "apihelp-query+checkuser-param-target": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉, IP 𐍂𐌰𐌸𐌾𐍉, 𐌰𐌹𐌸𐌸𐌰𐌿 CIDR",
+ "apihelp-query+checkuser-param-xff": "𐌱𐍂𐌿𐌺𐌴𐌹 𐍇𐍆𐍆 𐌲𐌹𐌱𐍉𐍃 𐌽𐌹𐌷 IP 𐍂𐌰𐌸𐌾𐍉."
+}
diff --git a/CheckUser/i18n/api/gu.json b/CheckUser/i18n/api/gu.json
new file mode 100644
index 00000000..ce9444e0
--- /dev/null
+++ b/CheckUser/i18n/api/gu.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "CptViraj"
+ ]
+ },
+ "apihelp-query+checkuser-param-reason": "તપાસ માટેનું કારણ.",
+ "apihelp-query+checkuserlog-param-user": "સભ્યતપાસકનું સભ્યનામ.",
+ "apierror-checkuser-missingsummary": "તમારે તપાસ માટેનું કારણ આપવું જરૂરી છે."
+}
diff --git a/CheckUser/i18n/api/he.json b/CheckUser/i18n/api/he.json
new file mode 100644
index 00000000..3b81b8d7
--- /dev/null
+++ b/CheckUser/i18n/api/he.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Guycn2"
+ ]
+ },
+ "apihelp-query+checkuser-description": "בדיקה אילו כתובות IP משמשות שם משתמש מסוים או אילו שמות משתמש נמצאים בשימוש על־ידי כתובת IP מסוימת.",
+ "apihelp-query+checkuser-summary": "בדיקה אילו כתובות IP משמשות שם משתמש מסוים או אילו שמות משתמש משמשות כתובת IP מסוימת.",
+ "apihelp-query+checkuser-param-request": "סוגי בדיקת משתמש:\n;userips:קבלת כתובות IP של המשתמש המיועד.\n;edits:קבלת שינויים מכתובת ה־IP או מהטווח המיועדים.\n;ipusers:קבלת משתמשים מכתובת ה־IP או מהטווח המיועדים.",
+ "apihelp-query+checkuser-param-target": "שם משתמש, כתובת IP, או טווח CIDR לבדיקה.",
+ "apihelp-query+checkuser-param-reason": "סיבה לבדיקה.",
+ "apihelp-query+checkuser-param-limit": "מגבלת שורות.",
+ "apihelp-query+checkuser-param-timecond": "מגבלת זמן של נתוני משתמש (כמו \"-2 weeks\" או \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "להשתמש בנתוני XFF במקום בכתובת IP.",
+ "apihelp-query+checkuser-example-1": "בדיקת כתובות IP עבור [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "בדיקת עריכות מ־192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "קבלת רשומות מיומן בדיקת משתמשים.",
+ "apihelp-query+checkuserlog-summary": "קבלת רשומות מיומן בדיקת משתמשים.",
+ "apihelp-query+checkuserlog-param-user": "שם משתמש של הבודק.",
+ "apihelp-query+checkuserlog-param-target": "המשתמש הנבדק, כתובת IP או טווח CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "מגבלת שורות.",
+ "apihelp-query+checkuserlog-param-from": "חותם־הזמן שהמנייה תתחיל ממנו.",
+ "apihelp-query+checkuserlog-param-to": "חותם־הזמן שהמנייה תסתיים בו.",
+ "apihelp-query+checkuserlog-example-1": "הצגת בדיקות של [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "קבלת בדיקות של 192.0.2.0/24 אחרי 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "עליך להגדיר סיבה לבדיקה.",
+ "apierror-checkuser-timelimit": "עליך להגדיר מגבלת זמן נכונה (למשל \"-2 weeks\" או \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "מצב בקשה בלתי־תקין"
+}
diff --git a/CheckUser/i18n/api/hi.json b/CheckUser/i18n/api/hi.json
new file mode 100644
index 00000000..d098ae4f
--- /dev/null
+++ b/CheckUser/i18n/api/hi.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sfic"
+ ]
+ },
+ "apihelp-query+checkuser-param-limit": "पंक्तियों की सीमा",
+ "apihelp-query+checkuserlog-param-limit": "पंक्तियों की सीमा"
+}
diff --git a/CheckUser/i18n/api/hu.json b/CheckUser/i18n/api/hu.json
new file mode 100644
index 00000000..466d1ed5
--- /dev/null
+++ b/CheckUser/i18n/api/hu.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bencemac",
+ "Wolf Rex"
+ ]
+ },
+ "apihelp-query+checkuser-description": "A megadott felhasználónév által használt IP-címek vagy egy megadott IP-cím által használt felhasználónevek ellenőrzése.",
+ "apihelp-query+checkuser-summary": "A megadott felhasználónév által használt IP-címek vagy egy megadott IP-cím által használt felhasználónevek ellenőrzése.",
+ "apihelp-query+checkuser-param-request": "IP-ellenőri kérelemtípusok:\n;userips:Konkrét felhasználó IP-címeinek lekérdezése.\n;edits:Konkrét IP vagy tartomány közreműködéseinek lekérdezése.\n;ipusers:Konkrét IP-t vagy tartományt használó felhasználók lekérdezése.",
+ "apihelp-query+checkuser-param-target": "Ellenőrizendő felhasználói név, IP-cím vagy CIDR tartomány.",
+ "apihelp-query+checkuser-param-reason": "Az ellenőrzés oka.",
+ "apihelp-query+checkuser-param-timecond": "Felhasználói adatok időlimitje (pl. „-2 weeks” vagy „2 weeks ago”).",
+ "apihelp-query+checkuser-param-xff": "XFF-adat használata IP-cím helyett.",
+ "apihelp-query+checkuser-example-1": "[[User:Example]] IP-címeinek ellenőrzése",
+ "apihelp-query+checkuser-example-2": "192.0.2.0/24 szerkesztéseinek ellenőrzése",
+ "apihelp-query+checkuserlog-description": "Bejegyzések lekérése az IP-ellenőri naplóból",
+ "apihelp-query+checkuserlog-summary": "Bejegyzések lekérése az IP-ellenőri naplóból",
+ "apihelp-query+checkuserlog-param-user": "Az IP-ellenőr neve.",
+ "apihelp-query+checkuserlog-param-target": "Ellenőrzött felhasználó, IP-cím vagy CIDR tartomány.",
+ "apihelp-query+checkuserlog-param-from": "Listázás ettől az időbélyegtől.",
+ "apihelp-query+checkuserlog-param-to": "Listázás eddig az időbélyegig.",
+ "apihelp-query+checkuserlog-example-1": "[[User:Example]] ellenőrzéseinek mutatása",
+ "apihelp-query+checkuserlog-example-2": "192.0.2.0/24 ellenőrzéseinek mutatása 2011-10-15T23:00:00Z után",
+ "apierror-checkuser-missingsummary": "Meg kell adnod az ellenőrzés okát.",
+ "apierror-checkuser-timelimit": "Helyes időlimitet kell használnod (pl. „-2 weeks” vagy „2 weeks ago”).",
+ "apierror-checkuser-invalidmode": "Érvénytelen kérésmód."
+}
diff --git a/CheckUser/i18n/api/ia.json b/CheckUser/i18n/api/ia.json
new file mode 100644
index 00000000..f95f83d6
--- /dev/null
+++ b/CheckUser/i18n/api/ia.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Verificar qual nomines de usator usa un adresse IP date o qual adresses IP usa un nomine de usator date.",
+ "apihelp-query+checkuser-summary": "Verificar qual nomines de usator usa un adresse IP date o qual adresses IP usa un nomine de usator date.",
+ "apihelp-query+checkuser-param-request": "Typo de demanda CheckUser :\n;userips:Obtener le adresse IP del usator.\n;edits:Obtener le modificationes del adresse o intervallo IP.\n;ipusers:Obtener le usatores del adresse o intervallo IP.",
+ "apihelp-query+checkuser-param-target": "Le nomine de usator, adresse IP o intervallo CIDR a verificar.",
+ "apihelp-query+checkuser-param-reason": "Motivo pro verificar.",
+ "apihelp-query+checkuser-param-limit": "Limite de lineas.",
+ "apihelp-query+checkuser-param-timecond": "Limite de tempore del datos de usator (in anglese, como \"-2 weeks\" o \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Usar datos XFF in loco del adresse IP.",
+ "apihelp-query+checkuser-example-1": "Verificar adresses IP pro [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Verificar modificationes ab 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Obtener entratas ab le registro CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Obtener entratas ab le registro CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Nomine del usator con le derecto CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Le usator, adresse IP o intervallo CIDR verificate.",
+ "apihelp-query+checkuserlog-param-limit": "Limite de lineas.",
+ "apihelp-query+checkuserlog-param-from": "Le data e hora al qual comenciar a enumerar.",
+ "apihelp-query+checkuserlog-param-to": "Le data e hora al qual cessar de enumerar.",
+ "apihelp-query+checkuserlog-example-1": "Monstrar verificationes de [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Monstrar verificationes de 192.0.2.0/24 post 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Tu debe scriber un motivo pro verificar.",
+ "apierror-checkuser-timelimit": "Tu debe usar un limite de tempore correcte (in anglese, como \"-2 weeks\" or \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Modo de requesta invalide"
+}
diff --git a/CheckUser/i18n/api/id.json b/CheckUser/i18n/api/id.json
new file mode 100644
index 00000000..636f1545
--- /dev/null
+++ b/CheckUser/i18n/api/id.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie",
+ "Rachmat04"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Periksa alamat IP mana yang digunakan oleh pengguna yang ditentukan atau nama pengguna manakah yang digunakan oleh alamat IP yang ditentukan.",
+ "apihelp-query+checkuser-param-request": "Jenis permintaan CheckUser:\n;userips: Mendapatkan alamat IP dari pengguna yang dituju.\n;edits: Mendapatkan perubahan dari alamat IP atau rentang alamat IP tujuan.\n;ipusers: Mendapatkan pengguna dari alamat IP atau rentang alamat IP tujuan.",
+ "apihelp-query+checkuser-param-target": "Nama pengguna, alamat IP atau rentang CIDR untuk diperiksa.",
+ "apihelp-query+checkuser-param-reason": "Alasan pemeriksaan.",
+ "apihelp-query+checkuser-param-limit": "Batas baris.",
+ "apihelp-query+checkuser-param-timecond": "Batas waktu data pengguna (seperti \"-2 weeks\" atau \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Gunakan data XFF alih-alih alamat IP.",
+ "apihelp-query+checkuser-example-1": "Periksa alamat IP untuk [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Periksa suntingan dari 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Dapatkan entri dari catatan CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Nama pengguna CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Pengguna yang telah diperiksa, alamat IP, atau rentang CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "Batas baris.",
+ "apihelp-query+checkuserlog-param-from": "Stempel waktu untuk mulai menghitung.",
+ "apihelp-query+checkuserlog-param-to": "Stempel waktu untuk mengakhiri hitungan.",
+ "apihelp-query+checkuserlog-example-1": "Tampilkan pemeriksaan dari [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Tampilkan pemeriksaan dari 192.0.2.0/24 setelah 2011-10-15T23:00:00Z"
+}
diff --git a/CheckUser/i18n/api/it.json b/CheckUser/i18n/api/it.json
new file mode 100644
index 00000000..dbe9a4ea
--- /dev/null
+++ b/CheckUser/i18n/api/it.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Gianfranco",
+ "McDutchie",
+ "Melos",
+ "Nivit"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Controlla quali indirizzi IP vengono usati da un determinato nome utente o quali nomi utente vengono usati da un dato IP.",
+ "apihelp-query+checkuser-summary": "Controlla quali indirizzi IP vengono usati da un determinato nome utente o quali nomi utente vengono usati da un dato indirizzo IP.",
+ "apihelp-query+checkuser-param-request": "Tipo di richiesta CheckUser:\n;userips:Ottieni l'indirizzo IP dell'utente osservato.\n;edit:Ottieni i cambiamenti dell'indirizzo IP o range.\n;ipusers:Ottieni gli utenti da un indirizzo IP o range.",
+ "apihelp-query+checkuser-param-target": "Nome utente, indirizzo IP, o range CIDR da controllare.",
+ "apihelp-query+checkuser-param-reason": "Ragione per controllare.",
+ "apihelp-query+checkuser-param-limit": "Limite di righe.",
+ "apihelp-query+checkuser-param-timecond": "Il limite di tempo dei dati utente (come \"-2 weeks\" o \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Utilizzare dati XFF invece dell'indirizzo IP.",
+ "apihelp-query+checkuser-example-1": "Verificare gli indirizzi IP per [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Controllare le modifiche di 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Vedi nel registro CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Ottieni i risultati dal registro CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Nome del CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Utente, indirizzo IP, o range CIDR controllato.",
+ "apihelp-query+checkuserlog-param-limit": "Limite di righe.",
+ "apihelp-query+checkuserlog-param-from": "Il timestamp da cui iniziare l'elenco.",
+ "apihelp-query+checkuserlog-param-to": "Il timestamp al quale interrompere l'elenco.",
+ "apihelp-query+checkuserlog-example-1": "Mostra controlli di [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Mostra controlli di 192.0.2.0/24 dopo il 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Devi indicare una motivazione per il controllo.",
+ "apierror-checkuser-timelimit": "Devi utilizzare un corretto limite temporale (come \"-2 settimane\" o \"2 settimane fa\").",
+ "apierror-checkuser-invalidmode": "Modalità di richiesta non valida"
+}
diff --git a/CheckUser/i18n/api/ja.json b/CheckUser/i18n/api/ja.json
new file mode 100644
index 00000000..eba89e76
--- /dev/null
+++ b/CheckUser/i18n/api/ja.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mirinano",
+ "Otokoume",
+ "Shirayuki",
+ "W.CC",
+ "Yusuke1109"
+ ]
+ },
+ "apihelp-query+checkuser-description": "指定した利用者名の利用者が使用した IPアドレス や、指定した IPアドレス を使用した利用者名を調査します。",
+ "apihelp-query+checkuser-summary": "指定した利用者名の利用者が使用した IPアドレス や、指定した IPアドレス を使用した利用者名を調査します。",
+ "apihelp-query+checkuser-param-request": "利用者調査リクエストの種類です:\n;userips:対象利用者の IPアドレス を取得します。\n;edits:対象 IPアドレス または IPアドレス 範囲による編集を取得します。\n;ipusers:対象 IPアドレス または IPアドレス 範囲を使用した利用者を取得します。",
+ "apihelp-query+checkuser-param-target": "調査する利用者名、IP アドレス、CIDR 範囲のいずれかです。",
+ "apihelp-query+checkuser-param-reason": "調査の理由です。",
+ "apihelp-query+checkuser-param-limit": "行数の上限です。",
+ "apihelp-query+checkuser-param-timecond": "利用者データの期間の上限です (例: \"-2 weeks\" または \"2 weeks ago\")。",
+ "apihelp-query+checkuser-param-xff": "IPアドレス の代わりに XFF データを使用します。",
+ "apihelp-query+checkuser-example-1": "[[User:Example]] が使用した IPアドレス を調査",
+ "apihelp-query+checkuser-example-2": "192.0.2.0/24 からなされた編集を調査",
+ "apihelp-query+checkuserlog-description": "利用者調査の記録から項目を取得します。",
+ "apihelp-query+checkuserlog-summary": "利用者調査の記録から項目を取得します。",
+ "apihelp-query+checkuserlog-param-user": "利用者調査の実行者の利用者名です。",
+ "apihelp-query+checkuserlog-param-target": "調査する対象の利用者、IP アドレス、CIDR範囲のいずれかです。",
+ "apihelp-query+checkuserlog-param-limit": "行数の上限です。",
+ "apihelp-query+checkuserlog-param-from": "一覧の開始点となる日時",
+ "apihelp-query+checkuserlog-param-to": "一覧の終了点となる日時",
+ "apihelp-query+checkuserlog-example-1": "[[User:Example]] の調査を表示",
+ "apihelp-query+checkuserlog-example-2": "192.0.2.0/24 の 2011-10-15T23:00:00Z 以降の調査を表示",
+ "apierror-checkuser-missingsummary": "調査理由を明確にする必要があります。"
+}
diff --git a/CheckUser/i18n/api/ka.json b/CheckUser/i18n/api/ka.json
new file mode 100644
index 00000000..675af369
--- /dev/null
+++ b/CheckUser/i18n/api/ka.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Otogi"
+ ]
+ },
+ "apihelp-query+checkuser-param-reason": "შეჩერების მიზეზი",
+ "apihelp-query+checkuser-param-limit": "რიგების ლიმიტი",
+ "apihelp-query+checkuserlog-param-limit": "რიგების ლიმიტი"
+}
diff --git a/CheckUser/i18n/api/ko.json b/CheckUser/i18n/api/ko.json
new file mode 100644
index 00000000..07de53c1
--- /dev/null
+++ b/CheckUser/i18n/api/ko.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kwj2772",
+ "McDutchie",
+ "Revi",
+ "Ykhwong",
+ "아라"
+ ]
+ },
+ "apihelp-query+checkuser-description": "특정한 사용자가 어떤 IP 주소를 썼는지 확인하거나 특정한 IP 주소를 사용한 계정 이름을 확인합니다.",
+ "apihelp-query+checkuser-summary": "특정한 사용자가 어떤 IP 주소를 썼는지 확인하거나 특정한 IP 주소를 사용한 계정 이름을 확인합니다.",
+ "apihelp-query+checkuser-param-request": "검사 요청의 유형:\n;userips: 대상 사용자의 IP 주소를 불러옴.\n;edits: 대상 IP 주소나 대역에서 이루어진 편집을 불러옴.\n;ipusers: 대상 IP 주소나 대역을 사용한 계정을 불러옴.",
+ "apihelp-query+checkuser-param-target": "검사할 계정 이름, IP 주소 혹은 CIDR 범위",
+ "apihelp-query+checkuser-param-reason": "검사 이유.",
+ "apihelp-query+checkuser-param-limit": "검사 한도",
+ "apihelp-query+checkuser-param-timecond": "사용자 데이터의 시간 제약 (예: \"-2 weeks\" 또는 \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "IP 주소 대신 XFF 데이터를 이용.",
+ "apihelp-query+checkuser-example-1": "[[User:Example]]에 대해 IP 주소 검사",
+ "apihelp-query+checkuser-example-2": "192.0.2.0/24에 대해 편집 검사",
+ "apihelp-query+checkuserlog-description": "검사관 기록에서 항목을 가져옵니다.",
+ "apihelp-query+checkuserlog-summary": "검사관 기록에서 항목을 가져옵니다.",
+ "apihelp-query+checkuserlog-param-user": "검사관의 사용자 이름",
+ "apihelp-query+checkuserlog-param-target": "검사된 사용자, IP 주소, CIDR 범위",
+ "apihelp-query+checkuserlog-param-limit": "검사 한도",
+ "apihelp-query+checkuserlog-param-from": "나열을 시작할 타임스탬프",
+ "apihelp-query+checkuserlog-param-to": "나열을 끝낼 타임스탬프",
+ "apihelp-query+checkuserlog-example-1": "[[User:Example]]에 대한 검사 보기",
+ "apihelp-query+checkuserlog-example-2": "192.0.2.0/24에 대한 2011-10-15T23:00:00Z 이후의 검사 보기",
+ "apierror-checkuser-missingsummary": "검사 이유를 지정해야 합니다.",
+ "apierror-checkuser-timelimit": "올바른 시간 형식(\"-2 weeks\" 혹은 \"2 weeks ago\"과 같이)으로 사용하셔야 합니다.",
+ "apierror-checkuser-invalidmode": "잘못된 요청 모드"
+}
diff --git a/CheckUser/i18n/api/ksh.json b/CheckUser/i18n/api/ksh.json
new file mode 100644
index 00000000..481323cd
--- /dev/null
+++ b/CheckUser/i18n/api/ksh.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Donn övverpröhve wat för en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße vun enem metmaacher med enem beschtemmpte Nahme udder wat för en nahme vun Metmaacher övver en beschtemmpte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß em Wikki opdouche.",
+ "apihelp-query+checkuser-param-request": "De Zood Övverpröhvong:\n;userips:Holl enem Metmaacher sing <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß.\n;edits:Holl de Änderonge över en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß udder ene Berätt.\n;ipusers:Holl de Metmaacher för en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß udder ene Berätt.",
+ "apihelp-query+checkuser-param-target": "Däm Metmaacher singe Nahme, de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß, udder dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt zom Övverpröhve.",
+ "apihelp-query+checkuser-param-reason": "der Jrond för et Övverpröhfe.",
+ "apihelp-query+checkuser-param-limit": "En Bejränzung för de Aanzahl Reihje.",
+ "apihelp-query+checkuser-param-timecond": "En Bejränzung noh de Zigg för der Ömfang vun Aanjahbe övver Metmaacher, allso esu jät wi: „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">2 weeks</code>“",
+ "apihelp-query+checkuser-param-xff": "Nemm de Aanjahbe uß dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">XFF</i>-Koppreih un nit de tiräkte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß.",
+ "apihelp-query+checkuser-example-1": "Övverpröhv de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße vum [[Metmaacher:Beijschpell]]\n<!--\nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Bcheckuser-example-1/en_(3)\n-->",
+ "apihelp-query+checkuser-example-2": "Donn Änderonge vun <code>192.0.2.0/24</code> övverpröhfe.",
+ "apihelp-query+checkuserlog-description": "Holl Enndrähsch vum {{int:Checkuserlog}}",
+ "apihelp-query+checkuserlog-param-user": "Dä Nahme vun däm Metmaacher vum {{int:Checkuser}}.",
+ "apihelp-query+checkuserlog-param-target": "Dä jepröhvte Metmaacher, de jepröhvte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß, udder dä jepröhvte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt.",
+ "apihelp-query+checkuserlog-param-limit": "De Jränß aan Reihje.",
+ "apihelp-query+checkuserlog-param-from": "Dattum un Uhrzigg, vun woh aan opzälle.",
+ "apihelp-query+checkuserlog-param-to": "Dattum un Uhrzigg, bes wann opzälle.",
+ "apihelp-query+checkuserlog-example-1": "Donn de Övverpröhfonge vum „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[User:Example]]</code>“ aanzeije.",
+ "apihelp-query+checkuserlog-example-2": "Zeisch de Övverpröhvonge vun 192.0.2.0/24 aff 2011-10-15T23:00:00Z"
+}
diff --git a/CheckUser/i18n/api/lb.json b/CheckUser/i18n/api/lb.json
new file mode 100644
index 00000000..460c7c0e
--- /dev/null
+++ b/CheckUser/i18n/api/lb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby"
+ ]
+ },
+ "apihelp-query+checkuser-param-reason": "Grond fir nozekucken."
+}
diff --git a/CheckUser/i18n/api/lt.json b/CheckUser/i18n/api/lt.json
new file mode 100644
index 00000000..071358b2
--- /dev/null
+++ b/CheckUser/i18n/api/lt.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eitvys200"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Patikrinti kokie IP adresai yra naudojami pateikto vartotojo vardo arba kokie vartotojų vardai yra naudojami pateikto IP adreso.",
+ "apihelp-query+checkuser-param-reason": "Tikrinimo priežastis.",
+ "apihelp-query+checkuser-param-limit": "Eilučių limitas.",
+ "apihelp-query+checkuser-example-1": "Patikrinti [[User:Example]] IP adresus",
+ "apihelp-query+checkuser-example-2": "Patikrinti 192.0.2.0/24 keitimus",
+ "apihelp-query+checkuserlog-description": "Gauti įrašus iš CheckUser žurnalo.",
+ "apihelp-query+checkuserlog-param-user": "CheckUser vartotojo vardas.",
+ "apihelp-query+checkuserlog-param-limit": "Eilučių limitas.",
+ "apihelp-query+checkuserlog-example-1": "Rodyti [[User:Example]] patikrinimus",
+ "apihelp-query+checkuserlog-example-2": "Rodyti 192.0.2.0/24 patikrinimus, po 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Privalote nurodyti tikrinimo priežastį.",
+ "apierror-checkuser-invalidmode": "Negalimas prašymo režimas"
+}
diff --git a/CheckUser/i18n/api/mai.json b/CheckUser/i18n/api/mai.json
new file mode 100644
index 00000000..92bc00b7
--- /dev/null
+++ b/CheckUser/i18n/api/mai.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tulsi Bhagat"
+ ]
+ },
+ "apihelp-query+checkuser-param-reason": "जाँच करे के कारण"
+}
diff --git a/CheckUser/i18n/api/mk.json b/CheckUser/i18n/api/mk.json
new file mode 100644
index 00000000..890708dc
--- /dev/null
+++ b/CheckUser/i18n/api/mk.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06",
+ "McDutchie"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Провери кои IP-адреси ги користи дадено корисничко име или пак кои кориснички имиња ги користи дадена IP-адреса.",
+ "apihelp-query+checkuser-summary": "Провери кои IP-адреси ги користи дадено корисничко име или пак кои кориснички имиња ги користи дадена IP-адреса.",
+ "apihelp-query+checkuser-param-request": "Тип на барање со CheckUser:\n;userips: Дај IP-адреса на целен корисник.\n;edits: Дај промени од целна IP-адреса или опсег.\n;ipusers: Дај корисници од целна IP-адреса или опсег.",
+ "apihelp-query+checkuser-param-target": "Корисничко име, IP-адреса или CIDR-опсег за проверка.",
+ "apihelp-query+checkuser-param-reason": "Причина за проверката.",
+ "apihelp-query+checkuser-param-limit": "Ограничување на редовите.",
+ "apihelp-query+checkuser-param-timecond": "Временско ограничување за корисничките податоци (како на пр. „-2 weeks“ или „2 weeks ago“).",
+ "apihelp-query+checkuser-param-xff": "Користи XFF-податоци наместо IP-адреса.",
+ "apihelp-query+checkuser-example-1": "Провери го [[User:Example]] по IP-адресите",
+ "apihelp-query+checkuser-example-2": "Провери ги уредувањата од 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Дај ставки од записникот на CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Дај ставки од записникот на CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Корисничко име на проверувачот (CheckUser).",
+ "apihelp-query+checkuserlog-param-target": "Проверен корисник, IP-адреса или CIDR-опсег.",
+ "apihelp-query+checkuserlog-param-limit": "Ограничување на редовите.",
+ "apihelp-query+checkuserlog-param-from": "Од кој датум и време да почне набројувањето.",
+ "apihelp-query+checkuserlog-param-to": "На кој датум и време да запре набројувањето.",
+ "apihelp-query+checkuserlog-example-1": "Прикажи проверки на [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Прикажи проверки на 192.0.2.0/24 по 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Мора да зададете причина за проверка.",
+ "apierror-checkuser-timelimit": "Ќе треба да употребите исправно временско ограничување (на пр. „-2 weeks“ „2 weeks ago“).",
+ "apierror-checkuser-invalidmode": "Неважечки режим на побарување"
+}
diff --git a/CheckUser/i18n/api/mr.json b/CheckUser/i18n/api/mr.json
new file mode 100644
index 00000000..e9ba7463
--- /dev/null
+++ b/CheckUser/i18n/api/mr.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie",
+ "V.narsikar"
+ ]
+ },
+ "apihelp-query+checkuser-description": "दिलेले सदस्यनाव कोणते अंकपत्ते वापरते किंवा दिलेल्या अंकपत्त्याद्वारे कोणती सदस्यनावे वापरल्या जातात ते तपासा.",
+ "apihelp-query+checkuser-param-target": "तपासावयाचे सदस्यनाव, अंकपत्ता किंवा सीआयडीआर रेंज.",
+ "apihelp-query+checkuser-param-reason": "तपासण्याचे कारण.",
+ "apihelp-query+checkuser-param-limit": "ओळींची मर्यादा.",
+ "apihelp-query+checkuser-param-timecond": "सदस्यडाटाची काल मर्यादा(जसे \"-2 weeks\" किंवा \"2 weeks ago\").",
+ "apihelp-query+checkuserlog-param-limit": "ओळींची मर्यादा."
+}
diff --git a/CheckUser/i18n/api/ms.json b/CheckUser/i18n/api/ms.json
new file mode 100644
index 00000000..86075362
--- /dev/null
+++ b/CheckUser/i18n/api/ms.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia"
+ ]
+ },
+ "apihelp-query+checkuser-param-target": "Nama pengguna, alamat IP atau 'CIDR range' untuk disemak.",
+ "apihelp-query+checkuser-param-xff": "Gunakan data XFF daripada alamat IP.",
+ "apihelp-query+checkuser-example-1": "Semak alamat IP untuk [[User:Example]]"
+}
diff --git a/CheckUser/i18n/api/nb.json b/CheckUser/i18n/api/nb.json
new file mode 100644
index 00000000..5d613225
--- /dev/null
+++ b/CheckUser/i18n/api/nb.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jon Harald Søby",
+ "McDutchie"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Sjekk hvilke IP-adresser som er brukt av et gitt brukernavn eller hvilke brukernavn som brukes av en gitt IP-adresse.",
+ "apihelp-query+checkuser-summary": "Sjekk hvilke IP-adresser som brukes av et gitt brukernavn eller hvilke brukernavn som brukes av ei gitt IP-adresse.",
+ "apihelp-query+checkuser-param-request": "Type IP-kontrollforespørsel:\n;userips:Hent IP-adresse for målbrukeren.\n;edits:Hent endringer fra mål-IP-en.\n;ipusers:Hent brukere fra mål-IP-en.",
+ "apihelp-query+checkuser-param-target": "Brukernavn, IP-adresse eller CIDR-område å sjekke.",
+ "apihelp-query+checkuser-param-reason": "Årsak for kontrollen.",
+ "apihelp-query+checkuser-param-limit": "Begrensning av rader.",
+ "apihelp-query+checkuser-param-timecond": "Tidsgrense for brukerdata (som «-2 weeks» eller «2 weeks ago»).",
+ "apihelp-query+checkuser-param-xff": "Bruk XFF-data i stedet for IP-adresse.",
+ "apihelp-query+checkuser-example-1": "Sjekk IP-adresser for [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Sjekk redigeringer fra 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Hent oppføringer fra IP-kontroll-loggen.",
+ "apihelp-query+checkuserlog-summary": "Hent oppføringer fra IP-kontroll-loggen.",
+ "apihelp-query+checkuserlog-param-user": "Brukernavnet til IP-kontrolløren.",
+ "apihelp-query+checkuserlog-param-target": "Sjekket bruker, IP-adresse eller CIDR-område.",
+ "apihelp-query+checkuserlog-param-limit": "Begrensning av rader.",
+ "apihelp-query+checkuserlog-param-from": "Tidsstempelet det skal startes fra.",
+ "apihelp-query+checkuserlog-param-to": "Tidsstempelet det skal sluttes på.",
+ "apihelp-query+checkuserlog-example-1": "Vis sjekker av [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Vis sjekker av 192.0.2.0/24 etter 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Du må angi en årsak for sjekken.",
+ "apierror-checkuser-timelimit": "Du må bruke en korrekt tidsgrense (som «-2 weeks» eller «2 weeks ago»).",
+ "apierror-checkuser-invalidmode": "Ugyldig forespørselsmodus"
+}
diff --git a/CheckUser/i18n/api/ne.json b/CheckUser/i18n/api/ne.json
new file mode 100644
index 00000000..9141a50f
--- /dev/null
+++ b/CheckUser/i18n/api/ne.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "बिप्लब आनन्द"
+ ]
+ },
+ "apihelp-query+checkuser-param-reason": "जाँच्ने कारण।",
+ "apihelp-query+checkuser-param-limit": "पङ्क्तिहरूको सीमा।",
+ "apihelp-query+checkuserlog-param-user": "प्रयोगकर्ताजाँचको प्रयोगकर्ता नाम।",
+ "apihelp-query+checkuserlog-param-target": "प्रयोगकर्ता जाँच, आइपी ठेगाना, वा सिआइडिआर सीमा।",
+ "apihelp-query+checkuserlog-param-limit": "पङ्क्तिहरूको सीमा।"
+}
diff --git a/CheckUser/i18n/api/nl.json b/CheckUser/i18n/api/nl.json
new file mode 100644
index 00000000..a01c29dd
--- /dev/null
+++ b/CheckUser/i18n/api/nl.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mainframe98",
+ "Siebrand",
+ "Sjoerddebruin"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Controleer welke IP-adressen gebruikt worden door een opgegeven gebruikersnaam of welke gebruikersnamen worden gebruikt door een opgegeven IP-adres.",
+ "apihelp-query+checkuser-summary": "Controleer welke IP-adressen gebruikt worden door een opgegeven gebruikersnaam of welke gebruikersnamen worden gebruikt door een opgegeven IP-adres.",
+ "apihelp-query+checkuser-param-request": "Type van het CheckUserverzoek:\n;userips:IP-adres van de doelgebruiker ophalen.\n;edits:Wijzigingen van IP-adres of IP-adresreeks ophalen.\n;ipusers:Gebruikers van IP-adres of IP-adresreeks ophalen.",
+ "apihelp-query+checkuser-param-target": "Gebruikersnaam, IP-adres, of te controleren CIDR-range.",
+ "apihelp-query+checkuser-param-reason": "Reden voor controleren.",
+ "apihelp-query+checkuser-param-limit": "Limiet voor rijen.",
+ "apihelp-query+checkuser-param-timecond": "Tijdslimiet voor gebruikersgegevens, bijvoorbeeld \"-2 weeks\" of \"2 weeks ago\".",
+ "apihelp-query+checkuser-param-xff": "XFF-gegevens gebruiken in plaats van IP-adres.",
+ "apihelp-query+checkuser-example-1": "IP-adressen controleren voor [[User:Example]].",
+ "apihelp-query+checkuser-example-2": "Bewerkingen controleren voor 192.0.2.0/24.",
+ "apihelp-query+checkuserlog-description": "Regels uit het CheckUserlogboek ophalen.",
+ "apihelp-query+checkuserlog-summary": "Regels uit het CheckUserlogboek ophalen.",
+ "apihelp-query+checkuserlog-param-user": "Naam van de gebruiker met CheckUserrechten.",
+ "apihelp-query+checkuserlog-param-target": "Gebruiker, IP-adres of CIDR-range gecontroleerd.",
+ "apihelp-query+checkuserlog-param-limit": "Limiet voor rijen.",
+ "apihelp-query+checkuserlog-param-from": "Het tijdstip waar de opsomming begint.",
+ "apihelp-query+checkuserlog-param-to": "Het tijdstip waar de opsomming eindigt.",
+ "apihelp-query+checkuserlog-example-1": "Controles van [[User:Example]] weergeven.",
+ "apihelp-query+checkuserlog-example-2": "Controles van 192.0.2.0/24 na 2011-10-15T23:00:00Z weergeven.",
+ "apierror-checkuser-missingsummary": "U moet een reden opgeven voor deze controle.",
+ "apierror-checkuser-timelimit": "U moet een juiste tijdsbeperking invoeren (zoals \"-2 weeks\" of \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Ongeldige aanvraagsmodus"
+}
diff --git a/CheckUser/i18n/api/pl.json b/CheckUser/i18n/api/pl.json
new file mode 100644
index 00000000..c1b6f3db
--- /dev/null
+++ b/CheckUser/i18n/api/pl.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chrumps",
+ "Rail",
+ "Railfail536",
+ "Saper",
+ "Woytecr"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Umożliwia sprawdzenie, z których adresów IP edytował zadany użytkownik lub odnalezienie nazw użytkowników korzystających z zadanego adresu IP.",
+ "apihelp-query+checkuser-summary": "Umożliwia sprawdzenie, z których adresów IP edytował zadany użytkownik lub odnalezienie nazw użytkowników korzystających z zadanego adresu IP.",
+ "apihelp-query+checkuser-param-request": "Rodzaj zapytania checkuser:\n;userips: Pobierz adresy IP zadanego użytkownika\n;edits: Pobierz edycje z zadanego adresu IP lub ich zakresu\n;ipusers: Pobierz nazwy użytkowników dla zadanego adresu IP lub ich zakresu",
+ "apihelp-query+checkuser-param-target": "Nazwa użytkownika, adres IP lub zakres CIDR do sprawdzenia.",
+ "apihelp-query+checkuser-param-reason": "Powód dla sprawdzenia",
+ "apihelp-query+checkuser-param-limit": "Limit liczby zwróconych wierszy",
+ "apihelp-query+checkuser-param-timecond": "Przedział czasowy dla pobieranych danych (np. \"-2 weeks\" lub \"2 weeks ago\" dla ostatnich dwóch tygodni)",
+ "apihelp-query+checkuser-param-xff": "Sprawdź nagłówki XFF zamiast rzeczywistego adresu IP",
+ "apihelp-query+checkuser-example-1": "Sprawdź adresy IP dla [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Pobierz edycje dla zakresu 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Pobierz wypisy w rejestrze zapytań checkuser.",
+ "apihelp-query+checkuserlog-summary": "Pobierz wypisy w rejestrze zapytań checkuser.",
+ "apihelp-query+checkuserlog-param-user": "Nazwa użytkownika sprawdzającego (checkusera)",
+ "apihelp-query+checkuserlog-param-target": "Nazwa użytkownika sprawdzanego, adres IP lub ich zakres.",
+ "apihelp-query+checkuserlog-param-limit": "Limit liczby zwracanych wierszy.",
+ "apihelp-query+checkuserlog-param-from": "Znacznik czasu dla najstarszych zwracanych wpisów",
+ "apihelp-query+checkuserlog-param-to": "Znacznik czasu, na którym zakończyć wpisywanie danych z rejestru",
+ "apihelp-query+checkuserlog-example-1": "Pokaż, co sprawdzał [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Pokaż, kto sprawdzał zakres adresów 192.0.2.0/24 po 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Musisz podać powód sprawdzenia",
+ "apierror-checkuser-timelimit": "Musisz użyć poprawnego limitu czasu (np. „-2 tygodnie” lub „2 tygodnie temu”).",
+ "apierror-checkuser-invalidmode": "Nieprawidłowy tryb żądania"
+}
diff --git a/CheckUser/i18n/api/pt-br.json b/CheckUser/i18n/api/pt-br.json
new file mode 100644
index 00000000..e55956e3
--- /dev/null
+++ b/CheckUser/i18n/api/pt-br.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Araceletorres",
+ "Felipe L. Ewald",
+ "Macofe"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Verifique quais endereços IP são utilizados por um determinado nome de usuário ou quais nomes de usuários são utilizados por um determinado endereço IP.",
+ "apihelp-query+checkuser-summary": "Verifique quais endereços IP são utilizados por um determinado nome de usuário ou quais nomes de usuários são utilizados por um determinado endereço IP.",
+ "apihelp-query+checkuser-param-request": "Tipo de pedido CheckUser:\n;userips:Obter endereço IP do usuário-alvo.\n;edits:Obter alterações de endereço IP de destino ou intervalo.\n;ipusers:Obter usuários de endereço IP de destino ou intervalo.",
+ "apihelp-query+checkuser-param-target": "Nome de usuário, endereço IP ou intervalo CIDR para verificar.",
+ "apihelp-query+checkuser-param-reason": "Motivo para verificar.",
+ "apihelp-query+checkuser-param-limit": "Limite de linhas.",
+ "apihelp-query+checkuser-param-timecond": "Limite de tempo dos dados do usuário (como \"-2 weeks\" ou \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Usar dados XFF no lugar do endereço IP.",
+ "apihelp-query+checkuser-example-1": "Verificar endereço IP para [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Verificar edições de 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Obter entradas do registro do CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Obter entradas do registro do CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Nome de usuário do CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Usuário verificado, endereço IP ou intervalo CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "Limite de linhas.",
+ "apihelp-query+checkuserlog-param-from": "O timestamp para começar a enumeração.",
+ "apihelp-query+checkuserlog-param-to": "O selo do tempo para finalizar a enumeração.",
+ "apihelp-query+checkuserlog-example-1": "Mostrar verificações de [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Mostrar verificações de 192.0.2.0/24 após 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Você deve definir o motivo da verificação.",
+ "apierror-checkuser-timelimit": "Você precisa usar o limite de tempo correto (como \"-2 semanas\" ou \"2 semanas atrás\").",
+ "apierror-checkuser-invalidmode": "Modo de solicitação inválido"
+}
diff --git a/CheckUser/i18n/api/pt.json b/CheckUser/i18n/api/pt.json
new file mode 100644
index 00000000..b687a994
--- /dev/null
+++ b/CheckUser/i18n/api/pt.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hamilton Abreu"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Verificar que endereços IP são usados por determinado nome de utilizador ou que nomes de utilizador são usados por um determinado endereço IP.",
+ "apihelp-query+checkuser-summary": "Verificar que endereços IP são usados por determinado nome de utilizador ou que nomes de utilizador são usados por um determinado endereço IP.",
+ "apihelp-query+checkuser-param-request": "Tipo do pedido de verificação de utilizadores:\n;userips:Obter endereço IP do utilizador alvo.\n;edits:Obter alterações do endereço IP ou gama IP alvo.\n;ipusers:Obter utilizadores do endereço IP ou gama IP alvo.",
+ "apihelp-query+checkuser-param-target": "Nome de utilizador, endereço IP, ou gama CIDR a verificar",
+ "apihelp-query+checkuser-param-reason": "Motivo da verificação.",
+ "apihelp-query+checkuser-param-limit": "Limite de linhas.",
+ "apihelp-query+checkuser-param-timecond": "Limite temporal dos dados de utilizador (como \"-2 weeks\" ou \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Usar dados XFF em vez do endereço IP.",
+ "apihelp-query+checkuser-example-1": "Verificar o endereço IP de [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Verificar edições de 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Obter entradas do registo de verificação de utilizadores.",
+ "apihelp-query+checkuserlog-summary": "Obter entradas do registo de verificação de utilizadores.",
+ "apihelp-query+checkuserlog-param-user": "Nome de utilizador do pedido de verificação de utilizadores.",
+ "apihelp-query+checkuserlog-param-target": "Utilizador verificado, endereço IP ou gama CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "Limite de linhas.",
+ "apihelp-query+checkuserlog-param-from": "A data e hora a partir da qual será começada a enumeração.",
+ "apihelp-query+checkuserlog-param-to": "A data e hora na qual será parada a enumeração.",
+ "apihelp-query+checkuserlog-example-1": "Mostrar verificações de [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Mostrar verificações de 192.0.2.0/24 após 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Tem de definir um motivo para a verificação.",
+ "apierror-checkuser-timelimit": "Tem de usar um limite temporal correto (como \"-2 weeks\" ou \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Modo de pedido inválido"
+}
diff --git a/CheckUser/i18n/api/qqq.json b/CheckUser/i18n/api/qqq.json
new file mode 100644
index 00000000..e0f98b27
--- /dev/null
+++ b/CheckUser/i18n/api/qqq.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "Liuxinyu970226",
+ "Siebrand",
+ "Umherirrender",
+ "Zoranzoki21"
+ ]
+ },
+ "apihelp-query+checkuser-description": "{{doc-apihelp-description|query+checkuser}}",
+ "apihelp-query+checkuser-summary": "{{doc-apihelp-summary|query+checkuser}}",
+ "apihelp-query+checkuser-param-request": "{{doc-apihelp-param|query+checkuser|request}}",
+ "apihelp-query+checkuser-param-target": "{{doc-apihelp-param|query+checkuser|target}}",
+ "apihelp-query+checkuser-param-reason": "{{doc-apihelp-param|query+checkuser|reason}}",
+ "apihelp-query+checkuser-param-limit": "{{doc-apihelp-param|query+checkuser|limit}}",
+ "apihelp-query+checkuser-param-timecond": "{{doc-important|Do not translate \"-2 weeks\" or \"2 weeks ago\". It must be in [http://www.php.net/strtotime original format].}}\n----\n{{doc-apihelp-param|query+checkuser|timecond}}",
+ "apihelp-query+checkuser-param-xff": "{{doc-apihelp-param|query+checkuser|xff}}",
+ "apihelp-query+checkuser-example-1": "{{doc-apihelp-example|query+checkuser}}",
+ "apihelp-query+checkuser-example-2": "{{doc-apihelp-example|query+checkuser}}",
+ "apihelp-query+checkuserlog-description": "{{doc-apihelp-description|query+checkuserlog}}",
+ "apihelp-query+checkuserlog-summary": "{{doc-apihelp-summary|query+checkuserlog}}",
+ "apihelp-query+checkuserlog-param-user": "{{doc-apihelp-param|query+checkuserlog|user}}",
+ "apihelp-query+checkuserlog-param-target": "{{doc-apihelp-param|query+checkuserlog|target}}",
+ "apihelp-query+checkuserlog-param-limit": "{{doc-apihelp-param|query+checkuserlog|limit}}",
+ "apihelp-query+checkuserlog-param-from": "{{doc-apihelp-param|query+checkuserlog|from}}",
+ "apihelp-query+checkuserlog-param-to": "{{doc-apihelp-param|query+checkuserlog|to}}",
+ "apihelp-query+checkuserlog-example-1": "{{doc-important|Do not translate \"User:Example\".}}\n{{doc-apihelp-example|query+checkuserlog}}",
+ "apihelp-query+checkuserlog-example-2": "{{doc-apihelp-example|query+checkuserlog}}",
+ "apierror-checkuser-missingsummary": "{{doc-apierror}}",
+ "apierror-checkuser-timelimit": "{{doc-apierror}}\n{{doc-important|Do not translate \"-2 weeks\" or \"2 weeks ago\". It must be in [http://www.php.net/strtotime original format].}}",
+ "apierror-checkuser-invalidmode": "{{doc-apierror}}"
+}
diff --git a/CheckUser/i18n/api/roa-tara.json b/CheckUser/i18n/api/roa-tara.json
new file mode 100644
index 00000000..de2754cc
--- /dev/null
+++ b/CheckUser/i18n/api/roa-tara.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Verifiche quale IP so ausate da 'nu certe nome utende o quale nome de utinde so ausate da 'nu certe IP.",
+ "apihelp-query+checkuser-summary": "Verifiche quale IP so ausate da 'nu certe nome utende o quale nome de utinde so ausate da 'nu certe IP.",
+ "apihelp-query+checkuser-param-request": "Tipe de richieste de CheckUser:\n;userips:Pigghie l'indirizze IP de l'utende de destinazione.\n;edits:Pigghie le cangiaminde da l'indirizze IP de destinazione o de l'indervalle.\n;ipusers:Pigghie le utinde da l'indirizze IP de destinazione o de l'indervalle..",
+ "apihelp-query+checkuser-param-target": "Nome de l'utende, indirizze IP o indervalle CIDR da verificà.",
+ "apihelp-query+checkuser-param-reason": "Mutive d'u condrolle.",
+ "apihelp-query+checkuser-param-limit": "Limite de righe.",
+ "apihelp-query+checkuser-param-timecond": "Tiembe limite de le date utende (cumme \"2 sumàne\" o \"2 sumàne fa\").",
+ "apihelp-query+checkuser-param-xff": "Ause date XFF invece de l'indirizze IP.",
+ "apihelp-query+checkuser-example-1": "Verifiche l'indirizze IP pe [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Verifiche le cangiaminde da 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Pigghie le vôsce da l'archivije CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Pigghie le v147sce de l'archivije d'u CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Nome de l'utende de CheckUser.",
+ "apihelp-query+checkuserlog-param-target": "Utende condrollate, indirizze IP o indervalle CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "Limite de righe.",
+ "apihelp-query+checkuserlog-param-from": "Orarie da addò accumenze l'enumerazione.",
+ "apihelp-query+checkuserlog-param-to": "Orarie da addò spicce l'enumerazione.",
+ "apihelp-query+checkuserlog-example-1": "Fà vedè le verifiche sus a [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Fà vedè le verifiche de 192.0.2.0/24 apprisse 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Tu ha dicere 'nu mutive de verifiche.",
+ "apierror-checkuser-timelimit": "Tu è abbesogne de ausà 'u limite de tiembe corrette (cumme \"-2 sumàne\" o \"2 sumàne rrete\").",
+ "apierror-checkuser-invalidmode": "Mode de richieste invalide"
+}
diff --git a/CheckUser/i18n/api/ru.json b/CheckUser/i18n/api/ru.json
new file mode 100644
index 00000000..4ea17fa3
--- /dev/null
+++ b/CheckUser/i18n/api/ru.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "Facenapalm",
+ "Mailman",
+ "Okras",
+ "Putnik"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Проверить, какие IP-адреса используются данным именем участника или какие имена участников используются заданным IP-адресом.",
+ "apihelp-query+checkuser-summary": "Проверить, какие IP-адреса используются данным именем участника или какие имена участников используются заданным IP-адресом.",
+ "apihelp-query+checkuser-param-request": "Тип запроса чекюзера:\n;userips:Получить IP-адрес целевого пользователя.\n; edits:Получить изменения, сделанные с целевого IP-адреса или диапазона адресов.\n;ipusers:Получить пользователей по целевому IP-адресу или диапазону.",
+ "apihelp-query+checkuser-param-target": "Имя участника, IP-адрес или CIDR-диапазон для проверки.",
+ "apihelp-query+checkuser-param-reason": "Причина проверки.",
+ "apihelp-query+checkuser-param-limit": "Ограничение количества строк.",
+ "apihelp-query+checkuser-param-timecond": "Ограничение по времени для данных об участнике (например, «-2 weeks» или «2 weeks ago»).",
+ "apihelp-query+checkuser-param-xff": "Использовать XFF-данные вместо IP-адреса.",
+ "apihelp-query+checkuser-example-1": "Проверить IP-адреса [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Проверить правки с 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Получить записи из журнала проверки участников (CheckUser).",
+ "apihelp-query+checkuserlog-summary": "Получить записи из журнала проверки участников.",
+ "apihelp-query+checkuserlog-param-user": "Имя пользователя чекюзера.",
+ "apihelp-query+checkuserlog-param-target": "Проверенный участник, IP-адрес или CIDR-диапазон.",
+ "apihelp-query+checkuserlog-param-limit": "Ограничение количества строк.",
+ "apihelp-query+checkuserlog-param-from": "Метка времени, с которого нужно начинать перечисление.",
+ "apihelp-query+checkuserlog-param-to": "Метка времени, до которого делать перечисление.",
+ "apihelp-query+checkuserlog-example-1": "Показать проверки [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Показать проверки 192.0.2.0/24 начиная с 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Вы должны указать причину для проверки.",
+ "apierror-checkuser-timelimit": "Вам необходимо использовать правильное ограничение по времени (например, «-2 weeks» или «2 weeks ago»).",
+ "apierror-checkuser-invalidmode": "Недопустимый режим запроса"
+}
diff --git a/CheckUser/i18n/api/scn.json b/CheckUser/i18n/api/scn.json
new file mode 100644
index 00000000..3b065279
--- /dev/null
+++ b/CheckUser/i18n/api/scn.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pippinu",
+ "Sarvaturi"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Cuntrolla quali nnirizzi IP sunnu adupirati dûn nomu utenti datu, o quali nomi utenti sunnu adupirati di nu nnirizzu IP datu.",
+ "apihelp-query+checkuser-param-request": "Sorta d'addumannata dû CheckUser:\n;userips:Pigghia lu nnirizzu IP di l'utenti.\n;edits:Pigghia li canciamenti dû nnirizzu IP o dû ntirvallu di nnirizzi IP.\n;ipusers:Pigghia l'utenti dû nnirizzu IP o dû ntirvallu di nnirizzi IP.",
+ "apihelp-query+checkuser-param-target": "Nomu utenti, nnirizzu IP, o ntirvallu CIDR di cuntrullari.",
+ "apihelp-query+checkuser-param-reason": "Mutivu dû cuntrollu.",
+ "apihelp-query+checkuser-param-limit": "Lìmiti di ringhi.",
+ "apihelp-query+checkuser-param-timecond": "Lìmiti di tempu pî dati di l’utenti (comu \"2 weeks\").",
+ "apihelp-query+checkuser-param-xff": "Adòpira lu datu XFF mmeci dû nnirizzu IP.",
+ "apihelp-query+checkuser-example-1": "Cuntrolla li nnirizzi IP di [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Cuntrolla li canciamenti ca vèninu di 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Pigghia li vuci dû riggistru dû CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Nomu utenti dû cuntrulluri.",
+ "apihelp-query+checkuserlog-param-target": "Utenti, nnirizzu IP, o ntirvallu CIDR cuntrullatu.",
+ "apihelp-query+checkuserlog-param-limit": "Lìmiti di ringhi.",
+ "apihelp-query+checkuserlog-param-from": "La data e l'ura di quannu si voli accuminzari l'enumirazzioni.",
+ "apihelp-query+checkuserlog-param-to": "La data e l'ura di quannu si voli cunchiùdiri l'enumirazzioni.",
+ "apihelp-query+checkuserlog-example-1": "Ammustra li cuntrolli fatti di [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Ammustra li cuntrolli fatti di 192.0.2.0/24 appressu dû 2011-10-15T23:00:00Z"
+}
diff --git a/CheckUser/i18n/api/sd.json b/CheckUser/i18n/api/sd.json
new file mode 100644
index 00000000..01d81b33
--- /dev/null
+++ b/CheckUser/i18n/api/sd.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mehtab ahmed"
+ ]
+ },
+ "apihelp-query+checkuser-example-2": "192.0.2.0/24 پاران سنوارون چڪاسيو"
+}
diff --git a/CheckUser/i18n/api/sh.json b/CheckUser/i18n/api/sh.json
new file mode 100644
index 00000000..6059c6f8
--- /dev/null
+++ b/CheckUser/i18n/api/sh.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Vlad5250"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Provjeri koje IP adrese ih koriste dano korisničko ime ili pak koja korisnička imena ih koriste danu IP adresu.",
+ "apihelp-query+checkuser-summary": "Provjeri koje IP adrese ih koriste dano korisničko ime ili pak koja korisnička imena ih koriste danu IP adresu.",
+ "apihelp-query+checkuser-param-request": "Tip zahtjeva s CheckUser-om:\n;userips: Daj IP adresu ciljanom korisniku.\n;edits: Daj promjene iz ciljne IP adrese ili opsega.\n;ipusers: Daj korisnike iz ciljne IP adrese ili opsega.",
+ "apihelp-query+checkuser-param-target": "Korisničko ime, IP adresa ili CIDR opseg za provjeru.",
+ "apihelp-query+checkuser-param-reason": "Razlog provjere.",
+ "apihelp-query+checkuser-param-limit": "Ograničenje redova.",
+ "apihelp-query+checkuser-param-timecond": "Vremensko ograničenje za korisničke podatke (npr, \"-2 weeks\" ili \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Koristi XFF podatke umjesto IP adrese.",
+ "apihelp-query+checkuser-example-1": "Provjeri [[User:Example]] za IP adrese",
+ "apihelp-query+checkuser-example-2": "Provjeri izmjene iz 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Daj stavke iz zapisnika CheckUser.",
+ "apihelp-query+checkuserlog-summary": "Daj stavke iz zapisnika CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Korisničko ime provjeritelja (CheckUser).",
+ "apihelp-query+checkuserlog-param-target": "Provjereni korisnik, IP adresa ili CIDR opseg.",
+ "apihelp-query+checkuserlog-param-limit": "Ograničenje redova.",
+ "apihelp-query+checkuserlog-param-from": "Od kojeg datuma i vremena počinje brojanje.",
+ "apihelp-query+checkuserlog-param-to": "Na koji datum i vrijeme zaustaviti brojanje.",
+ "apihelp-query+checkuserlog-example-1": "Prikaži provjere za [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Prikaži provjere 192.0.2.0/24 nakon 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Morate navesti razlog za provjeru.",
+ "apierror-checkuser-timelimit": "Morat ćete upotrijebiti ispravno vremensko ograničenje (npr, \"-2 weeks\" ili \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Nevažeći način upita"
+}
diff --git a/CheckUser/i18n/api/sl.json b/CheckUser/i18n/api/sl.json
new file mode 100644
index 00000000..75eb5f4d
--- /dev/null
+++ b/CheckUser/i18n/api/sl.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Janezdrilc"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Preveri, katere IP naslove uporablja navedeni uporabnik ali katera uporabniška imena uporablja navedeni IP naslov.",
+ "apihelp-query+checkuser-summary": "Preveri, katere IP naslove uporablja navedeni uporabnik ali katera uporabniška imena uporablja navedeni IP naslov.",
+ "apihelp-query+checkuser-param-request": "Vrsta prošnje za preverjanje uporabnika:\n;userips:Prikaži IP naslov ciljnega uporabnika.\n;edits:Prikaži spremembe ciljnega IP naslova ali razpona IP-jev.\n;ipusers:Prikaži uporabnike ciljnega IP naslova ali razpona IP-jev.",
+ "apihelp-query+checkuser-param-target": "Uporabniško ime, IP naslov ali razpon CIDR za preverbo.",
+ "apihelp-query+checkuser-param-reason": "Razlog preverbe.",
+ "apihelp-query+checkuser-param-limit": "Omejitev vrstic.",
+ "apihelp-query+checkuser-param-timecond": "Časovna omejitev uporabniških podatkov (na primer \"-2 tedna\" ali \"2 tedna nazaj\").",
+ "apihelp-query+checkuser-param-xff": "Uporabi podatke XFF namesto IP naslova.",
+ "apihelp-query+checkuser-example-1": "Preveri IP naslove za [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Preveri urejanja od 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Prikaži vpise iz dnevnika preverjanj uporabnikov.",
+ "apihelp-query+checkuserlog-summary": "Prikaži vpise iz dnevnika preverjanj uporabnikov.",
+ "apihelp-query+checkuserlog-param-user": "Uporabniško ime preverjevalca uporabnikov.",
+ "apihelp-query+checkuserlog-param-target": "Uporabniško ime, IP naslov ali razpon CIDR.",
+ "apihelp-query+checkuserlog-param-limit": "Omejitev vrstic.",
+ "apihelp-query+checkuserlog-param-from": "Datum začetka izpisa.",
+ "apihelp-query+checkuserlog-param-to": "Datum konca izpisa.",
+ "apihelp-query+checkuserlog-example-1": "Prikaži preverjanja za [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Prikaži preverjanja za 192.0.2.0/24 po 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Potrebno je navesti razlog za preverjanje.",
+ "apierror-checkuser-timelimit": "Potrebno je uporabiti pravilno časovno omejitev (na primer \"-2 tedna\" ali \"2 tedna nazaj\").",
+ "apierror-checkuser-invalidmode": "Neveljaven način zaprositve"
+}
diff --git a/CheckUser/i18n/api/sv.json b/CheckUser/i18n/api/sv.json
new file mode 100644
index 00000000..dda2c461
--- /dev/null
+++ b/CheckUser/i18n/api/sv.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jenniesarina",
+ "Lokal Profil",
+ "McDutchie",
+ "WikiPhoenix"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Kontrollera vilka IP-adresser som används av ett visst användarnamn eller vilka användarnamn som används av en viss IP-adress.",
+ "apihelp-query+checkuser-summary": "Kontrollera vilka IP-adresser som används av ett angivet användarnamn eller vilka användarnamn som används av en angiven IP-adress.",
+ "apihelp-query+checkuser-param-request": "Typ av CheckUser begäran:\n;userips:Få IP-adresser för målanvändaren.\n;edits:Få ändringar från mål-IP-adresser eller -intervall.\n;ipusers:Få användare från mål-IP-adresser eller -intervall.",
+ "apihelp-query+checkuser-param-target": "Användarnamn, IP-adress eller CIDR-intervall att kontrollera.",
+ "apihelp-query+checkuser-param-reason": "Skäl att kontrollera.",
+ "apihelp-query+checkuser-param-limit": "Begränsning av rader.",
+ "apihelp-query+checkuser-param-timecond": "Tidsgräns för användardata (som \"-2 weeks\" eller \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Använd XFF data istället för IP-adress.",
+ "apihelp-query+checkuser-example-1": "Kontrollera IP-adresser för [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Kontrollera redigeringar från 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Få poster från CheckUser-loggen.",
+ "apihelp-query+checkuserlog-summary": "Hämta poster från loggen över användarkontroller.",
+ "apihelp-query+checkuserlog-param-user": "Användarnamn för CheckUsern.",
+ "apihelp-query+checkuserlog-param-target": "Kontrollerad användare, IP-adress, eller CIDR-intervall.",
+ "apihelp-query+checkuserlog-param-limit": "Begränsning av rader.",
+ "apihelp-query+checkuserlog-param-from": "Tidsstämpel att börja räkna upp från.",
+ "apihelp-query+checkuserlog-param-to": "Tidsstämpeln att räkna upp till.",
+ "apihelp-query+checkuserlog-example-1": "Visa kontroller av [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Visa kontroller av 192.0.2.0/24 efter 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Du måste ange en anledning till att utföra kontrollen.",
+ "apierror-checkuser-timelimit": "Du måste använda rätt tidsgräns (t.ex. \"-2 weeks\" eller \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Ogiltigt frågeläge"
+}
diff --git a/CheckUser/i18n/api/th.json b/CheckUser/i18n/api/th.json
new file mode 100644
index 00000000..2963525d
--- /dev/null
+++ b/CheckUser/i18n/api/th.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aefgh39622"
+ ]
+ },
+ "apihelp-query+checkuserlog-description": "รับหน่วยจากรายการบันทึกการตรวจสอบผู้ใช้"
+}
diff --git a/CheckUser/i18n/api/tr.json b/CheckUser/i18n/api/tr.json
new file mode 100644
index 00000000..72bd50d0
--- /dev/null
+++ b/CheckUser/i18n/api/tr.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "BaRaN6161 TURK",
+ "Hedda",
+ "McDutchie",
+ "Sadrettin",
+ "Ömer Berkay"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Belirli bir kullanıcı adı tarafından hangi IP adreslerinin kullanıldığını veya kullanıcı adlarının belirli bir IP adresi tarafından kullanıldığını kontrol edin.",
+ "apihelp-query+checkuser-summary": "Belirli bir kullanıcı adı tarafından hangi IP adreslerinin kullanıldığını veya kullanıcı adlarının belirli bir IP adresi tarafından kullanıldığını kontrol edin.",
+ "apihelp-query+checkuser-param-request": "Denetçi isteğinin türü:\n;userips:Hedef kullanıcının IP adreslerini alın.\n;edits:Hedef IP adresleri veya IP aralığındaki değişiklikleri alın.\nipusers:Hedef IP adresleri veya IP aralığındaki kullanıcıları alın.",
+ "apihelp-query+checkuser-param-target": "Kullanıcı adı, IP adresi veya CIDR aralığını kontrol edin.",
+ "apihelp-query+checkuser-param-reason": "Kontrol nedeni.",
+ "apihelp-query+checkuser-param-limit": "Satır sınırı.",
+ "apihelp-query+checkuser-param-timecond": "Kullanıcı verilerinin zaman sınırı (\"-2 weeks\" veya \"2 weeks ago\" gibi).",
+ "apihelp-query+checkuser-param-xff": "IP adresi yerine XFF veri kullanın.",
+ "apihelp-query+checkuser-example-1": "[[User:Example]] için IP adreslerini kontrol edin",
+ "apihelp-query+checkuser-example-2": "192.0.2.0/24 tarafından yapılan değişiklikleri kontrol edin",
+ "apihelp-query+checkuserlog-description": "Denetçi günlüğünden girdileri alın.",
+ "apihelp-query+checkuserlog-summary": "Denetçi günlüğünden girdileri alın.",
+ "apihelp-query+checkuserlog-param-user": "Denetçi olan kullanıcı adları.",
+ "apihelp-query+checkuserlog-param-target": "Kontrol edilen IP adresleri veya CIDR aralığı.",
+ "apihelp-query+checkuserlog-param-limit": "Satır sınırı.",
+ "apihelp-query+checkuserlog-param-from": "Numaralandırmaya başlamak için zaman damgası.",
+ "apihelp-query+checkuserlog-param-to": "Numaralandırmayı sonlandırmak için zaman bilgisi.",
+ "apihelp-query+checkuserlog-example-1": "[[User:Example]] için yapılan kontrolleri göster",
+ "apihelp-query+checkuserlog-example-2": "2011-10-15T23:00:00Z tarihinden sonraki 192.0.2.0/24 kontrollerini göster",
+ "apierror-checkuser-missingsummary": "Kontrol için neden tanımlamanız gerekir.",
+ "apierror-checkuser-timelimit": "Doğru zaman sınırını kullanmanız gerekiyor (\"-2 weeks\" veya \"2 weeks ago\" gibi)",
+ "apierror-checkuser-invalidmode": "Geçersiz istek modu"
+}
diff --git a/CheckUser/i18n/api/uk.json b/CheckUser/i18n/api/uk.json
new file mode 100644
index 00000000..95270a8f
--- /dev/null
+++ b/CheckUser/i18n/api/uk.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Alex Khimich",
+ "Base",
+ "Piramidion"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Перевірка того, які IP-адреси використовуються даним іменем користувача, або які імена користувачів використовуються даною IP-адресою.",
+ "apihelp-query+checkuser-summary": "Перевірка того, які IP-адреси використовуються даним іменем користувача, або які імена користувачів використовуються даною IP-адресою.",
+ "apihelp-query+checkuser-param-request": "Тип запиту перевірки користувача:\n;userips:Отримати IP-адреси цільового користувача.\n;edits:Отримати зміни з цільової IP-адреси або діапазону.\n;ipusers:Отримати користувачів з цільової IP-адреси або діапазону.",
+ "apihelp-query+checkuser-param-target": "Ім'я користувача, IP-адреса, або CIDR-діапазон для перевірки.",
+ "apihelp-query+checkuser-param-reason": "Причина перевірки.",
+ "apihelp-query+checkuser-param-limit": "Обмеження рядків.",
+ "apihelp-query+checkuser-param-timecond": "Обмеження часу для даних користувача (як то \"-2 weeks\" чи \"2 weeks ago\").",
+ "apihelp-query+checkuser-param-xff": "Використовуйте XFF-дані замість IP-адреси.",
+ "apihelp-query+checkuser-example-1": "Перевірити IP-адреси для [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Перевірити редагування з 192.0.2.0/24",
+ "apihelp-query+checkuserlog-description": "Отримати записи з журналу перевірки користувачів.",
+ "apihelp-query+checkuserlog-summary": "Отримати записи з журналу перевірки користувачів.",
+ "apihelp-query+checkuserlog-param-user": "Ім'я користувача перевіряльника користувачів.",
+ "apihelp-query+checkuserlog-param-target": "Перевірений користувач, IP-адреса чи CIDR-діапазон.",
+ "apihelp-query+checkuserlog-param-limit": "Обмеження рядків.",
+ "apihelp-query+checkuserlog-param-from": "Часова мітка початку переліку.",
+ "apihelp-query+checkuserlog-param-to": "Часова мітка завершення переліку.",
+ "apihelp-query+checkuserlog-example-1": "Показати перевірки [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Показати перевірки 192.0.2.0/24 після 2011-10-15T23:00:00Z",
+ "apierror-checkuser-missingsummary": "Вам необхідно зазначити причину для перевірки.",
+ "apierror-checkuser-timelimit": "Вам необхідно використовувати правильне обмеження за часом (наприклад, \"-2 weeks\" або \"2 weeks ago\").",
+ "apierror-checkuser-invalidmode": "Неправильний параметр запиту"
+}
diff --git a/CheckUser/i18n/api/vi.json b/CheckUser/i18n/api/vi.json
new file mode 100644
index 00000000..ad441a2d
--- /dev/null
+++ b/CheckUser/i18n/api/vi.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen"
+ ]
+ },
+ "apihelp-query+checkuser-description": "Kiểm tra địa chỉ IP nào được sử dụng bởi một tên người dùng nào đó hoặc tên người dùng nào được sử dụng bởi một địa chỉ IP nào đó.",
+ "apihelp-query+checkuser-param-request": "Kiểu yêu cầu CheckUser:\n;userips:Lấy địa chỉ IP của người dùng mục tiêu.\n;edits:Lấy các thay đổi do địa chỉ hoặc dãy IP mục tiêu thực hiện.\n;ipusers:Lấy những người dùng theo địa chỉ hoặc dãy IP.",
+ "apihelp-query+checkuser-param-target": "Tên người dùng, địa chỉ IP, hoặc dãy CIDR để kiểm tra.",
+ "apihelp-query+checkuser-param-reason": "Lý do kiểm tra.",
+ "apihelp-query+checkuser-param-limit": "Số hàng tối đa.",
+ "apihelp-query+checkuser-param-timecond": "Giới hạn thời gian của dữ liệu người dùng (ví dụ “-2 weeks” hoặc “2 weeks ago”).",
+ "apihelp-query+checkuser-param-xff": "Sử dụng dữ liệu XFF thay vì địa chỉ IP.",
+ "apihelp-query+checkuser-example-1": "Kiểm tra địa chỉ IP của [[User:Example]]",
+ "apihelp-query+checkuser-example-2": "Kiểm tra các sửa đổi do 192.0.2.0/24 thực hiện",
+ "apihelp-query+checkuserlog-description": "Lấy mục từ nhật trình CheckUser.",
+ "apihelp-query+checkuserlog-param-user": "Tên đăng nhập của kiểm định viên.",
+ "apihelp-query+checkuserlog-param-target": "Thành viên, địa chỉ IP, hoặc dãy CIDR để kiểm tra.",
+ "apihelp-query+checkuserlog-param-limit": "Số hàng tối đa.",
+ "apihelp-query+checkuserlog-param-from": "Dấu thời gian đầu tiên trong danh sách.",
+ "apihelp-query+checkuserlog-param-to": "Dấu thời gian cuối cùng trong danh sách.",
+ "apihelp-query+checkuserlog-example-1": "Xem các tác vụ kiểm tra [[User:Example]]",
+ "apihelp-query+checkuserlog-example-2": "Xem các tác vụ kiểm tra 192.0.2.0/24 sau 2011-10-15T23:00:00Z"
+}
diff --git a/CheckUser/i18n/api/zh-hans.json b/CheckUser/i18n/api/zh-hans.json
new file mode 100644
index 00000000..97d4a238
--- /dev/null
+++ b/CheckUser/i18n/api/zh-hans.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Liuxinyu970226",
+ "WhitePhosphorus",
+ "Yfdyh000"
+ ]
+ },
+ "apihelp-query+checkuser-description": "检查指定用户名使用的IP地址或指定IP地址使用过的用户名。",
+ "apihelp-query+checkuser-summary": "检查指定用户名使用过的IP地址或指定IP地址使用过的用户名。",
+ "apihelp-query+checkuser-param-request": "用户查核请求类型:\n;userips:获取目标用户的IP地址。\n;edits:获取目标IP地址或地址段的更改。\n;ipusers:获取目标IP地址或地址段的用户。",
+ "apihelp-query+checkuser-param-target": "要查核的用户名、IP地址或CIDR地址段。",
+ "apihelp-query+checkuser-param-reason": "查核原因。",
+ "apihelp-query+checkuser-param-limit": "限定行数。",
+ "apihelp-query+checkuser-param-timecond": "用户数据的限定(例如“-2 weeks”或“2 weeks ago”)。",
+ "apihelp-query+checkuser-param-xff": "使用XFF数据代替IP地址。",
+ "apihelp-query+checkuser-example-1": "查核[[User:Example]]的IP地址",
+ "apihelp-query+checkuser-example-2": "查核来自192.0.2.0/24的编辑",
+ "apihelp-query+checkuserlog-description": "从用户查核日志获得记录。",
+ "apihelp-query+checkuserlog-summary": "获取用户查核日志中的记录。",
+ "apihelp-query+checkuserlog-param-user": "用户查核员的用户名。",
+ "apihelp-query+checkuserlog-param-target": "已查核的用户、IP地址或CIDR地址段。",
+ "apihelp-query+checkuserlog-param-limit": "限定行数。",
+ "apihelp-query+checkuserlog-param-from": "枚举的起始时间戳。",
+ "apihelp-query+checkuserlog-param-to": "枚举的结束时间戳。",
+ "apihelp-query+checkuserlog-example-1": "显示[[User:Example]]的查核",
+ "apihelp-query+checkuserlog-example-2": "显示2011-10-15T23:00:00Z之后对192.0.2.0/24的查核",
+ "apierror-checkuser-missingsummary": "您必须定义查核原因。",
+ "apierror-checkuser-timelimit": "您需要使用正确的时间限制(例如“-2 weeks”或“2 weeks ago”)。",
+ "apierror-checkuser-invalidmode": "无效的请求模式"
+}
diff --git a/CheckUser/i18n/api/zh-hant.json b/CheckUser/i18n/api/zh-hant.json
new file mode 100644
index 00000000..bce3aac0
--- /dev/null
+++ b/CheckUser/i18n/api/zh-hant.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cwlin0416",
+ "Kly",
+ "LNDDYL",
+ "Liuxinyu970226",
+ "Waihorace"
+ ]
+ },
+ "apihelp-query+checkuser-description": "檢查指定使用者使用的 IP 地址或指定 IP 地址使用的使用者",
+ "apihelp-query+checkuser-summary": "檢查指定使用者使用的 IP 地址或指定 IP 地址使用的使用者",
+ "apihelp-query+checkuser-param-request": "使用者查核請求類型:\n;userips:取得目標使用者的 IP。\n;edits:取得目標 IP 或地址段所作的更改。\n;ipusers:取得目標 IP 或地址段的使用者。",
+ "apihelp-query+checkuser-param-target": "要查核的使用者名稱 IP 地址,或 CIDR 地址段。",
+ "apihelp-query+checkuser-param-reason": "查核原因。",
+ "apihelp-query+checkuser-param-limit": "行數限制。",
+ "apihelp-query+checkuser-param-timecond": "使用者資料的時限 (例如 \"-2 weeks\" 或 \"2 weeks ago\" ) 。",
+ "apihelp-query+checkuser-param-xff": "使用 XFF 資料代替 IP。",
+ "apihelp-query+checkuser-example-1": "查核[[User:Example]]的 IP",
+ "apihelp-query+checkuser-example-2": "查核來自 192.0.2.0/24 的編輯",
+ "apihelp-query+checkuserlog-description": "從使用者查核日誌獲得記錄。",
+ "apihelp-query+checkuserlog-summary": "從使用者查核日誌獲得記錄。",
+ "apihelp-query+checkuserlog-param-user": "使用者查核員的使用者名稱。",
+ "apihelp-query+checkuserlog-param-target": "已查核的使用者、IP 地址或 CIDR 地址段。",
+ "apihelp-query+checkuserlog-param-limit": "行數限制。",
+ "apihelp-query+checkuserlog-param-from": "起始列舉的時間戳記。",
+ "apihelp-query+checkuserlog-param-to": "結束列舉的時間戳記。",
+ "apihelp-query+checkuserlog-example-1": "顯示[[User:Example]]的查核",
+ "apihelp-query+checkuserlog-example-2": "顯示在 2011-10-15T23:00:00Z 之後的 192.0.2.0/24 檢查",
+ "apierror-checkuser-missingsummary": "您必須定義檢查的原因。",
+ "apierror-checkuser-timelimit": "您必須使用正確的時間限制(例如:「-2 weeks」或「2 weeks ago」)。",
+ "apierror-checkuser-invalidmode": "無效請求模式"
+}
diff --git a/CheckUser/i18n/ar.json b/CheckUser/i18n/ar.json
index 859cdccf..004a7a78 100644
--- a/CheckUser/i18n/ar.json
+++ b/CheckUser/i18n/ar.json
@@ -1,15 +1,17 @@
{
"@metadata": {
"authors": [
+ "AHmed Khaled",
"Alnokta",
"AwamerT",
"Ciphers",
"Meno25",
"Mido",
+ "NEHAOUA",
"OsamaK",
"ديفيد",
"علاء",
- "AHmed Khaled"
+ "محمد أحمد عبد الفتاح"
]
},
"checkuser-summary": ";ملاحظات\n* تفحص هذه الأداة أحدث التغييرات بهدف استرجاع عنوان الآي بي المُستخدم بواسطة مستخدم ما أو بهدف إظهار تعديلات/بيانات عنوان الآي بي.\n* المستخدمون والتعديلات التي تتم بواسطة عنوان آي بي العميل من الممكن استرجاعها من خلال رؤوس XFF ويتم ذلك من خلال إلحاق \"/xff\" في نهاية عنوان الآي بي. عناوين آي بي في4 (CIDR $1-32) وَآي بي في6 (CIDR $2-128) مدعومة.\n* لن يتم عرض أكثر من 5000 تعديل لأسباب تتعلق بالأداء.\n* استخدام هذه الأداة يتم وفقاً للسياسات.",
@@ -57,9 +59,10 @@
"checkuser-massblock": "امنع المستخدمين المختارين",
"checkuser-massblock-text": "الحسابات المختارة سيتم منعها لا نهائيا، مع تفعيل المنع التلقائي وتعطيل إنشاء الحسابات.\nعناوين الأيبي سيتم منعها لمدة 1 أسبوع لمستخدمي الأيبي فقط ومع تعطيل إنشاء الحسابات.",
"checkuser-blockemail": "امنع المستخدم من إرسال بريد إلكتروني",
- "checkuser-blocktalk": "امنع هذا المستخدم من تعديل صفحة نقاشه ما دام ممنوعاً",
+ "checkuser-blocktalk": "امنع هذا المستخدم من تعديل صفحة نقاشه ما دام ممنوعا",
"checkuser-blocktag": "استبدل صفحات المستخدمين ب:",
"checkuser-blocktag-talk": "استبدل صفحات النقاش ب:",
+ "checkuser-reblock": "تجاوز المنع الحالي",
"checkuser-massblock-commit": "منع المستخدمين المختارين",
"checkuser-block-success": "'''{{PLURAL:$2|المستخدم|المستخدمون}} $1 الآن {{PLURAL:$2|ممنوع|ممنوعون}}.'''",
"checkuser-block-failure": "'''لا مستخدمون تم منعهم.'''",
@@ -67,7 +70,6 @@
"checkuser-block-noreason": "يجب أن تعطي سببا لعمليات المنع.",
"checkuser-centralauth-multilock": "منع متعدد للحسابات المحددة",
"checkuser-noreason": "يجب أن تقدم سببًا لهذا الاستعلام.",
- "checkuser-accounts": "$1 {{PLURAL:$1|حساب|حساب}} جديد",
"checkuser-too-many": "نتائج كثيرة جدا (بناء على استعلام تقريبي)، من فضلك قلل CIDR.\nهذه هي الأيبيهات المستخدمة (5000 كحد أقصى، مرتبة بالعنوان):",
"checkuser-user-nonexistent": "المستخدم المحدد غير موجود.",
"checkuser-search": "بحث في إدخالات سجل تدقيق المستخدم",
@@ -77,13 +79,13 @@
"checkuser-log-search-target": "الهدف:",
"checkuser-log-search-type": "البحث حسب:",
"checkuser-ipeditcount": "~$1 من كل المستخدمين",
- "checkuser-showmain": "غير إلى استمارة تدقيق المستخدم الرئيسية",
+ "checkuser-showmain": "تغيير إلى استمارة تدقيق المستخدم الرئيسية",
"checkuser-limited": "'''هذه النتائج تم اختصارها لأسباب تتعلق بالأداء.'''",
"checkuser-log-entry-userips": "$3، $1 حصل على عناوين الأيبي ل$2",
- "checkuser-log-entry-ipedits": "$3، $1 حصل على التعديلات ل$2",
- "checkuser-log-entry-ipusers": "$3، $1 حصل على المستخدمين ل$2",
- "checkuser-log-entry-ipedits-xff": "$3، $1 حصل على التعديلات للXFF $2",
- "checkuser-log-entry-ipusers-xff": "$3، $1 حصل على المستخدمين لرؤوس XFF $2",
+ "checkuser-log-entry-ipedits": "$3، $1 حصل على التعديلات ل<bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3، $1 حصل على المستخدمين ل<bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3، $1 حصل على التعديلات للXFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3، $1 حصل على المستخدمين لرؤوس XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3، $1 حصل على التعديلات ل$2",
"checkuser-autocreate-action": "تم إنشاؤه تلقائيا",
"checkuser-create-action": "تم إنشاؤه",
@@ -92,26 +94,45 @@
"checkuser-token-fail": "فشلت الجلسة. يُرجى المحاولة مرة أخرى.",
"checkuser-login-failure": "أخفق تسجيل الدخول إلى {{SITENAME}} كـ$1",
"checkuser-login-success": "تم تسجيل الدخول بنجاح إلى {{SITENAME}} كـ$1",
- "apihelp-query+checkuser-description": "تحقق من عناوين الآيبي التي يتم استخدامها بواسطة اسم مستخدم معين أو أي أسماء المستخدمين يتم استخدامها بواسطة عنوان آيبي محدد.",
- "apihelp-query+checkuser-summary": "تحقق من عناوين الآيبي التي يتم استخدامها بواسطة اسم مستخدم معين أو أي أسماء المستخدمين يتم استخدامها بواسطة عنوان آيبي محدد.",
- "apihelp-query+checkuser-param-request": "نوع طلب تدقيق المستخدم:\n;userips: احصل على عنوان الآيبي للمستخدم المستهدف.\n;edits:التعديلات: الحصول على تغييرات من عنوان IP آيبي نطاق الهدف.\n;ipusers: احصل على مستخدمين من عنوان آيبي أو نطاق الهدف.",
- "apihelp-query+checkuser-param-target": "اسم المستخدم أو عنوان آيبي أو نطاق CIDR للتحقق.",
- "apihelp-query+checkuser-param-reason": "السبب للتحقق.",
- "apihelp-query+checkuser-param-limit": "حد الصفوف",
- "apihelp-query+checkuser-param-timecond": "الحد الزمني لبيانات المستخدم (مثل \"-2 weeks\" أو \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "استخدم بيانات XFF بدلاً من عنوان الآيبي.",
- "apihelp-query+checkuser-example-1": "لتحقق من عناوين الآيبي لـ[[User:Example]]",
- "apihelp-query+checkuser-example-2": "تدقيق تعديلات من 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "الحصول على إدخالات من سجل تدقيق المستخدم.",
- "apihelp-query+checkuserlog-summary": "الحصول على إدخالات من سجل تدقيق المستخدم.",
- "apihelp-query+checkuserlog-param-user": "اسم المستخدم لمدقق المستخدم.",
- "apihelp-query+checkuserlog-param-target": "تم تدقيق مستخدم أو عنوان آيبي أو نطاق CIDR للتحقق.",
- "apihelp-query+checkuserlog-param-limit": "حد الصفوف",
- "apihelp-query+checkuserlog-param-from": "الطابع الزمني لبدء العد منه.",
- "apihelp-query+checkuserlog-param-to": "الطابع الزمني لإنهاء التعداد.",
- "apihelp-query+checkuserlog-example-1": "عرض تدقيقات [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "عرض تدقيقات 192.0.2.0/24 بعد 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "يجب عليك تحديد سبب لهذا التدقيق.",
- "apierror-checkuser-timelimit": "تحتاج إلى استخدام الحد الزمني الصحيح (مثل \"-2 weeks\" أو \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "وضع الطلب غير صالح"
+ "group-checkuser.css": "/* الأنماط المتراصة CSS المعروضة هنا ستؤثر على مدققي المستخدم فقط */",
+ "group-checkuser.js": "/* الجافا سكريبت المعروضة هنا ستؤثر على مدققي المستخدم فقط */",
+ "checkuser-investigateblock": "منع المستخدمين",
+ "checkuser-investigateblock-reason": "السبب",
+ "checkuser-investigateblock-options": "خيارات إضافية",
+ "checkuser-investigateblock-notice-text-label": "نص الويكي",
+ "checkuser-investigate-log": "سجلات التحقيق",
+ "checkuser-investigate-log-entry": "$3, $1 بحث عن معلومات لـ<bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "لم يتم العثور على مدخلات سجل التحقيق.",
+ "checkuser-investigate-log-subtitle": "التحويل إلى استمارة التحقيق",
+ "checkuser-investigate": "فحص",
+ "checkuser-investigate-page-subtitle": "التحقيق الحالي حول $1",
+ "checkuser-investigate-subtitle-block-button-label": "منع",
+ "checkuser-investigate-indicator-new-investigation": "تحقيق جديد",
+ "checkuser-investigate-indicator-logs": "السجلات",
+ "checkuser-investigate-legend": "البحث عن أسماء المستخدمين أو عناوين الآيبي أو نطاقات الآيبي",
+ "checkuser-investigate-notice-no-results": "لا توجد نتائج.",
+ "checkuser-investigate-tab-preliminary-check": "تحقق ابتدائي",
+ "checkuser-investigate-tab-compare": "قارن",
+ "checkuser-investigate-targets-label": "أسماء المستخدمين وعناوين الآيبي",
+ "checkuser-investigate-targets-placeholder": "اسم المستخدم أو 1.1.1.1",
+ "checkuser-investigate-duration-label": "المدة",
+ "checkuser-investigate-duration-option-1w": "الأسبوع الماضي",
+ "checkuser-investigate-duration-option-2w": "آخر أسبوعين",
+ "checkuser-investigate-reason-label": "السبب",
+ "checkuser-investigate-preliminary-table-cell-blocked": "ممنوع",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|تعديل|تعديلات}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "غير ممنوع",
+ "checkuser-investigate-preliminary-table-header-blocked": "الحالة",
+ "checkuser-investigate-preliminary-table-header-editcount": "التعديلات",
+ "checkuser-investigate-preliminary-table-header-groups": "المجموعات",
+ "checkuser-investigate-preliminary-table-header-name": "اسم المستخدم",
+ "checkuser-investigate-preliminary-table-header-registration": "البيانات المرفقة",
+ "checkuser-investigate-preliminary-table-header-wiki": "الويكي",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "لم يعثر على الويكي",
+ "checkuser-investigate-filters-legend": "المرشحات",
+ "checkuser-investigate-compare-copy-button-label": "أظهر نص الويكي",
+ "checkuser-investigate-compare-table-cell-unregistered": "غير مسجل",
+ "checkuser-investigate-compare-table-header-username": "اسم المستخدم:",
+ "checkuser-investigate-compare-table-header-activity": "نطاق التاريخ",
+ "checkuser-investigate-compare-table-header-useragent": "وكيل المستخدم"
}
diff --git a/CheckUser/i18n/arz.json b/CheckUser/i18n/arz.json
index acc301da..9fdd20ad 100644
--- a/CheckUser/i18n/arz.json
+++ b/CheckUser/i18n/arz.json
@@ -12,7 +12,7 @@
"checkuser": "التشييك على اليوزر",
"checkuserlog": "سجل تشييك اليوزر",
"group-checkuser": "التشييك على اليوزرز",
- "group-checkuser-member": "تشييك اليوزر",
+ "group-checkuser-member": "{{GENDER:$1|تشييك اليوزر}}",
"right-checkuser": "التشييك على عناوين الاى بى لليوزرز و معلومات تانية",
"right-checkuser-log": "اعرض السجل بتاع تشييك اليوزر",
"grouppage-checkuser": "{{ns:project}}:تشييك اليوزر",
@@ -50,7 +50,6 @@
"checkuser-block-failure": "'''مافيش يوزرز ممنوعين'''",
"checkuser-block-limit": "انت اخترت يوزرز كتار جدا.",
"checkuser-block-noreason": "لازم تدى سبب لعمليات المنع.",
- "checkuser-accounts": "$1 جديد {{PLURAL:$1|حساب|حسابات}}",
"checkuser-too-many": "فى نتايج كتيرة جدا, لو سمحت تقلل الـ CIDR.\nدول الايبيهات المستعملة (5000 كحد اقصى, مترتبين بالعنوان):",
"checkuser-user-nonexistent": "اليوزر المتحدد مش موجود",
"checkuser-search": "تدوير",
diff --git a/CheckUser/i18n/ast.json b/CheckUser/i18n/ast.json
index 9e8fac14..35f1e4c9 100644
--- a/CheckUser/i18n/ast.json
+++ b/CheckUser/i18n/ast.json
@@ -3,10 +3,11 @@
"authors": [
"Dferg",
"Esbardu",
- "MarcoAurelio",
- "Xuacu",
+ "Fitoschido",
"Macofe",
- "McDutchie"
+ "MarcoAurelio",
+ "McDutchie",
+ "Xuacu"
]
},
"checkuser-summary": "Esta ferramienta escanea los cambios recientes pa sacar les IP usaes por un usuariu o p'amosar los datos d'ediciones/usuarios d'una IP.\nLos usuarios y ediciones correspondientes a una IP puen sacase per aciu de les cabeceres XFF amestando depués de la IP \\\"/xff\\\". Puen usase los protocolos IPv4 (CIDR $1-32) ya IPv6 (CIDR $2-128).\nPor razones de rindimientu nun s'amosarán más de 5.000 ediciones.\nEmplega esta ferramienta acordies cola política d'usu.",
@@ -45,7 +46,7 @@
"checkuser-check-this-user": "Comprobar esti usuariu",
"checkuser-recent-checks": "Comprobaciones recién pa esti usuariu",
"checkuser-log-fail": "Nun se pue añader la entrada nel rexistru",
- "checkuser-nolog": "Nun s'atopó l'archivu del rexistru.",
+ "checkuser-nolog": "Nun s'atopó'l ficheru del rexistru.",
"checkuser-blocked": "Bloquiáu",
"checkuser-gblocked": "Bloquiáu globalmente",
"checkuser-locked": "Candáu",
@@ -64,7 +65,6 @@
"checkuser-block-noreason": "Tienes que dar un motivu pa los bloqueos.",
"checkuser-centralauth-multilock": "Candar múltiples cuentes esbillaes",
"checkuser-noreason": "Tien de dar un motivu pa esta consulta.",
- "checkuser-accounts": "$1 {{PLURAL:$1|cuenta nueva|cuentes nueves}}",
"checkuser-too-many": "Demasiaos resultaos (acordies colo albidrao pola consulta), intenta menguar el CIDR.\nEstes son les direiciones IP usaes (5000 max, axeitaes por direición):",
"checkuser-user-nonexistent": "L'usuariu especificáu nun esiste.",
"checkuser-search": "Buscar entraes nel rexistru de check user",
@@ -77,10 +77,10 @@
"checkuser-showmain": "Cambiar al formulariu principal del comprobador d'usuarios",
"checkuser-limited": "'''Estos resultaos fueron truncaos por motivos de rendimientu.'''",
"checkuser-log-entry-userips": "$3, $1 recibió les direiciones IP de $2",
- "checkuser-log-entry-ipedits": "$3, $1 recibió les ediciones de $2",
- "checkuser-log-entry-ipusers": "$3, $1 recibió los usuarios de $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 recibió les ediciones de XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 recibió los usuarios de XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 recibió les ediciones de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 recibió los usuarios de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 recibió les ediciones de XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 recibió los usuarios de XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 recibió les ediciones de $2",
"checkuser-autocreate-action": "creóse automáticamente",
"checkuser-create-action": "creóse",
@@ -89,26 +89,9 @@
"checkuser-token-fail": "Fallu de la sesión. Vuelvi a intentalo.",
"checkuser-login-failure": "Falló l'aniciu de sesión en {{SITENAME}} como $1",
"checkuser-login-success": "Aniciu de sesión correutu en {{SITENAME}} como $1",
- "apihelp-query+checkuser-description": "Comprobar qué direiciones IP usa un usuariu determináu o que nomes d'usuariu usa una IP determinada.",
- "apihelp-query+checkuser-summary": "Comprobar qué direiciones IP usa un usuariu determináu o que nomes d'usuariu usa una IP determinada.",
- "apihelp-query+checkuser-param-request": "Tipu de solicitú CheckUser:\n;userips: Devolver la direición IP del usuariu destín.\n;edits: Devolver los cambios de la direición o rangu IP de destín.\n;ipusers: Devolver los usuarios de la direición o rangu IP de destín.",
- "apihelp-query+checkuser-param-target": "Nome d'usuariu, direición IP, o rangu CIDR a comprobar.",
- "apihelp-query+checkuser-param-reason": "Motivu de la comprobación.",
- "apihelp-query+checkuser-param-limit": "Llende de fileres.",
- "apihelp-query+checkuser-param-timecond": "Llende de tiempu de datos del usuariu (p. ex. \"-2 weeks\" o \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Usar datos XFF en llugar de direiciones IP.",
- "apihelp-query+checkuser-example-1": "Comprobar les direiciones IP pa [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Comprobar les ediciones dende 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Recibir entraes del rexistru de CheckUser.",
- "apihelp-query+checkuserlog-summary": "Recibir entraes del rexistru de CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Nome d'usuariu de CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Usuariu, direición IP o rangu CIDR comprobáu.",
- "apihelp-query+checkuserlog-param-limit": "Llende de fileres.",
- "apihelp-query+checkuserlog-param-from": "La marca horaria dende la que principiar la enumeración.",
- "apihelp-query+checkuserlog-param-to": "La marca horaria na que finar la enumeración.",
- "apihelp-query+checkuserlog-example-1": "Amosar les comprobaciones de [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Amosar les comprobaciones de 192.0.2.0/24 después de 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Tienes de dar un motivu pa la comprobación.",
- "apierror-checkuser-timelimit": "Tienes d'usar una llende de tiempu correuta (como «-2 weeks» o «2 weeks ago»).",
- "apierror-checkuser-invalidmode": "Mou de solicitú inválidu"
+ "checkuser-investigate": "Investigar",
+ "checkuser-investigate-legend": "Buscar nomes d'usuariu, direiciones IP o intervalos d'IP",
+ "checkuser-investigate-targets-label": "Nomes d'usuariu y direcciones IP",
+ "checkuser-investigate-targets-placeholder": "Nome d'Usuariu o 1.1.1.1",
+ "checkuser-investigate-reason-label": "Motivu"
}
diff --git a/CheckUser/i18n/az.json b/CheckUser/i18n/az.json
index 4c966d6c..19ded4fe 100644
--- a/CheckUser/i18n/az.json
+++ b/CheckUser/i18n/az.json
@@ -3,28 +3,94 @@
"authors": [
"Cekli829",
"Emperyan",
+ "Neriman2003",
"PPerviz",
+ "Toghrul Rahimli",
"Vago",
+ "Vesely35",
"Vugar 1981"
]
},
+ "checkuser-summary": "Bu alət bir istifadəçi tərəfindən istifadə olunan IP ünvanlarını almaq və ya bir IP ünvan üçün redaktə/istifadəçi məlumatlarını göstərmək üçün son dəyişiklikləri yoxlayır. Bir müştəri IP ünvanı ilə istifadəçilər və redaktələr IP ünvana \"/xff\" əlavə edərək XFF başlıqları əldə edə bilər. IPv4 (CIDR $1-32) və IPv6 (CIDR $2-128) ilə dəstəklənir. Performans səbəbləri üçün 5,000-dən çox redaktə qaytarılmayacaq. Bunu siyasətə uyğun olaraq istifadə edin.",
+ "checkuser-desc": "Müvafiq icazəsi olan istifadəçiləri istifadəçinin IP ünvanlarını və digər məlumatları yoxlamaq imkanı verir",
+ "checkuser-logcase": "Gündəlik axtarışı həssasdır.",
"checkuser": "Təftişçi",
"checkuserlog": "Təftişçi qeydi",
+ "checkuser-contribs": "İstifadəçinin IP ünvanını yoxla",
+ "checkuser-contribs-log": "Hal-hazırki istifadəçi yoxlanılmaları",
"group-checkuser": "Təftişçilər",
+ "group-checkuser-member": "{{GENDER:$1|təftiş et}}",
+ "right-checkuser": "İstifadəçinin IP ünvanını və daha çox məlumatı yoxla",
+ "right-checkuser-log": "Təftişçi jurnalına bax",
+ "action-checkuser": "istifadəçinin IP ünvanını və daha çox məlumatı yoxla",
+ "action-checkuser-log": "təftişçi jurnalına bax",
"grouppage-checkuser": "{{ns:project}}:Təftişçi",
"checkuser-reason": "Səbəb:",
"checkuser-reason-api": "API: $1",
+ "checkuser-showlog": "Təftişçi jurnalına keçid et",
+ "checkuser-query": "Son dəyişiklikləri soruşun",
+ "checkuser-target": "IP ünvanı və ya istifadəçi adı:",
+ "checkuser-users": "İstifadəçiləri əldə et",
+ "checkuser-edits": "Redaktələri əldə et",
+ "checkuser-ips": "IP ünvanları əldə et",
"checkuser-period": "Müddəti:",
"checkuser-week-1": "Son həftə",
"checkuser-week-2": "son iki həftə",
"checkuser-month": "son 30 gün",
"checkuser-all": "bütün",
+ "checkuser-cidr-label": "IP ünvanlarının siyahısı üçün ümumi ərazini və təsirlənmiş IP ünvanlarını tapın",
+ "checkuser-cidr-res": "Common CIDR:",
+ "checkuser-empty": "Jurnalda heç nə yoxdur.",
+ "checkuser-nomatch": "Heç bir nəticə tapılmadı",
+ "checkuser-nomatch-edits": "Heç bir nəticə tapılmadı.\nSon redaktənin edildiyi tarix: $2, $1",
"checkuser-check": "Yoxla",
- "checkuser-log-fail": "Gündəlik girdilər əlavə etilemiyor.",
- "checkuser-blocked": "Bloklanmış",
+ "checkuser-check-this-user": "Bu istifadəçini yoxla",
+ "checkuser-recent-checks": "Bu istifadəçi üçün hal-hazırki yoxlamalar",
+ "checkuser-log-fail": "Gündəlik qeydləri əlavə etmək mümkün olmadı.",
+ "checkuser-nolog": "Jurnal faylı tapılmadı.",
+ "checkuser-blocked": "Bloklanıb",
"checkuser-gblocked": "Qlobal bloklanmış",
"checkuser-locked": "Bloklanıb",
- "checkuser-search": "Axtar",
+ "checkuser-wasblocked": "Daha əvvəl bloklanıb",
+ "checkuser-localonly": "Birləşdirilməyib",
+ "checkuser-massblock": "Seçilmiş istifadəçiləri blokla",
+ "checkuser-massblock-text": "Seçilən hesablar qeyri-müəyyən hallarda IP ünvanlarının autobloklanması və hesab yaratmağı dayandırmaqla birlikdə bloklanacaq. IP ünvanlar yalnız bir həftə anonim istifadəçilər üçün bloklanır və hesab yaratma işi dayandırılır.",
+ "checkuser-blockemail": "E-poçt göndərməyin qarşısını almaq",
+ "checkuser-blocktalk": "Bloklandıqda öz müzakirə səhifəsini redaktə etməyə mane olun",
+ "checkuser-blocktag": "İstifadəçi səhifələrini aşağıdakılarla dəyişdirin:",
+ "checkuser-blocktag-talk": "Müzakirə səhifələrini aşağıdakılarla dəyişdirin:",
+ "checkuser-massblock-commit": "Seçilmiş istifadəçiləri blokla",
+ "checkuser-block-success": "'''{{PLURAL:$2|İstifadəçi|İstifadəçilər}} $1 bloklanıb'''",
+ "checkuser-block-failure": "'''Bloklanmış istifadəçi yoxdur.'''",
+ "checkuser-block-limit": "Çox istifadəçi seçilib.",
+ "checkuser-block-noreason": "Siz blok üçün səbəb yazmalısınız.",
+ "checkuser-centralauth-multilock": "Multi kilidi seçilmiş hesablar",
+ "checkuser-noreason": "Siz bu sorğu üçün səbəb yazmalısınız.",
+ "checkuser-too-many": "Çox nəticə var. (sorğunun qiymətləndirilməsinə görə), CIDR-ni daraltın. Burada istifadə olunan IP ünvanları (5000 max, ünvanı ilə sıralanır):",
+ "checkuser-user-nonexistent": "Göstərilən istifadəçi yoxdur.",
+ "checkuser-search": "İstifadəçi yoxlama girişlərini axtarın",
"checkuser-search-submit": "Axtar",
- "checkuser-create-action": "yaradılıb"
+ "checkuser-search-initiator": "Təşəbbüskar",
+ "checkuser-search-target": "hədəf",
+ "checkuser-log-search-target": "Hədəf:",
+ "checkuser-log-search-type": "Axtar:",
+ "checkuser-ipeditcount": "Bütün istifadəçilərdən ~$1",
+ "checkuser-showmain": "Təftişçi əsas formasına keç",
+ "checkuser-limited": "'''Bu nəticələr performans səbəbləri ilə kəsildi.'''",
+ "checkuser-log-entry-userips": "$3, $1 $2 istifadəçisinin IP ünvanlarını əldə etdi",
+ "checkuser-log-entry-ipedits": "$3, $1 <bdi>$2</bdi> istifadəçisinin redaktələrini əldə etdi",
+ "checkuser-log-entry-ipusers": "$3, $1 <bdi>$2</bdi> istifadəçisinin istifadəçilərini əldə etdi",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 XFF <bdi>$2</bdi> istifadəçisinin redaktələrini əldə etdi",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 XFF <bdi>$2</bdi> istifadəçisinin istifadəçilərini əldə etdi",
+ "checkuser-log-entry-useredits": "$3, $1 $2 istifadəçisinin redaktələrini əldə etdi",
+ "checkuser-autocreate-action": "avtomatik yaradıldı",
+ "checkuser-create-action": "yaradılıb",
+ "checkuser-email-action": "\"$1\" istifadəçisinə e-poçt göndər",
+ "checkuser-reset-action": "\"$1\" istifadəçisinin parolunu sıfırla",
+ "checkuser-token-fail": "Daxil olarkən xəta baş verdi. Zəhmət olmasa bir daha cəhd edin",
+ "checkuser-login-failure": "$1 olaraq {{SITENAME}} saytına daxil olmaq uğursuz oldu",
+ "checkuser-login-success": "$1 olaraq {{SITENAME}} saytına daxil olmaq uğurla alındı",
+ "group-checkuser.css": "/* Burada yerləşən CSS yalnız təftişçilərə şamil olunur */",
+ "group-checkuser.js": "/* Burada yerləşən CSS yalnız təftişçilərə şamil olunur */",
+ "checkuser-investigateblock-success": "'''{{PLURAL:$2|İstifadəçi|İstifadəçilər}} $1 bloklanıb'''"
}
diff --git a/CheckUser/i18n/azb.json b/CheckUser/i18n/azb.json
index bd178947..e0110246 100644
--- a/CheckUser/i18n/azb.json
+++ b/CheckUser/i18n/azb.json
@@ -1,10 +1,13 @@
{
"@metadata": {
"authors": [
+ "E THP",
"Ebrahimi-amir",
"පසිඳු කාවින්ද"
]
},
+ "checkuser": "تفتیشچیلر",
+ "grouppage-checkuser": "{{ns:project}}:تفتیشچیلر",
"checkuser-reason": "ندن:",
"checkuser-all": "بوتون",
"checkuser-search": "آختار",
diff --git a/CheckUser/i18n/ba.json b/CheckUser/i18n/ba.json
index 05686a77..2a240764 100644
--- a/CheckUser/i18n/ba.json
+++ b/CheckUser/i18n/ba.json
@@ -3,11 +3,11 @@
"authors": [
"Assele",
"Haqmar",
- "Ләйсән",
- "Рустам Нурыев",
"Sagan",
"Азат Хәлилов",
- "Ансар"
+ "Ансар",
+ "Ләйсән",
+ "Рустам Нурыев"
]
},
"checkuser-summary": "Был ҡорал ҡатнашыусы тарафынан ҡулланылған IP адрестарҙы алыр өсөн йәки IP адрестан эшләнгән үҙгәртеүҙәрҙе/ҡатнашыусыларҙы ҡарар өсөн ҡулланыла ала.\nIP адрестан эшләнгән үҙгәртеүҙәр һәм ҡатнашыусылар күрһәтелгән XFF-башлыҡтар аша, IP адрестан һуң \"/xff\" өҫтәп, алына ала. IPv4 (CIDR $1-32) һәм IPv6 (CIDR $2-128) ҡулланыла ала.\nЕтештереүсәнлек маҡсаттарында тәүге 5000 үҙгәртеү генә күрһәтеләсәк.\nБыл ҡоралды ҡағиҙәләргә ярашлы ҡулланығыҙ.",
@@ -64,7 +64,6 @@
"checkuser-block-limit": "Бигерәк күп ҡатнашыусы һайланған.",
"checkuser-block-noreason": "Һеҙ бикләүҙең сәбәбен күрһәтергә тейешһегеҙ.",
"checkuser-noreason": "Һеҙ был һорауҙың сәбәбен күрһәтергә тейешһегеҙ.",
- "checkuser-accounts": "$1 {{PLURAL:$1|яңы иҫәп яҙмаһы}}",
"checkuser-too-many": "Бигерәк күп һөҙөмтә (һорауҙы баһалау буйынса), зинһар, CIDR-ҙы тарайтығыҙ.\nҠулланылған IP-адрестар (иң күбе — 5000, адрестары буйынса тәртипкә килтерелгән):",
"checkuser-user-nonexistent": "Күрһәтелгән ҡатнашыусы юҡ.",
"checkuser-search": "Ҡатнашыусыны тикшереү журналы яҙмалары буйынса эләү",
@@ -74,34 +73,17 @@
"checkuser-log-search-target": "Маҡсат:",
"checkuser-log-search-type": "Буйынса эҙләү:",
"checkuser-ipeditcount": "бөтә ҡатнашыусыларҙан ~$1",
- "checkuser-showmain": "!!FUZZY!!Ҡатнашыусыларҙы тикшереү битенә кире ҡайтырға",
+ "checkuser-showmain": "Ҡатнашыусыларҙы тикшереү битенә кире ҡайтырға",
"checkuser-limited": "'''Һөҙөмтәләр етештереүсәнлек маҡсаттарында киҫелде.'''",
"checkuser-log-entry-userips": " $2 өсөн IP адрестар алған $1 $3",
- "checkuser-log-entry-ipedits": "$3 $1 өсөн үҙгәртеүҙәр алған $2",
- "checkuser-log-entry-ipusers": "$2 адресы өсөн иҫәп яҙмаһы алынды $1 $3",
- "checkuser-log-entry-ipedits-xff": "$3 $1 төҙәтеү алды XFF $2",
- "checkuser-log-entry-ipusers-xff": "XFF $2 өсөн иҫәп яҙмаһы алды $3 $1",
+ "checkuser-log-entry-ipedits": "$3 $1 өсөн үҙгәртеүҙәр алған <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "<bdi>$2</bdi> адресы өсөн иҫәп яҙмаһы алынды $1 $3",
+ "checkuser-log-entry-ipedits-xff": "$3 $1 төҙәтеү алды XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "XFF <bdi>$2</bdi> өсөн иҫәп яҙмаһы алды $3 $1",
"checkuser-log-entry-useredits": "$2 өсөн төҙәтеү алды $3 $1",
"checkuser-autocreate-action": "үҙенән-үҙе булдырылған",
"checkuser-create-action": "төҙөлдө",
"checkuser-email-action": "\"$1\" ҡатнашыусыһына электрон хат ебәргән",
"checkuser-reset-action": "\"$1\" ҡатнашыусыһының серһүҙен үҙгәртергә",
- "checkuser-token-fail": "Сеанс өҙөлдө. Зинһар, тағы бер тапҡыр ҡабатлап ҡарағыҙ.",
- "apihelp-query+checkuser-description": "Ҡатнашыусы ниндәй IP-адрес ҡуллыныуын йәки ниндәй исемдәр ошоIP-адресты ҡулланыуын тикшерегеҙ.",
- "apihelp-query+checkuser-param-request": "Чекюзерға һорау ебәреү тибы:\n;userips:Ҡулланыусының IP-адресын алырға .\n; edits:IP-адресынан йәки диапазонынан алынған үҙгәртеүҙәр турыһында мәғлүмәт аларға.\n;ipusers: IP-адресындаға йәки диапозонындағы ҡулланыусыларҙы белергә.",
- "apihelp-query+checkuser-param-target": "Ҡатнашыу IP-адрес йәки CIDR-диапазоны тикшереү өсөн.",
- "apihelp-query+checkuser-param-reason": "Тикшереү сәбәбе.",
- "apihelp-query+checkuser-param-limit": "Юл һанын сикләү.",
- "apihelp-query+checkuser-param-timecond": "Ҡатнашыусы өсөн ваҡыт сикләүе (мәҫәлән, «-2 weeks» йәки «2 weeks ago»).",
- "apihelp-query+checkuser-param-xff": "IP-адрес урынына XFF мәғлүмәттәрен ҡулланырға.",
- "apihelp-query+checkuser-example-1": "IP-адресты тикшерергә [[User:Example]]",
- "apihelp-query+checkuser-example-2": " 192.0.2.0/24 төҙәтеүҙәрен тикшерергә",
- "apihelp-query+checkuserlog-description": "Ҡатнашыусыларҙы тикшереү журналынан яҙма алырға (CheckUser).",
- "apihelp-query+checkuserlog-param-user": "Чекюзер ҡулланыусы исемлеге.",
- "apihelp-query+checkuserlog-param-target": "IP-адрес йәки CIDR-диапазоны тикшерелелгән ҡатнашыусы.",
- "apihelp-query+checkuserlog-param-limit": "Юл һанын сикләү.",
- "apihelp-query+checkuserlog-param-from": "Иҫәп күсереү башланған ваҡыт билдәһе",
- "apihelp-query+checkuserlog-param-to": "Иҫәп күсереү тамамланған ваҡыт билдәһе",
- "apihelp-query+checkuserlog-example-1": "Тикшереүҙәрҙә күрһәтергә [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "192.0.2.0/24 башлап 2011-10-15T23:00:00Z тиклем тикшереүҙе күрһәтергә"
+ "checkuser-token-fail": "Сеанс өҙөлдө. Зинһар, тағы бер тапҡыр ҡабатлап ҡарағыҙ."
}
diff --git a/CheckUser/i18n/bcc.json b/CheckUser/i18n/bcc.json
index bb25349a..563b6ab2 100644
--- a/CheckUser/i18n/bcc.json
+++ b/CheckUser/i18n/bcc.json
@@ -1,7 +1,8 @@
{
"@metadata": {
"authors": [
- "Mostafadaneshvar"
+ "Mostafadaneshvar",
+ "Sultanselim baloch"
]
},
"checkuser-desc": "کاربرانء اجازت دن گون مناسبین اجازت آدرسان آی پی یک کاربری و دگه اطلاعاتء کنترل بکنت",
@@ -29,7 +30,7 @@
"checkuser-user-nonexistent": "مشخص بوتگین کاربر موجود نهنت",
"checkuser-search": "گردگ",
"checkuser-search-submit": "گردگ",
- "checkuser-search-initiator": "شروع کنوک",
+ "checkuser-search-initiator": "بنٚگݔجۏک",
"checkuser-search-target": "هدف",
"checkuser-ipeditcount": "~$1 چه کلی کابران",
"checkuser-showmain": "په فرم اصلی کنترل کاربر تر"
diff --git a/CheckUser/i18n/bcl.json b/CheckUser/i18n/bcl.json
index 94ded4cd..d2a2a641 100644
--- a/CheckUser/i18n/bcl.json
+++ b/CheckUser/i18n/bcl.json
@@ -1,6 +1,7 @@
{
"@metadata": {
"authors": [
+ "Brazal.dang",
"Filipinayzd",
"Geopoet"
]
@@ -21,7 +22,7 @@
"grouppage-checkuser": "{{ns:project}}:Rikisaha an paragamit",
"checkuser-reason": "Rason:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Ipahiling an mga historial",
+ "checkuser-showlog": "Magduman sa CheckUser log",
"checkuser-query": "Ihapot an dae pa sana nahaloy na mga kaliwatan",
"checkuser-target": "Estada kan IP o ngaran-parágamit:",
"checkuser-users": "Kûanón",
@@ -55,10 +56,9 @@
"checkuser-block-limit": "Grabe kadakulon na mga paragamit an pinagpili.",
"checkuser-block-noreason": "Ika kaipohan na magtao nin sarong rason para sa mga pagkubkob.",
"checkuser-noreason": "Ika kaipohan na magtao nin sarong rason para kaining kahaputan.",
- "checkuser-accounts": "$1 baguhon na {{PLURAL:$1|panindog|mga panindog}}",
"checkuser-too-many": "Grabe kadakulon na mga resulta (uyon sa estimeyt nin kahaputan), tabi man pakisaditan nin hababa an CIDR.\nUya an mga IP na pinaggamit (5000 pinakadakulon, pinagsalansan sa paagi nin estada):",
"checkuser-user-nonexistent": "An pinagsambit na paragamit bakong eksistido.",
- "checkuser-search": "Hanápon",
+ "checkuser-search": "Maghanap sa user log entries",
"checkuser-search-submit": "Hanapa baya",
"checkuser-search-initiator": "Inisyador",
"checkuser-search-target": "patamaan",
diff --git a/CheckUser/i18n/be-tarask.json b/CheckUser/i18n/be-tarask.json
index db32be32..bf9e0f12 100644
--- a/CheckUser/i18n/be-tarask.json
+++ b/CheckUser/i18n/be-tarask.json
@@ -1,11 +1,11 @@
{
"@metadata": {
"authors": [
+ "Artsiom91",
"EugeneZelenko",
"Jim-by",
"Red Winged Duck",
- "Wizardist",
- "Artsiom91"
+ "Wizardist"
]
},
"checkuser-summary": "Гэты інструмэнт праглядае апошнія зьмены для атрыманьня ІР-адрасоў удзельніка альбо паказвае рэдагаваньні/зьвесткі ўдзельніка па ІР-адрасе.\nУдзельнікі і рэдагаваньні, якія рабіліся з ІР-адрасу, пазначаным ў загалоўках XFF, можна атрымаць, дадаўшы да ІР-адрасу «/xff». Падтрымліваюцца IPv4 (CIDR $1-32) і IPv6 (CIDR $2-128).\nЗ прычыны прадукцыйнасьці будуць паказаны ня больш за 5000 рэдагаваньняў.\nКарыстайцеся гэтым інструмэнтам толькі згодна з правіламі.",
@@ -58,7 +58,6 @@
"checkuser-block-limit": "Выбрана зашмат рахункаў удзельнікаў.",
"checkuser-block-noreason": "Вам неабходна пазначыць прычыну блякаваньня.",
"checkuser-noreason": "Вам неабходна падаць прычыну гэтага запыту.",
- "checkuser-accounts": "$1 {{PLURAL:$1|новы рахунак|новыя рахункі|новых рахункаў}}",
"checkuser-too-many": "Зашмат вынікаў (згодна з ацэнкай запыту), калі ласка, абмяжуйце CIDR.\nТут пададзеныя ўжытыя ІР-адрасы (максымум 5000, адсартаваныя паводле адрасу):",
"checkuser-user-nonexistent": "Пазначанага рахунку ўдзельніка не існуе.",
"checkuser-search": "Пошук у запісах журналу праверкі ўдзельнікаў",
diff --git a/CheckUser/i18n/be.json b/CheckUser/i18n/be.json
index 128ba502..58d5005e 100644
--- a/CheckUser/i18n/be.json
+++ b/CheckUser/i18n/be.json
@@ -1,8 +1,8 @@
{
"@metadata": {
"authors": [
- "Тест",
- "Artsiom91"
+ "Artsiom91",
+ "Тест"
]
},
"checkuser-reason": "Прычына:",
diff --git a/CheckUser/i18n/bg.json b/CheckUser/i18n/bg.json
index 46993127..17384eef 100644
--- a/CheckUser/i18n/bg.json
+++ b/CheckUser/i18n/bg.json
@@ -4,48 +4,55 @@
"Borislav",
"DCLXVI",
"Spiritia",
- "Turin",
- "Vodnokon4e",
"StanProg",
- "Termininja"
+ "Ted Masters",
+ "Termininja",
+ "Turin",
+ "Vlad5250",
+ "Vodnokon4e"
]
},
- "checkuser-summary": "Този инструмент сканира последните промени и извлича IP адресите, използвани от потребител или показва информацията за редакциите/потребителя за посоченото IP.\nПотребители и редакции по клиентско IP могат да бъдат извлечени чрез XFF headers като се добави IP с \"/xff\". Поддържат се IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128).\nОт съображения, свързани с производителността на уикито, ще бъдат показани не повече от 5000 редакции. Използвайте инструмента съобразно установената политика.",
+ "checkuser-summary": "Този инструмент сканира последните промени, за да извлече IP адресите, използвани от потребител, или за да покаже информация за редакциите и потребителите от даден IP адрес.\nИнформация за потребители и редакции от даден IP адрес може да се извлече и от XFF headers, като в края на IP адреса се добави „/xff“. Поддържат се IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128).\nОт съображения, свързани с производителността на уикито, ще бъдат показани не повече от 5000 редакции.\nИзползвайте инструмента съобразно установената политика.",
"checkuser-desc": "Предоставя на потребители с подходящите права възможност за проверка на потребителски IP адреси и друга информация",
- "checkuser-logcase": "Търсенето в дневника различава главни от малки букви.",
+ "checkuser-logcase": "Търсенето в дневника е чувствително към регистъра на буквите.",
"checkuser": "Проверяване на потребител",
- "checkuserlog": "Дневник на проверяващите",
+ "checkuserlog": "Дневник на проверките на потребители",
"checkuser-contribs": "проверка на IP-адресите на потребителя",
+ "checkuser-contribs-log": "последни проверки",
"group-checkuser": "Проверяващи",
"group-checkuser-member": "{{GENDER:$1|проверяващ}}",
"right-checkuser": "Проверяване на потребителски IP адреси и друга информация",
"right-checkuser-log": "Преглеждане на дневника с проверки на потребители",
- "action-checkuser": "проверка на потребител",
- "action-checkuser-log": "проверка на дневника на проверяващите",
+ "action-checkuser": "проверяване на потребителски IP адреси и друга информация",
+ "action-checkuser-log": "преглед на дневника на проверяващите",
"grouppage-checkuser": "{{ns:project}}:Проверяващи",
"checkuser-reason": "Причина:",
"checkuser-reason-api": "API: $1",
"checkuser-showlog": "Преминаване към дневника на проверките",
"checkuser-query": "Заявка към последните промени",
"checkuser-target": "IP-адрес или потребителско име:",
- "checkuser-users": "Извличане на потребители",
- "checkuser-edits": "Извличане на редакции",
- "checkuser-ips": "Извличане на IP адреси",
+ "checkuser-users": "Връщане на потребители",
+ "checkuser-edits": "Връщане на редакции",
+ "checkuser-ips": "Връщане на IP адреси",
"checkuser-period": "Продължителност:",
"checkuser-week-1": "последната седмица",
"checkuser-week-2": "последните 2 седмици",
"checkuser-month": "последните 30 дни",
"checkuser-all": "всички",
+ "checkuser-cidr-res": "Общ CIDR:",
"checkuser-empty": "Дневникът не съдържа записи.",
"checkuser-nomatch": "Няма открити съвпадения.",
"checkuser-nomatch-edits": "Не бяха открити съвпадения.\nПоследната редакция е била на $1 в $2.",
"checkuser-check": "Проверка",
+ "checkuser-check-this-user": "Проверка на потребителя",
+ "checkuser-recent-checks": "Последни проверки на потребителя",
"checkuser-log-fail": "Беше невъзможно да се добави запис в дневника",
"checkuser-nolog": "Не беше открит дневник.",
"checkuser-blocked": "Блокиран",
"checkuser-gblocked": "Глобално блокиран",
"checkuser-locked": "Заключено",
"checkuser-wasblocked": "Блокиран преди време",
+ "checkuser-localonly": "Необединена",
"checkuser-massblock": "Блокиране на избраните потребители",
"checkuser-massblock-text": "Избраните потребителски сметки ще бъдат блокирани безсрочно, като създаването на сметки ще бъде забранено и ще бъде включена автоблокировка на IP адресите.\nСамо за анонимни потребители IP адресите ще бъдат блокирани за една седмица и ще бъде забранено създаването на потребителски сметки.",
"checkuser-blockemail": "Забрана на потребителя да праща е-поща",
@@ -57,8 +64,8 @@
"checkuser-block-failure": "'''Няма блокирани потребители.'''",
"checkuser-block-limit": "Избрани са твърде много потребители.",
"checkuser-block-noreason": "Трябва да се посочи причина за блокиранията.",
+ "checkuser-centralauth-multilock": "Заключване на избраните сметки",
"checkuser-noreason": "Необходимо е да се посочи основание за тази заявка.",
- "checkuser-accounts": "$1 {{PLURAL:$1|нова сметка|нови сметки}}",
"checkuser-too-many": "Твърде много резултати (според оценката на заявката), моля уточнете CIDR.\nПоказани са използваните IP адреси (най-много 5 000, сортирани по адрес):",
"checkuser-user-nonexistent": "Посоченият потребител не съществува.",
"checkuser-search": "Търсене в дневника на проверките",
@@ -70,7 +77,9 @@
"checkuser-ipeditcount": "~$1 от всички потребители",
"checkuser-showmain": "Преминаване към страницата за проверка на редактори",
"checkuser-limited": "'''Резултатите бяха съкратени от съображения, свързани с производителността на системата.'''",
+ "checkuser-autocreate-action": "беше автоматично създадена",
+ "checkuser-create-action": "е създаден",
"checkuser-email-action": "изпрати е-писмо на потребител „$1“",
"checkuser-reset-action": "промяна на парола за потребител „$1“",
- "apierror-checkuser-invalidmode": "Невалиден режим на заявката"
+ "checkuser-token-fail": "Сесията не е успешна. Опитайте отново."
}
diff --git a/CheckUser/i18n/bn.json b/CheckUser/i18n/bn.json
index ac49a7ec..b9e52dcc 100644
--- a/CheckUser/i18n/bn.json
+++ b/CheckUser/i18n/bn.json
@@ -2,11 +2,13 @@
"@metadata": {
"authors": [
"Aftab1995",
+ "Aftabuzzaman",
"Bellayet",
"Nasir8891",
+ "Sibabrata Banerjee",
+ "Sourav Halder",
"Wikitanvir",
"Zaheen",
- "Aftabuzzaman",
"আফতাবুজ্জামান"
]
},
@@ -22,7 +24,7 @@
"right-checkuser": "ব্যবহারকারীর আইপি ঠিকানা এবং অন্যান্য তথ্য যাচাই করুন",
"right-checkuser-log": "ব্যবহারকারী পরীক্ষণ লগ দেখুন",
"action-checkuser": "ব্যবহারকারীর আইপি ঠিকানা এবং অন্যান্য তথ্য পরীক্ষা",
- "action-checkuser-log": "ব্যবহারকারী পরীক্ষণ লগ দেখুন",
+ "action-checkuser-log": "ব্যবহারকারী পরীক্ষণ লগ দেখার",
"grouppage-checkuser": "{{ns:project}}:ব্যবহারকারী পরীক্ষক",
"checkuser-reason": "কারণ:",
"checkuser-reason-api": "এপিআই: $1",
@@ -31,7 +33,7 @@
"checkuser-target": "আইপি ঠিকানা বা ব্যবহারকারীর নাম:",
"checkuser-users": "ব্যবহারকারী খুঁজুন",
"checkuser-edits": "সম্পাদনাগুলি খুঁজুন",
- "checkuser-ips": "আইপিসমূহ খুঁজুন",
+ "checkuser-ips": "আইপি ঠিকানাসমূহ খুঁজুন",
"checkuser-period": "সময়:",
"checkuser-week-1": "পূর্ববর্তী সপ্তাহ",
"checkuser-week-2": "পূর্ববর্তী দুই সপ্তাহ",
@@ -47,14 +49,14 @@
"checkuser-recent-checks": "এই ব্যবহারকারীর জন্য সাম্প্রতিক পরীক্ষাগুলি",
"checkuser-log-fail": "লগ ভুক্তিতে যোগ করা সম্ভব হচ্ছে না",
"checkuser-nolog": "কোন লগ ফাইল পাওয়া যায়নি।",
- "checkuser-blocked": "বাধা দেওয়া হয়েছে",
- "checkuser-gblocked": "বৈশ্বিকভাবে বাধাদানকৃত",
+ "checkuser-blocked": "বাধাপ্রাপ্ত",
+ "checkuser-gblocked": "বৈশ্বিকভাবে বাধাপ্রাপ্ত",
"checkuser-locked": "অবরুদ্ধ",
"checkuser-wasblocked": "পূর্বে বাধাদানকৃত ছিলো",
"checkuser-localonly": "কোনো একত্রকীকরণ নেই",
"checkuser-massblock": "নির্বাচিত ব্যবহারকারীদের বাধা দিন",
"checkuser-massblock-text": "আইপি ঠিকানাগুলির স্বয়ংক্রিয় অবরুদ্ধ সক্রিয়করণ এবং অ্যাকাউন্ট সৃষ্টি নিষ্ক্রিয়করণ সহ, নির্বাচিত অ্যাকাউন্টগুলি অনির্দিষ্টকালের জন্য অবরুদ্ধ করা হবে।\nআইপি ঠিকানাগুলি বেনামী ব্যবহারকারীদের জন্য শুধুমাত্র এক সপ্তাহের জন্য অবরুদ্ধ হবে এবং অ্যাকাউন্ট সৃষ্টি নিষ্ক্রিয় করা হবে।",
- "checkuser-blockemail": "ই-মেইল পাঠানো থেকে বিরত রাখো",
+ "checkuser-blockemail": "ইমেইল পাঠানো থেকে বিরত রাখো",
"checkuser-blocktalk": "বাধা থাকা অবস্থায় তাদের নিজস্ব আলাপ পাতা সম্পাদনা করা থেকে বিরত রাখো",
"checkuser-blocktag": "যেটির মাধ্যমে ব্যবহারকারী পাতা প্রতিস্থাপন করবেন:",
"checkuser-blocktag-talk": "যেটির মাধ্যমে আলাপ পাতা প্রতিস্থাপন করবেন:",
@@ -63,29 +65,78 @@
"checkuser-block-failure": "'''বাধাদানকৃত কোনো ব্যবহারকারী নেই।'''",
"checkuser-block-limit": "অনেক বেশি ব্যবহারকারী নির্বাচিত করা হয়েছে।",
"checkuser-block-noreason": "আপনাকে অবশ্যই এই বাধাদানের জন্য একটি কারণ উল্লেখ করতে হবে।",
+ "checkuser-centralauth-multilock": "নির্বাচিত অ্যাকাউন্টগুলি বহু তালাবদ্ধ করুন",
"checkuser-noreason": "আপনাকে অবশ্যই এই কোয়েরির জন্য একটি কারণ উল্লেখ করতে হবে।",
- "checkuser-accounts": "$1টি নতুন {{PLURAL:$1|অ্যাকাউন্ট}}",
- "checkuser-too-many": "অত্যধিক সংখ্যক ফলাফল (অনুসন্ধান হিসাব অনুযায়ী), অনুগ্রহ করে CIDR সীমিত করুন। নিচের আইপি ঠিকানাগুলি ব্যবহৃত হয়েছে (সর্বোচ্চ ৫০০০, ঠিকানা অনুযায়ী বিন্যস্ত):",
+ "checkuser-too-many": "অত্যধিক সংখ্যক ফলাফল (অনুসন্ধান হিসাব অনুযায়ী), অনুগ্রহ করে CIDR সীমিত করুন। নিচের আইপি ঠিকানাগুলি ব্যবহৃত হয়েছে (সর্বোচ্চ $1, ঠিকানা অনুযায়ী বিন্যস্ত):",
"checkuser-user-nonexistent": "এই নির্দিষ্ট ব্যবহারকারী নেই।",
"checkuser-search": "ব্যবহারকারী পরীক্ষণের ভুক্তিতে খুঁজুন",
"checkuser-search-submit": "অনুসন্ধান",
"checkuser-search-initiator": "আরম্ভকারী",
"checkuser-search-target": "লক্ষ্য",
"checkuser-log-search-target": "লক্ষ্য:",
- "checkuser-log-search-type": "কর্তৃক অনুসন্ধান:",
- "checkuser-ipeditcount": "সকল ব্যবহারকারী থেকে ~$1টি",
+ "checkuser-log-search-type": "অনুসন্ধান করুন এই অনুসারে:",
+ "checkuser-ipeditcount": "সকল ব্যবহারকারী মিলিয়ে ~$1টি",
"checkuser-showmain": "CheckUser মূল ফর্মে ফেরত যান",
- "checkuser-limited": "'''এসব ফলাফল কর্মক্ষমতা কারণে ছেঁটে ফেলা হয়েছে।'''",
+ "checkuser-limited": "'''এসব ফলাফল কর্মক্ষমতার কারণে ছেঁটে ফেলা হয়েছে।'''",
"checkuser-log-entry-userips": "$3, $1 $2-এর জন্য আইপি ঠিকানাগুলি পেয়েছেন",
- "checkuser-log-entry-ipedits": "$3, $1 $2-এর জন্য সম্পাদনাগুলি পেয়েছেন",
- "checkuser-log-entry-ipusers": "$3, $1 $2-এর জন্য ব্যবহারকারীগুলি পেয়েছেন",
- "checkuser-log-entry-ipedits-xff": "$3, $1 XFF $2-এর জন্য সম্পাদনাগুলি পেয়েছেন",
- "checkuser-log-entry-ipusers-xff": "$3, $1 XFF $2-এর জন্য ব্যবহারকারীগুলি পেয়েছেন",
+ "checkuser-log-entry-ipedits": "$3, $1 <bdi>$2</bdi>-এর জন্য সম্পাদনাগুলি পেয়েছেন",
+ "checkuser-log-entry-ipusers": "$3, $1 <bdi>$2</bdi>-এর জন্য ব্যবহারকারীগুলি পেয়েছেন",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 XFF <bdi>$2</bdi>-এর জন্য সম্পাদনাগুলি পেয়েছেন",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 XFF <bdi>$2</bdi>-এর জন্য ব্যবহারকারীগুলি পেয়েছেন",
"checkuser-log-entry-useredits": "$3, $1 $2-এর জন্য সম্পাদনাগুলি পেয়েছেন",
"checkuser-autocreate-action": "স্বয়ংক্রিয়ভাবে তৈরি হয়েছিলো",
"checkuser-create-action": "তৈরি করা হয়েছে",
- "checkuser-email-action": "ব্যবহারকারী \"$1\" কে একটি ই-মেইল পাঠিয়েছে",
+ "checkuser-email-action": "ব্যবহারকারী \"$1\" কে একটি ইমেইল পাঠিয়েছে",
"checkuser-reset-action": "ব্যবহারকারী \"$1\"-এর জন্য পাসওয়ার্ড পুনঃস্থাপন করো",
"checkuser-token-fail": "সেশন ব্যর্থতা। অনুগ্রহপূর্বক আবার চেষ্টা করুন।",
- "apihelp-query+checkuser-param-reason": "পরীক্ষার কারণ।"
+ "checkuser-login-failure": "$1 হিসেবে {{SITENAME}}-এ প্রবেশ করতে ব্যর্থ",
+ "checkuser-login-success": "$1 হিসেবে {{SITENAME}}-এ প্রবেশ সফল হয়েছে",
+ "checkuser-investigateblock-target": "ব্যবহারকারী নাম বা আইপি ঠিকানা",
+ "checkuser-investigateblock-actions": "যেটি থেকে অবরুদ্ধ করা হবে",
+ "checkuser-investigateblock-options": "অতিরিক্ত বিকল্প",
+ "checkuser-investigateblock-notice-talk-page-label": "ব্যবহারকারীর আলাপ পাতায় একটি বিজ্ঞপ্তি দিন",
+ "checkuser-investigateblock-notice-position-label": "অবস্থান",
+ "checkuser-investigateblock-notice-text-label": "উইকিপাঠ্য",
+ "checkuser-investigateblock-notice-append": "পাতায় যোগ করুন",
+ "checkuser-investigateblock-notice-prepend": "পাতার শীর্ষে যোগ করুন",
+ "checkuser-investigateblock-notice-replace": "পাতা প্রতিস্থাপন করুন",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|ব্যবহারকারী}} $1 এখন বাধাপ্রাপ্ত।",
+ "checkuser-investigateblock-notices-failed": "কিছু বিজ্ঞপ্তি ব্যবহারকারীর পাতাগুলি বা আলাপ পাতাগুলিতে যোগ করা যায়নি।",
+ "checkuser-investigate": "তদন্ত করুন",
+ "checkuser-investigate-subtitle-block-button-label": "বাধা দিন",
+ "checkuser-investigate-subtitle-cancel-button-label": "বাতিল",
+ "checkuser-investigate-subtitle-continue-button-label": "অব্যাহত",
+ "checkuser-investigate-indicator-logs": "লগ",
+ "checkuser-investigate-legend": "ব্যবহারকারীর নামগুলি, আইপি ঠিকানাগুলি বা আইপি পরিসীমাগুলির জন্য অনুসন্ধান করুন",
+ "checkuser-investigate-tab-preliminary-check": "অ্যাকাউন্টের তথ্য",
+ "checkuser-investigate-tab-compare": "আইপি ও ব্যবহারকারী এজেন্ট",
+ "checkuser-investigate-tab-timeline": "সময়ক্রম",
+ "checkuser-investigate-targets-label": "ব্যবহারকারী নামগুলি বা আইপি ঠিকানাগুলি",
+ "checkuser-investigate-targets-placeholder": "ব্যবহারকারী নাম বা 1.1.1.1",
+ "checkuser-investigate-duration-label": "স্থিতিকাল",
+ "checkuser-investigate-duration-option-all": "সমস্ত",
+ "checkuser-investigate-duration-option-1w": "গত সপ্তাহ",
+ "checkuser-investigate-duration-option-2w": "গত ২ সপ্তাহ",
+ "checkuser-investigate-duration-option-30d": "গত ৩০ দিন",
+ "checkuser-investigate-reason-label": "কারণ",
+ "checkuser-investigate-preliminary-table-cell-blocked": "বাধাপ্রাপ্ত",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1টি {{PLURAL:$1|সম্পাদনা}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "বাধাপ্রাপ্ত নয়",
+ "checkuser-investigate-preliminary-table-header-blocked": "অবস্থা",
+ "checkuser-investigate-preliminary-table-header-editcount": "সম্পাদনা",
+ "checkuser-investigate-preliminary-table-header-groups": "দল",
+ "checkuser-investigate-preliminary-table-header-name": "ব্যবহারকারী নাম",
+ "checkuser-investigate-preliminary-table-header-wiki": "উইকি",
+ "checkuser-investigate-filters-legend": "ছাঁকনি",
+ "checkuser-investigate-compare-copy-button-label": "উইকিপাঠ্য দেখান",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "এই ব্যবহারকারীর সমস্ত আইপি দেখান",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "এই আইপির সমস্ত ব্যবহারকারীকে দেখান",
+ "checkuser-investigate-compare-table-button-filter-label": "ফলাফল থেকে ছাঁকুন",
+ "checkuser-investigate-compare-table-cell-unregistered": "অনিবন্ধিত",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|সম্পাদনা|সম্পাদনাগুলি}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(সকল ব্যবহারকারী মিলিয়ে ~$1টি)</i>",
+ "checkuser-investigate-compare-table-header-username": "ব্যবহারকারী নাম",
+ "checkuser-investigate-compare-table-header-activity": "তারিখের পরিসীমা",
+ "checkuser-investigate-compare-table-header-ip": "আইপি",
+ "checkuser-investigate-compare-table-header-useragent": "ব্যবহারকারী এজেন্ট"
}
diff --git a/CheckUser/i18n/br.json b/CheckUser/i18n/br.json
index 6a31ab8f..fc2cbee3 100644
--- a/CheckUser/i18n/br.json
+++ b/CheckUser/i18n/br.json
@@ -3,6 +3,7 @@
"authors": [
"Fohanno",
"Fulup",
+ "Huñvreüs",
"Y-M D"
]
},
@@ -13,7 +14,7 @@
"checkuserlog": "Marilh kontrolliñ an implijerien",
"checkuser-contribs": "gwiriañ chomlec'hioù IP an implijer",
"checkuser-contribs-log": "Gwiriadennoù diwezhañ diwar-benn an implijer-mañ",
- "group-checkuser": "Gwiriañ an implijerien",
+ "group-checkuser": "Gwirierien an implijerien",
"group-checkuser-member": "{{GENDER:$1|gwirier implijerien|gwirierez implijerien}}",
"right-checkuser": "Gwiriañ chomlec'hioù IP ha titouroù all an implijer",
"right-checkuser-log": "Gwelet marilh gwiriekadurioù an implijerien",
@@ -56,7 +57,6 @@
"checkuser-block-limit": "Re a implijerien diuzet.",
"checkuser-block-noreason": "Ret eo deoc'h reizhabegiñ ar stankadennoù.",
"checkuser-noreason": "Ret eo deoc'h reizhabegiñ an enklask-mañ.",
- "checkuser-accounts": "$1 {{PLURAL:$1|kont|kont}} nevez",
"checkuser-too-many": "Re a zisoc'hoù (hervez istimadur ar reked), strishaat ar CIDR mar plij.\nSetu an IPoù implijet (5000 d'ar muiañ, urzhiet dre ar chomlec'h) :",
"checkuser-user-nonexistent": "N'eus ket eus an implijer merket",
"checkuser-search": "Klask",
@@ -69,5 +69,10 @@
"checkuser-autocreate-action": "zo bet krouet ent emgefre",
"checkuser-create-action": "zo bet krouet",
"checkuser-email-action": "en deus kaset ur postel d'an implijer « $1 »",
- "checkuser-reset-action": "adderaouekaat a ra ger-tremen an implijer \"$1\""
+ "checkuser-reset-action": "adderaouekaat a ra ger-tremen an implijer \"$1\"",
+ "checkuser-investigate-indicator-logs": "Marilhoù",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "N'eo ket bet kavet ar wiki",
+ "checkuser-investigate-compare-notice-no-results": "N'eus disoc'h ebet : an implijerien pe IPoù-se n'o deus graet kemm ebet e-kerzh an 90 deiz diwezhañ.",
+ "checkuser-investigate-compare-notice-no-results-filters": "Disoc'h ebet ne glot gant an dezverkoù silañ-mañ. Dilamit siloù zo evit ledanaat ar c'hlask.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Diskouez holl implijerien an IP-mañ"
}
diff --git a/CheckUser/i18n/bs.json b/CheckUser/i18n/bs.json
index 84b7668b..8b7c5e45 100644
--- a/CheckUser/i18n/bs.json
+++ b/CheckUser/i18n/bs.json
@@ -3,8 +3,9 @@
"authors": [
"CERminator",
"KWiki",
+ "Semso98",
"Srdjan m",
- "Semso98"
+ "Srđan"
]
},
"checkuser-summary": "Ovaj alat skenira nedavne promjene te vraća IP adrese koje koriste korisnici ili prikazuje podatke o izmjenama i korisnicima za pojedinu IP adresu.\nKorisnici i izmjene nekog IP klijenta mogu biti nađene preko XFF zaglavlja uz primjenu oznake \"/xff\" pored IP-a. Podržani su i IPv4 (CIDR $1-32) i IPv6 (CIDR $2-128).\nZbog boljih performansi, neće biti prikazano više od 5000 izmjena.\nKoristite ovo u skladu s pravilima.",
@@ -56,7 +57,6 @@
"checkuser-block-limit": "Previše korisnika odabrano.",
"checkuser-block-noreason": "Morate navesti razlog za blokiranje.",
"checkuser-noreason": "Morate navesti razlog za ovaj upit.",
- "checkuser-accounts": "$1 {{PLURAL:$1|novi korisnik|nova korisnika|novih korisnika}}",
"checkuser-too-many": "Pronađeno previše rezultata (po procjeni upita), suzite CIDR.\nOvdje su prikazane korištene IP-adrese (najviše 5000, poredano po adresi):",
"checkuser-user-nonexistent": "Navedeni korisnik ne postoji.",
"checkuser-search": "Pretraži unose u zapisniku provjeravača",
@@ -69,7 +69,5 @@
"checkuser-autocreate-action": "je automatski napravljen",
"checkuser-create-action": "je napravljen",
"checkuser-email-action": "slanje e-mail korisniku \"$1\"",
- "checkuser-reset-action": "poništi šifru za korisnika \"$1\"",
- "apihelp-query+checkuser-param-timecond": "Vremensko ograničenje za korisničke podatke (npr, \"-2 weeks\" ili \"2 weeks ago\").",
- "apierror-checkuser-timelimit": "Morate koristiti ispravno vremensko ograničenje (npr, \"-2 weeks\" ili \"2 weeks ago\")."
+ "checkuser-reset-action": "poništi šifru za korisnika \"$1\""
}
diff --git a/CheckUser/i18n/ca.json b/CheckUser/i18n/ca.json
index 36d8efe2..eea3ca9a 100644
--- a/CheckUser/i18n/ca.json
+++ b/CheckUser/i18n/ca.json
@@ -6,9 +6,12 @@
"Arnaugir",
"Chaduvari",
"El libre",
+ "Fitoschido",
"Grondin",
+ "Jlrb+",
"Jordi Roqué",
"Juanpabl",
+ "Mguix",
"Papapep",
"Paucabot",
"Pitort",
@@ -31,7 +34,7 @@
"grouppage-checkuser": "{{ns:project}}:Verificador de comptes d'usuari",
"checkuser-reason": "Motiu:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Mostra registre",
+ "checkuser-showlog": "Canviar al registre de CheckUser",
"checkuser-query": "Cerca als canvis recents",
"checkuser-target": "Adreça IP o nom d'usuari:",
"checkuser-users": "Retorna els usuaris",
@@ -65,10 +68,9 @@
"checkuser-block-limit": "Massa usuaris seleccionats.",
"checkuser-block-noreason": "Heu d'indicar un motiu pels blocatges.",
"checkuser-noreason": "Heu de donar un motiu per a executar aquesta consulta.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nou compte|nous comptes}}",
- "checkuser-too-many": "Hi ha massa resultats (d'acord amb l'estimació de la consulta), cal que useu un CIDR més petit.\nAquí teniu les IP usades (màx. 5000 ordenades per adreça):",
+ "checkuser-too-many": "Hi ha massa resultats (d'acord amb l'estimació de la consulta), cal que useu un CIDR més petit.\nAquí teniu les IP usades (màx. $1, ordenades per adreça):",
"checkuser-user-nonexistent": "L'usuari especificat no existeix.",
- "checkuser-search": "Cerca",
+ "checkuser-search": "Cerca les entrades de registre de comprovació d'usuari",
"checkuser-search-submit": "Cerca",
"checkuser-search-initiator": "l'iniciador",
"checkuser-search-target": "el consultat",
@@ -78,5 +80,9 @@
"checkuser-autocreate-action": "fou automàticament creat",
"checkuser-create-action": "va ser creat",
"checkuser-email-action": "S'ha enviat un missatge de correu electrònic a {{GENDER:$1|l'usuari|la usuària}} $1",
- "checkuser-reset-action": "reinicia la contrasenya de l'usuari «$1»"
+ "checkuser-reset-action": "reinicia la contrasenya de l'usuari «$1»",
+ "checkuser-link-investigate-label": "Provi la nova eina CheckUser",
+ "checkuser-investigate-log": "Registres de recerca",
+ "checkuser-investigate-log-empty": "No s’ha trobat cap registre de recerca",
+ "checkuser-investigate-tour-addusertargets-title": "Necessiteu més context?"
}
diff --git a/CheckUser/i18n/ce.json b/CheckUser/i18n/ce.json
index 92c99a21..b4cce00b 100644
--- a/CheckUser/i18n/ce.json
+++ b/CheckUser/i18n/ce.json
@@ -27,11 +27,12 @@
"checkuser-week-2": "тӀаьххьара ши кӀира",
"checkuser-month": "тӀаьххьара 30 де",
"checkuser-all": "массо",
+ "checkuser-nomatch": "ХӀума цакарина",
"checkuser-nomatch-edits": "Цакарий.\nТӀеххьара нисдар дина $1 $2.",
"checkuser-check": "Хьажа",
"checkuser-log-fail": "Цатарло тептар тӀе дӀаяздар тӀоха",
"checkuser-blocked": "Блоктоьхна",
- "checkuser-gblocked": "Глобальни блоктоьхна",
+ "checkuser-gblocked": "Глобалан блоктоьхна",
"checkuser-locked": "Блоктоьхна",
"checkuser-block-success": "'''ХӀинца {{PLURAL:$2|1=блоктоьхна $1 декъашхочун|блоктоьхна $1 декъашхойн}}.'''",
"checkuser-search": "Лахар",
@@ -39,5 +40,7 @@
"checkuser-search-target": "Ӏалашо",
"checkuser-log-search-target": "Ӏалашо:",
"checkuser-log-search-type": "Лахар:",
- "checkuser-create-action": "кхолийна"
+ "checkuser-create-action": "кхолийна",
+ "checkuser-investigateblock": "Блоктоьхна декъашхой",
+ "checkuser-investigateblock-notice-text-label": "Викийоза"
}
diff --git a/CheckUser/i18n/ckb.json b/CheckUser/i18n/ckb.json
index 35b98be3..3151bb3d 100644
--- a/CheckUser/i18n/ckb.json
+++ b/CheckUser/i18n/ckb.json
@@ -1,8 +1,10 @@
{
"@metadata": {
"authors": [
+ "Asoxor",
"Calak",
- "Asoxor"
+ "Cwtiyar",
+ "ئارام بکر"
]
},
"group-checkuser": "پشکنەرانی بەکارھێنەر",
@@ -41,10 +43,15 @@
"checkuser-block-limit": "ژمارەیەکی زۆر لە بەکارھێنەران ھەڵبژێردراوە.",
"checkuser-block-noreason": "دەبێ ھۆکارێک بۆ بەرەبەستنەکان بخەیە ڕوو.",
"checkuser-noreason": "دەبێ ھۆکارێک بۆ ئەم پرسە بخەیە ڕوو.",
- "checkuser-accounts": "$1 {{PLURAL:$1|ھەژمار}}ی نوێ",
"checkuser-too-many": "ژمارەی ئاکامەکان یەکجار زۆرە (بە پێی بەراوردی پرسەکە)، تکایە CIDR بەرتەسک بکەوە.\nئەمانە ئایپییە بەکارھێنراوەکانن (ئەو پەڕی ٥٠٠٠، ڕیزکراو بە ناونیشان):",
"checkuser-user-nonexistent": "بەکارھێنەری دەستنیشان کراوە بوونی نییە.",
"checkuser-search": "گەڕان",
"checkuser-search-submit": "گەڕان",
- "checkuser-search-target": "مەبەست"
+ "checkuser-search-target": "مەبەست",
+ "checkuser-investigate-duration-label": "ماوە",
+ "checkuser-investigate-duration-option-all": "هەمووی",
+ "checkuser-investigate-duration-option-1w": "ھەفتەی پێشوو",
+ "checkuser-investigate-duration-option-2w": "کۆتا ٢ هەفتە",
+ "checkuser-investigate-duration-option-30d": "٣٠ ڕۆژ لەمەو پێش",
+ "checkuser-investigate-preliminary-table-header-blocked": "ڕەوش"
}
diff --git a/CheckUser/i18n/co.json b/CheckUser/i18n/co.json
index 47551e1b..a0808a5b 100644
--- a/CheckUser/i18n/co.json
+++ b/CheckUser/i18n/co.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"group-checkuser": "Controllori",
"group-checkuser-member": "Controllore",
"grouppage-checkuser": "{{ns:project}}:Controllori"
diff --git a/CheckUser/i18n/cs.json b/CheckUser/i18n/cs.json
index e1958ec6..fbe3ace8 100644
--- a/CheckUser/i18n/cs.json
+++ b/CheckUser/i18n/cs.json
@@ -3,7 +3,9 @@
"authors": [
"Beren",
"Danny B.",
+ "Dvorapa",
"Li-sung",
+ "Matěj Suchánek",
"Mormegil"
]
},
@@ -62,8 +64,7 @@
"checkuser-block-noreason": "Musíte zadat důvod blokování",
"checkuser-centralauth-multilock": "Hromadně zamknout vybrané účty",
"checkuser-noreason": "K tomuto dotazu musíte uvést důvod.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nový účet|nové účty|nových účtů}}",
- "checkuser-too-many": "Příliš mnoho výsledků (podle odhadu dotazu), zkuste omezit CIDR.\nNíže jsou použité IP adresy (nejvýše 5000, seřazené podle adresy):",
+ "checkuser-too-many": "Příliš mnoho výsledků (podle odhadu dotazu), zkuste omezit CIDR.\nNíže jsou použité IP adresy (nejvýše $1, seřazené podle adresy):",
"checkuser-user-nonexistent": "Zadaný uživatel neexistuje.",
"checkuser-search": "Hledání v záznamech kontroly uživatelů",
"checkuser-search-submit": "Hledat",
@@ -75,10 +76,10 @@
"checkuser-showmain": "Přepnout na hlavní formulář Kontroly uživatele",
"checkuser-limited": "'''Výsledky byly z výkonnostních důvodů zkráceny.'''",
"checkuser-log-entry-userips": "$3, $1 zjišťuje IP adresy uživatele $2",
- "checkuser-log-entry-ipedits": "$3, $1 zjišťuje editace z $2",
- "checkuser-log-entry-ipusers": "$3, $1 zjišťuje uživatele z $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 zjišťuje editace s XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 zjišťuje uživatele s XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 zjišťuje editace z <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 zjišťuje uživatele z <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 zjišťuje editace s XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 zjišťuje uživatele s XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 zjišťuje editace uživatele $2",
"checkuser-autocreate-action": "byl automaticky vytvořen",
"checkuser-create-action": "byl vytvořen",
@@ -86,5 +87,7 @@
"checkuser-reset-action": "požádal o nové heslo pro uživatele „$1“",
"checkuser-token-fail": "Chyba relace. Zkuste to prosím znovu.",
"checkuser-login-failure": "Neúspěšný pokus o přihlášení do {{grammar:2sg|{{SITENAME}}}} jako $1",
- "checkuser-login-success": "Úspěšné přihlášení do {{grammar:2sg|{{SITENAME}}}} jako $1"
+ "checkuser-login-success": "Úspěšné přihlášení do {{grammar:2sg|{{SITENAME}}}} jako $1",
+ "group-checkuser.css": "/* Zde uvedené CSS bude ovlivňovat pouze revizory */",
+ "group-checkuser.js": "/* Zde uvedený JavaScript bude použit pouze pro revizory */"
}
diff --git a/CheckUser/i18n/csb.json b/CheckUser/i18n/csb.json
index 18ea19d4..15ea81e7 100644
--- a/CheckUser/i18n/csb.json
+++ b/CheckUser/i18n/csb.json
@@ -2,8 +2,8 @@
"@metadata": {
"authors": [
"Byulent",
- "Kirsan",
- "Kaszeba"
+ "Kaszeba",
+ "Kirsan"
]
},
"checkuser-all": "wszëtczé",
diff --git a/CheckUser/i18n/cy.json b/CheckUser/i18n/cy.json
index 9a8cc36c..6fef7aa5 100644
--- a/CheckUser/i18n/cy.json
+++ b/CheckUser/i18n/cy.json
@@ -55,7 +55,6 @@
"checkuser-block-limit": "Dewiswyd gormod o ddefnyddwyr.",
"checkuser-block-noreason": "Rhaid cynnig rheswm dros y blociau.",
"checkuser-noreason": "Rhaid cynnig rheswm dros yr ymholiad hwn.",
- "checkuser-accounts": "$1 {{PLURAL:$1|cyfrif|cyfrif|gyfrif|chyfrif|chyfrif|cyfrif}} newydd",
"checkuser-too-many": "Mae gormod o lawer o ganlyniadau (yn ôl amcangyfrif yr ymholiad), cyfyngwch y CIDR. Dyma'r IPau a ddefnyddiwyd (hyd at 5000 ohonynt, yn nhrefn y cyfeiriadau):",
"checkuser-user-nonexistent": "Nid yw'r defnyddiwr a enwyd ar gael.",
"checkuser-search": "Chwiliwch a gwirwch logiau'r defnyddiwr",
diff --git a/CheckUser/i18n/da.json b/CheckUser/i18n/da.json
index 706c4797..304ddfff 100644
--- a/CheckUser/i18n/da.json
+++ b/CheckUser/i18n/da.json
@@ -3,6 +3,7 @@
"authors": [
"Amjaabc",
"Byrial",
+ "Cgtdk",
"Christian List",
"Emilkris33",
"Fredelige",
@@ -10,8 +11,8 @@
"Masz",
"Morten LJ",
"Peter Alberti",
- "Sarrus",
- "Cgtdk"
+ "Saederup92",
+ "Sarrus"
]
},
"checkuser-summary": "Dette værktøj scanner Seneste ændringer for at finde IP'er brugt af en bestemt bruger, eller for at vise redigerings- eller brugerdata for en IP.\nBruger og redigeringer fra en klient-IP kan hentes via XFF-headers ved at tilføje \"/xff\" til IP'en. Ipv4 (CIRD $1-32) og IPv6 (CIDR $2-128) er understøttet.\nFor at sikre programmelets ydeevne kan maksimalt 5000 redigeringer returneres. Brug kun dette værktøj i overensstemmelse med gældende politiker på {{SITENAME}}.",
@@ -68,7 +69,6 @@
"checkuser-block-limit": "Der er valgt for mange brugere.",
"checkuser-block-noreason": "Du skal angive en blokeringsgrund.",
"checkuser-noreason": "Du skal angive en begrundelse for denne forespørgsel.",
- "checkuser-accounts": "$1 {{PLURAL:$1|ny konto|nye kontoer}}",
"checkuser-too-many": "For mange resultater, gør CIDR'en mindre. Her er de brugte IP'er (maks. 5000, sorteret efter adresse):",
"checkuser-user-nonexistent": "Den anførte bruger eksisterer ikke.",
"checkuser-search": "Søg i tjekbrugerloggen",
@@ -76,6 +76,7 @@
"checkuser-search-initiator": "initiativtager",
"checkuser-search-target": "mål",
"checkuser-log-search-target": "Mål:",
+ "checkuser-log-search-type": "Søg efter:",
"checkuser-ipeditcount": "~$1 fra alle brugere",
"checkuser-showmain": "Gå til hovedformularen for tjekbruger",
"checkuser-limited": "'''Disse resultater er blevet afkortet af hensyn til ydeevnen.'''",
@@ -84,8 +85,38 @@
"checkuser-email-action": "sendte en e-mail til \"$1\"",
"checkuser-reset-action": "nulstillede adgangskoden for \"$1\"",
"checkuser-token-fail": "Sessionsfejl. Prøv venligst igen.",
- "apihelp-query+checkuser-param-target": "Brugernavn, ip-adresse eller CIDR-interval at tjekke.",
- "apihelp-query+checkuser-param-reason": "Begrundelse for tjek.",
- "apihelp-query+checkuser-example-2": "Tjek redigeringer fra 192.0.2.0/24",
- "apierror-checkuser-missingsummary": "Du skal angive en begrundelse for tjekket."
+ "checkuser-investigateblock": "Bloker brugere",
+ "checkuser-investigateblock-target": "Brugernavne og IP-adresser",
+ "checkuser-investigateblock-reason": "Årsag",
+ "checkuser-investigateblock-email-label": "Spær brugerens adgang til at sende e-mail",
+ "checkuser-investigateblock-notice-text-label": "Wikitekst",
+ "checkuser-investigateblock-notice-replace": "Erstat side",
+ "checkuser-investigate": "Undersøg",
+ "checkuser-investigate-page-subtitle": "Igangværende undersøgelse af $1",
+ "checkuser-investigate-subtitle-block-button-label": "Blokér",
+ "checkuser-investigate-subtitle-cancel-button-label": "Annullér",
+ "checkuser-investigate-subtitle-continue-button-label": "Fortsæt",
+ "checkuser-investigate-indicator-new-investigation": "Ny undersøgelse",
+ "checkuser-investigate-tab-compare": "Sammenlign",
+ "checkuser-investigate-tab-timeline": "Tidslinje",
+ "checkuser-investigate-targets-label": "Brugernavne og IP-adresser",
+ "checkuser-investigate-targets-placeholder": "Brugernavn eller 1.1.1.1",
+ "checkuser-investigate-duration-label": "Varighed",
+ "checkuser-investigate-duration-option-all": "Alle",
+ "checkuser-investigate-duration-option-1w": "Sidste uge",
+ "checkuser-investigate-duration-option-2w": "Sidste 2 uger",
+ "checkuser-investigate-duration-option-30d": "Sidste 30 dage",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Blokeret",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|redigering|redigeringer}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Ikke blokeret",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Redigeringer",
+ "checkuser-investigate-preliminary-table-header-groups": "Grupper",
+ "checkuser-investigate-preliminary-table-header-name": "Brugernavn",
+ "checkuser-investigate-filters-legend": "Filtre",
+ "checkuser-investigate-compare-copy-button-label": "Vis wikitekst",
+ "checkuser-investigate-compare-table-button-contribs-label": "Bidrag",
+ "checkuser-investigate-compare-table-header-username": "Brugernavn",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-tour-addusertargets-title": "Har du brug for mere kontekst?"
}
diff --git a/CheckUser/i18n/de.json b/CheckUser/i18n/de.json
index f11faebb..b51f3dde 100644
--- a/CheckUser/i18n/de.json
+++ b/CheckUser/i18n/de.json
@@ -1,18 +1,20 @@
{
"@metadata": {
"authors": [
+ "FF11",
"Geitost",
+ "J. 'mach' wust",
"Kghbln",
+ "Luke081515",
"MF-Warburg",
+ "McDutchie",
"Metalhead64",
"Pill",
"Purodha",
"Raimond Spekking",
- "Umherirrender",
- "Luke081515",
"Tiin",
- "J. 'mach' wust",
- "McDutchie"
+ "Tobi 406",
+ "Umherirrender"
]
},
"checkuser-summary": "Dieses Werkzeug durchsucht die letzten Änderungen, um die IP-Adressen eines Benutzers bzw. die Bearbeitungen/Benutzernamen für eine IP-Adresse zu ermitteln. Benutzer und Bearbeitungen einer IP-Adresse können auch nach Informationen aus den XFF-Headern abgefragt werden, indem der IP-Adresse ein „/xff“ angehängt wird. IPv4 (CIDR $1-32) und IPv6 (CIDR $2-128) werden unterstützt.\nZur Aufrechterhaltung der Leistungsfähigkeit werden maximal 5000 Bearbeitungen ausgegeben. Benutze CheckUser ausschließlich in Übereinstimmung mit den Datenschutzrichtlinien.",
@@ -63,6 +65,7 @@
"checkuser-blocktalk": "Vom Bearbeiten der eigenen Diskussionsseite abhalten, während der Benutzer gesperrt ist.",
"checkuser-blocktag": "Inhalt der Benutzerseiten ersetzen durch:",
"checkuser-blocktag-talk": "Inhalt der Benutzerdiskussionsseiten ersetzen durch:",
+ "checkuser-reblock": "Bestehende Sperren überschreiben",
"checkuser-massblock-commit": "Ausgewählte Benutzer sperren",
"checkuser-block-success": "'''{{PLURAL:$2|Der Benutzer|Die Benutzer}} $1 {{PLURAL:$2|wurde|wurden}} gesperrt.'''",
"checkuser-block-failure": "'''Es wurden keine Benutzer gesperrt.'''",
@@ -70,8 +73,7 @@
"checkuser-block-noreason": "Du musst einen Grund für die Sperre angeben.",
"checkuser-centralauth-multilock": "Ausgewählte Benutzerkonten sperren",
"checkuser-noreason": "Für diese Abfrage muss eine Begründung angegeben werden.",
- "checkuser-accounts": "$1 {{PLURAL:$1|neues Benutzerkonto|neue Benutzerkonten}}",
- "checkuser-too-many": "Die Ergebnisliste ist zu lang (nach Schätzung der Abfrage). Bitte grenze den IP-Adressbereich weiter ein.\nEs folgen die benutzten IP-Adressen (maximal 5000, sortiert nach Adresse):",
+ "checkuser-too-many": "Die Ergebnisliste ist zu lang (nach Schätzung der Abfrage). Bitte grenze den IP-Adressbereich weiter ein.\nEs folgen die benutzten IP-Adressen (maximal $1, sortiert nach Adresse):",
"checkuser-user-nonexistent": "Das angegebene Benutzerkonto ist nicht vorhanden.",
"checkuser-search": "Einträge im Checkuser-Logbuch durchsuchen",
"checkuser-search-submit": "Suche",
@@ -83,10 +85,10 @@
"checkuser-showmain": "Zum CheckUser-Hauptformular wechseln",
"checkuser-limited": "'''Die Ergebnisliste wurde zur Aufrechterhaltung der Leistungsfähigkeit gekürzt.'''",
"checkuser-log-entry-userips": "$1 rief am $3 die IP-Adressen für $2 ab",
- "checkuser-log-entry-ipedits": "$1 rief am $3 die Bearbeitungen für $2 ab",
- "checkuser-log-entry-ipusers": "$1 rief am $3 die Benutzer für $2 ab",
- "checkuser-log-entry-ipedits-xff": "$1 rief am $3 die Bearbeitungen für XFF $2 ab",
- "checkuser-log-entry-ipusers-xff": "$1 rief am $3 die Benutzer für XFF $2 ab",
+ "checkuser-log-entry-ipedits": "$1 rief am $3 die Bearbeitungen für <bdi>$2</bdi> ab",
+ "checkuser-log-entry-ipusers": "$1 rief am $3 die Benutzer für <bdi>$2</bdi> ab",
+ "checkuser-log-entry-ipedits-xff": "$1 rief am $3 die Bearbeitungen für XFF <bdi>$2</bdi> ab",
+ "checkuser-log-entry-ipusers-xff": "$1 rief am $3 die Benutzer für XFF <bdi>$2</bdi> ab",
"checkuser-log-entry-useredits": "$1 rief am $3 die Bearbeitungen für $2 ab",
"checkuser-autocreate-action": "wurde automatisch erstellt",
"checkuser-create-action": "wurde erstellt",
@@ -95,25 +97,94 @@
"checkuser-token-fail": "Sitzungsfehler. Bitte erneut versuchen.",
"checkuser-login-failure": "Anmeldung bei {{SITENAME}} als $1 fehlgeschlagen",
"checkuser-login-success": "Erfolgreich bei {{SITENAME}} angemeldet als $1",
- "apihelp-query+checkuser-description": "Überprüfen, welche IP-Adressen durch einen bestimmten Benutzernamen oder welche Benutzernamen von einer bestimmten IP-Adresse verwendet werden.",
- "apihelp-query+checkuser-param-request": "Art der CheckUser-Anfrage:\n;userips:Ermittelt die IP-Adresse des Ziel-Benutzers.\n;edits:Ermittelt Änderungen der Ziel-IP-Adresse oder des Adressbereichs.\n;ipusers:Ermittelt den Benutzer der Ziel-IP-Adresse oder des Adressbereichs.",
- "apihelp-query+checkuser-param-target": "Zu überprüfender Benutzername, CIDR-Bereich oder zu überprüfende IP-Adresse.",
- "apihelp-query+checkuser-param-reason": "Grund für die Überprüfung.",
- "apihelp-query+checkuser-param-limit": "Zeilenlimit.",
- "apihelp-query+checkuser-param-timecond": "Zeitlimit der Benutzerdaten (wie „-2 weeks“ oder „2 weeks ago“).",
- "apihelp-query+checkuser-param-xff": "XFF-Daten anstelle der IP-Adresse verwenden.",
- "apihelp-query+checkuser-example-1": "IP-Adressen für [[User:Example]] überprüfen",
- "apihelp-query+checkuser-example-2": "Bearbeitungen von 192.0.2.0/24 überprüfen",
- "apihelp-query+checkuserlog-description": "Einträge aus dem CheckUser-Logbuch abrufen.",
- "apihelp-query+checkuserlog-summary": "Ruft Einträge aus dem Checkuser-Logbuch ab.",
- "apihelp-query+checkuserlog-param-user": "Benutzername des zu überprüfenden Benutzers.",
- "apihelp-query+checkuserlog-param-target": "Überprüfter Benutzer, CIDR-Bereich oder überprüfte IP-Adresse.",
- "apihelp-query+checkuserlog-param-limit": "Zeilenlimit.",
- "apihelp-query+checkuserlog-param-from": "Der Zeitstempel, bei dem die Aufzählung beginnen soll.",
- "apihelp-query+checkuserlog-param-to": "Der Zeitstempel, bei dem die Aufzählung enden soll.",
- "apihelp-query+checkuserlog-example-1": "Prüfungen von [[User:Example]] anzeigen",
- "apihelp-query+checkuserlog-example-2": "Zeigt Überprüfungen von 192.0.2.0/24 nach 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Du musst zur Überprüfung einen Grund angeben.",
- "apierror-checkuser-timelimit": "Du musst das korrekte Zeitlimit verwenden (wie „-2 weeks“ oder „2 weeks ago“).",
- "apierror-checkuser-invalidmode": "Ungültiger Abfragemodus"
+ "checkuser-link-investigate-label": "Das neue CheckUser-Tool testen",
+ "checkuser-investigateblock": "Benutzer sperren",
+ "checkuser-investigateblock-target": "Benutzernamen und IP-Adressen",
+ "checkuser-investigateblock-actions": "Zu sperrende Aktionen",
+ "checkuser-investigateblock-reason": "Grund",
+ "checkuser-investigateblock-options": "Zusätzliche Optionen",
+ "checkuser-investigateblock-email-label": "Vom Versenden von E-Mails abhalten",
+ "checkuser-investigateblock-usertalk-label": "Vom Bearbeiten der eigenen Diskussionsseite abhalten, während der Benutzer gesperrt ist.",
+ "checkuser-investigateblock-reblock-label": "Bestehende Sperren überschreiben",
+ "checkuser-investigateblock-notice-user-page-label": "Hinterlassen eine Nachricht auf der Benutzerseite",
+ "checkuser-investigateblock-notice-talk-page-label": "Hinterlassen einer Nachricht auf der Benutzerdiskussionsseite",
+ "checkuser-investigateblock-notice-position-label": "Position",
+ "checkuser-investigateblock-notice-text-label": "Wikitext",
+ "checkuser-investigateblock-notice-append": "An Seite anhängen",
+ "checkuser-investigateblock-notice-prepend": "Der Seite voranstellen",
+ "checkuser-investigateblock-notice-replace": "Seite ersetzen",
+ "checkuser-investigateblock-failure": "Es wurden keine Benutzer gesperrt. Um bestehende Sperren aufzuheben, markiere das Kästchen „{{int:checkuser-investigateblock-reblock-label}}“. Eine Sperre wird nicht außer Kraft gesetzt, wenn die neue Sperre mit der bestehenden Sperre identisch ist.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|Der Benutzer|Die Benutzer}} $1 {{PLURAL:$2|wurde|wurden}} gesperrt.",
+ "checkuser-investigateblock-notices-failed": "Einige Hinweise konnten nicht zu den Benutzerseiten oder den Benutzerdiskussionsseiten hinzugefügt werden.",
+ "checkuser-investigate-log": "Untersuchungs-Logbuch",
+ "checkuser-investigate-log-entry": "$3, $1 hat Informationen über <bdi>$2</bdi> nachgeschlagen. $4",
+ "checkuser-investigate-log-empty": "Keine Einträge im Untersuchungs-Logbuch gefunden.",
+ "checkuser-investigate-log-subtitle": "Zum Formular Untersuchung wechseln",
+ "checkuser-investigate": "Untersuchen",
+ "checkuser-investigate-page-subtitle": "Aktuelle Untersuchung für $1",
+ "checkuser-investigate-subtitle-block-button-label": "Sperren",
+ "checkuser-investigate-subtitle-cancel-button-label": "Abbrechen",
+ "checkuser-investigate-subtitle-continue-button-label": "Fortfahren",
+ "checkuser-investigate-indicator-new-investigation": "Neue Untersuchung",
+ "checkuser-investigate-indicator-logs": "Logbücher",
+ "checkuser-investigate-legend": "Suche nach Benutzernamen, IP-Adressen oder IP-Bereiche",
+ "checkuser-investigate-notice-no-results": "Es gibt keine Ergebnisse.",
+ "checkuser-investigate-tab-preliminary-check": "Benutzerkonteninformation",
+ "checkuser-investigate-tab-compare": "IP-Adresse und User Agents",
+ "checkuser-investigate-tab-timeline": "Zeitleiste",
+ "checkuser-investigate-targets-label": "Benutzernamen und IP-Adressen",
+ "checkuser-investigate-targets-placeholder": "Benutzername oder 1.1.1.1",
+ "checkuser-investigate-duration-label": "Dauer",
+ "checkuser-investigate-duration-option-all": "Alle",
+ "checkuser-investigate-duration-option-1w": "Letzte Woche",
+ "checkuser-investigate-duration-option-2w": "Letzte 2 Wochen",
+ "checkuser-investigate-duration-option-30d": "Letzte 30 Tage",
+ "checkuser-investigate-reason-label": "Grund",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Der Benutzerkonteninformations-Tab enthält keine Informationen über IPs. Siehe den <span class=\"plainlinks\">[$1 IP-Adressen- und User Agents-Tab]<span> für diese Details.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Gesperrt",
+ "checkuser-investigate-preliminary-table-cell-edits": "{{PLURAL:$1|Eine Bearbeitung|$1 Bearbeitungen}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Nicht gesperrt",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Bearbeitungen",
+ "checkuser-investigate-preliminary-table-header-groups": "Gruppen",
+ "checkuser-investigate-preliminary-table-header-name": "Benutzername",
+ "checkuser-investigate-preliminary-table-header-registration": "Datum der Anlage",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki nicht gefunden",
+ "checkuser-investigate-filters-legend": "Filter",
+ "checkuser-investigate-filters-exclude-targets-label": "Die folgenden Benutzer oder IP-Adressen verbergen",
+ "checkuser-investigate-timeline-notice-no-results": "Es gibt keine Ergebnisse: es gab in den letzten 90 Tagen keine aufgezeichneten Aktivitäten von diesen Benutzern oder IP-Adressen",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Es gibt keine Ergebnisse, die diesen Filterkriterien entsprechen. Versuche, einige Filter zu entfernen, um die Suche zu erweitern.",
+ "checkuser-investigate-compare-copy-button-label": "Zeige Wikitext",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Proxy-Prüfung",
+ "checkuser-investigate-compare-copy-message-label": "Möchtest du diese Informationen als Wikitext-Tabelle kopieren?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Aufgrund technischer Beschränkungen haben wir die Anzahl der Datensätze erreicht, die präsentiert werden können. Die Daten, die für die folgenden Ziele zurückgegeben werden, sind unvollständig: $1. Bitte versuche, weniger Ziele, ein kleineres Zeitfenster oder engere IP-Bereiche zu verwenden.",
+ "checkuser-investigate-compare-notice-no-results": "Es gibt keine Ergebnisse: Es gab in den letzten 90 Tagen keine Bearbeitungen von diesen Benutzern oder IP-Adressen",
+ "checkuser-investigate-compare-notice-no-results-filters": "Es gibt keine Ergebnisse, die diesen Filterkriterien entsprechen. Versuche, einige Filter zu entfernen, um die Suche zu erweitern.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Zeige alle IP-Adressen von diesem Benutzer",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Zeige alle Benutzer mit dieser IP-Adresse",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Diese IP-Adresse zur Untersuchung hinzufügen",
+ "checkuser-investigate-compare-table-button-checks-label": "Abfragen",
+ "checkuser-investigate-compare-table-button-contribs-label": "Beiträge",
+ "checkuser-investigate-compare-table-button-filter-label": "Aus den Ergebnissen filtern",
+ "checkuser-investigate-compare-table-cell-unregistered": "Unregistriert",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|Bearbeitung|Bearbeitungen}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 von allen Benutzern)</i>",
+ "checkuser-investigate-compare-table-header-username": "Benutzername",
+ "checkuser-investigate-compare-table-header-activity": "Datumsbereich",
+ "checkuser-investigate-compare-table-header-ip": "IP-Adresse",
+ "checkuser-investigate-compare-table-header-useragent": "User-Agent",
+ "checkuser-investigate-subtitle-link-restart-tour": "Tour neu starten",
+ "checkuser-investigate-tour-targets-title": "Überprüfung mehrerer Benutzer und IP-Adressen?",
+ "checkuser-investigate-tour-targets-desc": "Ergänze bis zu $1 {{PLURAL:$1|Benutzername oder IP-Adresse|Benutzernamen oder IP-Adressen}} und erhalte alle Informationen an einem Ort. Keine Sorge, wir erstellen für jeden von ihnen einen separaten CheckUser-Logbucheintrag.",
+ "checkuser-investigate-tour-useragents-title": "Passende User Agents?",
+ "checkuser-investigate-tour-useragents-desc": "Bewege den Mauszeiger über eine Zelle, um alle anderen Zeilen mit den gleichen Daten hervorzuheben. Klicke auf das Pin-Symbol, um die Hervorhebung beim Durchlaufen der Daten eingeschaltet zu lassen.",
+ "checkuser-investigate-tour-addusertargets-title": "Brauchst du mehr Kontext?",
+ "checkuser-investigate-tour-addusertargets-desc": "Klicke, um alle anderen Benutzer unter dieser IP-Adresse zu sehen. Du kannst dies auch für Benutzer tun und alle IP-Adressen sehen, die sie verwendet haben. Es wird automatisch ein CheckUser-Logbucheintrag erstellt.",
+ "checkuser-investigate-tour-filterip-title": "Untersuchung eingrenzen?",
+ "checkuser-investigate-tour-filterip-desc": "Entferne das Durcheinander, indem du Benutzernamen, IP-Adressen oder User Agents herausfilterst. Willst du alle Daten sehen? Verwende das Filter-Panel oben, um die Filter zu entfernen.",
+ "checkuser-investigate-tour-block-title": "Sperren?",
+ "checkuser-investigate-tour-block-desc": "Ermöglicht es dir, die Benutzer auszuwählen, die du sperren möchtest, und führt dich dann zum Sperrformular, um die entsprechende Sperre auszuwählen.",
+ "checkuser-investigate-tour-copywikitext-title": "Daten kopieren?",
+ "checkuser-investigate-tour-copywikitext-desc": "Kopiere die Vergleichstabelle mit einem Klick und bringe sie in das CU-Wiki. Beachte, dass du nur das kopierst, was sichtbar ist und nicht alle Seiten der Untersuchung."
}
diff --git a/CheckUser/i18n/diq.json b/CheckUser/i18n/diq.json
index e13b3d3f..63cfb45e 100644
--- a/CheckUser/i18n/diq.json
+++ b/CheckUser/i18n/diq.json
@@ -1,13 +1,14 @@
{
"@metadata": {
"authors": [
+ "1917 Ekim Devrimi",
"Erdemaslancan",
"Gorizon",
- "Mirzali",
- "Xoser",
- "Marmase",
"Kumkumuk",
- "1917 Ekim Devrimi"
+ "Marmase",
+ "Mirzali",
+ "Orbot707",
+ "Xoser"
]
},
"checkuser-summary": "Eno xacet vurnayışanê neweyan sken keno ke adresanê IPyan reyna biaro ke bımocno ra yew adresa IPya melumatê karberi ser.\nKarberan u vurnayışan ke yew IPyê karberi kerd a reyna yeno pê XFF u \"/xff\". IPv4 (CIDR $1-32) u IPv6 (CIDR $2-128) rê zi desteg beno.\n5000 zafêr vurnayışan sero netice nêdano, qet performans hêdi beno.\nEna politika ma sero kar bıke.",
@@ -20,19 +21,19 @@
"group-checkuser": "Weynayoği",
"group-checkuser-member": "{{GENDER:$1|Kontrolkar}}",
"right-checkuser": "Adresanê IPyê karberi û melumatê bini kontrol ke",
- "right-checkuser-log": "Qeydé rocekané karber cernayışi bıvin",
+ "right-checkuser-log": "Roceka Tetqiqwani bıvênên",
"action-checkuser": "adresanê IPyê karberi û melumatê bini kontrol ke",
"action-checkuser-log": "Rocekane Karber kontroli bıvin",
"grouppage-checkuser": "{{ns:project}}:Teftişwan",
"checkuser-reason": "Sebeb:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Qeydé asayışi",
+ "checkuser-showlog": "Qeydê asayışi weçinê",
"checkuser-query": "Bigêrayîşî de vurnayîşanê penîyan",
"checkuser-target": "Adresa IPy ya zi nameyê karberi:",
"checkuser-users": "Karberî bivîne",
"checkuser-edits": "Vurnayışan bıgê",
"checkuser-ips": "Adresê IPyî bivîne",
- "checkuser-period": "Sure:",
+ "checkuser-period": "Dom:",
"checkuser-week-1": "hefteyê verînî",
"checkuser-week-2": "di hefteyê verînî",
"checkuser-month": "30 rocê verînî",
@@ -60,18 +61,30 @@
"checkuser-block-limit": "Ti zaf karberan weçino.",
"checkuser-block-noreason": "Qe blokan, ti gani yew sebeb bide.",
"checkuser-noreason": "Qe bigêrayîşî, ti gani yew sebeb bide.",
- "checkuser-accounts": "$1 {{PLURAL:$1|hesab|hesaban}} newî",
"checkuser-too-many": "Zaf neticiyan esto (ser texminê cigeyrayîşî), şima ra rica keno CIDR qickek bike.\nTiya de IPyan ke sero kar biyo (5000 max, pê adresan):",
"checkuser-user-nonexistent": "Karbero ke ti specife kerd, ay database ma de niesto.",
"checkuser-search": "Cı geyre",
"checkuser-search-submit": "Cı geyre",
"checkuser-search-initiator": "başlî kerdoğ",
"checkuser-search-target": "hedef",
+ "checkuser-log-search-target": "Etiket:",
"checkuser-ipeditcount": "~$1 karberan pêrıne ra",
"checkuser-showmain": "Peyd şori form de KarberKontroli",
"checkuser-limited": "'''Ena neticeyan qe sebabanê performansî ra kilm kerd.'''",
"checkuser-autocreate-action": "otomatikî ra virziyo",
"checkuser-create-action": "Vıraziya",
"checkuser-email-action": "karberê $1î rê email Bırşe",
- "checkuser-reset-action": "karberê \"$1\" rê parola nên ke"
+ "checkuser-reset-action": "karberê \"$1\" rê parola nên ke",
+ "checkuser-investigate-reason-label": "Sebeb",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|vurnayış|vurnayışi}}",
+ "checkuser-investigate-preliminary-table-header-blocked": "Weziyet",
+ "checkuser-investigate-preliminary-table-header-editcount": "Bıvurnê",
+ "checkuser-investigate-preliminary-table-header-groups": "Grube",
+ "checkuser-investigate-preliminary-table-header-name": "Nameykarberi",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-compare-table-cell-unregistered": "Bêqeydıni",
+ "checkuser-investigate-compare-table-cell-edits": "<b>$1 {{PLURAL:$1|vurnayış|vurnayışi}}</b>",
+ "checkuser-investigate-compare-table-header-username": "Namey karberi",
+ "checkuser-investigate-compare-table-header-activity": "Mabênê tarix",
+ "checkuser-investigate-compare-table-header-ip": "IP"
}
diff --git a/CheckUser/i18n/dsb.json b/CheckUser/i18n/dsb.json
index 0f358200..5af493b0 100644
--- a/CheckUser/i18n/dsb.json
+++ b/CheckUser/i18n/dsb.json
@@ -54,7 +54,6 @@
"checkuser-block-limit": "Pśewjele wužywarjow wubrane.",
"checkuser-block-noreason": "Musyš pśicynu za blokěrowanja pódaś.",
"checkuser-noreason": "Musyš pśicynu za toś to wótpšašanje pódaś.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nowe konto|nowej konśe|nowe konta|nowych kontow}}",
"checkuser-too-many": "Pśewjele wuslědkow (pó pówoblicenju napšašowanja), pšosym wobgranicuj CIDR. How su wužywane IP-adrese (maks. 5000, pséwuběrane pó adresu):",
"checkuser-user-nonexistent": "Pódany wužywaŕ njeeksistěrujo.",
"checkuser-search": "Pytaś",
diff --git a/CheckUser/i18n/el.json b/CheckUser/i18n/el.json
index fc5d4c0e..4d4e711b 100644
--- a/CheckUser/i18n/el.json
+++ b/CheckUser/i18n/el.json
@@ -8,10 +8,11 @@
"Glavkos",
"K sal 15",
"Konsnos",
+ "Norhorn",
"Omnipaedista",
+ "Protnet",
"ZaDiak",
- "Απεργός",
- "Protnet"
+ "Απεργός"
]
},
"checkuser-summary": "Αυτό το εργαλείο σαρώνει τις πρόσφατες αλλαγές για να ανακτήσει τις IP διευθύνσεις που χρησιμοποιούνται από ένα χρήστη ή για να δείξει τα δεδομένα επεξεργασιών/χρηστών για μία IP.\nΧρήστες και επεξεργασίες από μία σταθερή IP μπορούν να ανακτηθούν μέσω XFF επικεφαλίδων προσαρτώντας \"/xff\" στην IP. Το IPv4 (CIDR $1-32) και το IPv6 (CIDR $2-128) υποστηρίζονται.\nΌχι περισσότερες από 5000 επεξεργασίες θα επιστραφούν για λόγους απόδοσης.\nΧρησιμοποιήστε αυτό σύμφωνα με την πολιτική.",
@@ -64,7 +65,6 @@
"checkuser-block-limit": "Έχουν επιλεχθεί πάρα πολλοί χρήστες.",
"checkuser-block-noreason": "Πρέπει να αιτιολογήσετε τις φραγές.",
"checkuser-noreason": "Πρέπει να δώσετε μια αιτία για αυτή την ερώτηση.",
- "checkuser-accounts": "$1 {{PLURAL:$1|νέος λογαριασμός|νέοι λογαριασμοί}}",
"checkuser-too-many": "Πάρα πολλά αποτελέσματα (σύμφωνα με την εκτίμηση σειράς), παρακαλούμε στενέψτε το CIDR.\nΠαρακάτω είναι οι διευθύνσεις IP που χρησιμοποιούνται (με ανώτατο όριο τις 5000, ταξινομημένες κατά διεύθυνση):",
"checkuser-user-nonexistent": "Ο συγκεκριμένος χρήστης δεν υπάρχει.",
"checkuser-search": "Αναζήτηση",
@@ -77,5 +77,13 @@
"checkuser-autocreate-action": "δημιουργήθηκε αυτόματα",
"checkuser-create-action": "δημιουργήθηκε",
"checkuser-email-action": "έστειλε ένα ηλεκτρονικό μήνυμα στον χρήστη \"$1\"",
- "checkuser-reset-action": "αποστολή νέου κωδικού για τον χρήστη \"$1\""
+ "checkuser-reset-action": "αποστολή νέου κωδικού για τον χρήστη \"$1\"",
+ "checkuser-investigateblock": "Αποκλεισμένοι χρήστες",
+ "checkuser-investigateblock-target": "Ονόματα χρήστη και διευθύνσεις IP",
+ "checkuser-investigateblock-actions": "Ενέργειες για φραγή",
+ "checkuser-investigateblock-reason": "Αιτία",
+ "checkuser-investigateblock-email-label": "Αποτροπή αποστολής μηνύματος ηλεκτρονικού ταχυδρομείου",
+ "checkuser-investigateblock-notice-position-label": "Θέση",
+ "checkuser-investigateblock-notice-text-label": "Κείμενο wiki",
+ "checkuser-investigateblock-notice-replace": "Αντικατάσταση σελίδας"
}
diff --git a/CheckUser/i18n/en-gb.json b/CheckUser/i18n/en-gb.json
index 10dc51e1..9790a7eb 100644
--- a/CheckUser/i18n/en-gb.json
+++ b/CheckUser/i18n/en-gb.json
@@ -1,14 +1,15 @@
{
"@metadata": {
"authors": [
+ "Andibing",
+ "Bjh21",
"Chase me ladies, I'm the Cavalry",
- "Macofe",
"Guycn2",
- "Andibing"
+ "Macofe"
]
},
"checkuser-summary": "This tool scans recent changes to retrieve the IP addresses used by a user or show the edit/user data for an IP address.\nUsers and edits by a client IP address can be retrieved via XFF headers by appending the IP address with \"/xff\". IPv4 (CIDR $1-32) and IPv6 (CIDR $2-128) are supported.\nNo more than 5,000 edits will be returned for performance reasons.\nUse this in accordance with policy.",
- "checkuser-desc": "Grants users with the appropriate permission the ability to check user's IP addresses and other information",
+ "checkuser-desc": "Grants users with the appropriate permission the ability to check users' IP addresses and other information",
"checkuser-logcase": "The log search is case sensitive.",
"checkuser": "Check user",
"checkuserlog": "Check user log",
@@ -16,9 +17,9 @@
"checkuser-contribs-log": "recent user checks",
"group-checkuser": "Check users",
"group-checkuser-member": "{{GENDER:$1|check user}}",
- "right-checkuser": "Check user's IP addresses and other information",
+ "right-checkuser": "Check users' IP addresses and other information",
"right-checkuser-log": "View the checkuser log",
- "action-checkuser": "check user's IP addresses and other information",
+ "action-checkuser": "check users' IP addresses and other information",
"action-checkuser-log": "view the checkuser log",
"grouppage-checkuser": "{{ns:project}}:Check user",
"checkuser-reason": "Reason:",
@@ -60,8 +61,7 @@
"checkuser-block-noreason": "You must give a reason for the blocks.",
"checkuser-centralauth-multilock": "Multi lock selected accounts",
"checkuser-noreason": "You must give a reason for this query.",
- "checkuser-accounts": "$1 new {{PLURAL:$1|account|accounts}}",
- "checkuser-too-many": "Too many results (according to query estimate), please narrow down the CIDR.\nHere are the IP addresses used (5000 max, sorted by address):",
+ "checkuser-too-many": "Too many results (according to query estimate), please narrow down the CIDR.\nHere are the IP addresses used ($1 max, sorted by address):",
"checkuser-user-nonexistent": "The specified user does not exist.",
"checkuser-search": "Search check user log entries",
"checkuser-search-submit": "Search",
@@ -73,31 +73,14 @@
"checkuser-showmain": "Switch to CheckUser main form",
"checkuser-limited": "'''These results have been truncated for performance reasons.'''",
"checkuser-log-entry-userips": "$3, $1 got IP addresses for $2",
- "checkuser-log-entry-ipedits": "$3, $1 got edits for $2",
- "checkuser-log-entry-ipusers": "$3, $1 got users for $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 got edits for XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 got users for XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 got edits for <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 got users for <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 got edits for XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 got users for XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 got edits for $2",
"checkuser-autocreate-action": "was automatically created",
"checkuser-create-action": "was created",
"checkuser-email-action": "sent an email to user \"$1\"",
"checkuser-reset-action": "reset password for user \"$1\"",
- "checkuser-token-fail": "Session failure. Please try again.",
- "apihelp-query+checkuser-description": "Check which IP addresses are used by a given username, or which usernames are used by a given IP.",
- "apihelp-query+checkuser-param-request": "Type of CheckUser request:\n;userips:Get IP address of target user.\n;edits:Get changes from target IP address or range.\n;ipusers:Get users from target IP address or range.",
- "apihelp-query+checkuser-param-target": "Username, IP address, or CIDR range to check.",
- "apihelp-query+checkuser-param-reason": "Reason to check.",
- "apihelp-query+checkuser-param-limit": "Limit of rows.",
- "apihelp-query+checkuser-param-timecond": "Time limit of user data (like \"-2 weeks\" or \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Use XFF data instead of IP address.",
- "apihelp-query+checkuser-example-1": "Check IP addresses for [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Check edits from 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Get entries from the CheckUser log.",
- "apihelp-query+checkuserlog-param-user": "Username of the CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Checked user, IP address, or CIDR range.",
- "apihelp-query+checkuserlog-param-limit": "Limit of rows.",
- "apihelp-query+checkuserlog-param-from": "The timestamp to start enumerating from.",
- "apihelp-query+checkuserlog-param-to": "The timestamp to end enumerating.",
- "apihelp-query+checkuserlog-example-1": "Show checks of [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Show checks of 192.0.2.0/24 after 2011-10-15T23:00:00Z"
+ "checkuser-token-fail": "Session failure. Please try again."
}
diff --git a/CheckUser/i18n/en.json b/CheckUser/i18n/en.json
index 23e25bff..e2fb8ada 100644
--- a/CheckUser/i18n/en.json
+++ b/CheckUser/i18n/en.json
@@ -7,7 +7,7 @@
]
},
"checkuser-summary": "This tool scans recent changes to retrieve the IP addresses used by a user or show the edit/user data for an IP address.\nUsers and edits by a client IP address can be retrieved via XFF headers by appending the IP address with \"/xff\". IPv4 (CIDR $1-32) and IPv6 (CIDR $2-128) are supported.\nNo more than 5,000 edits will be returned for performance reasons.\nUse this in accordance with policy.",
- "checkuser-desc": "Grants users with the appropriate permission the ability to check user's IP addresses and other information",
+ "checkuser-desc": "Grants users with the appropriate permission the ability to check users' IP addresses and other information",
"checkuser-logcase": "The log search is case sensitive.",
"checkuser": "Check user",
"checkuserlog": "Check user log",
@@ -15,9 +15,9 @@
"checkuser-contribs-log": "recent user checks",
"group-checkuser": "Check users",
"group-checkuser-member": "{{GENDER:$1|check user}}",
- "right-checkuser": "Check user's IP addresses and other information",
+ "right-checkuser": "Check users' IP addresses and other information",
"right-checkuser-log": "View the checkuser log",
- "action-checkuser": "check user's IP addresses and other information",
+ "action-checkuser": "check users' IP addresses and other information",
"action-checkuser-log": "view the checkuser log",
"grouppage-checkuser": "{{ns:project}}:Check user",
"checkuser-reason": "Reason:",
@@ -54,6 +54,7 @@
"checkuser-blocktalk": "Prevent from editing their own talk page while blocked",
"checkuser-blocktag": "Replace user pages with:",
"checkuser-blocktag-talk": "Replace talk pages with:",
+ "checkuser-reblock": "Override existing blocks",
"checkuser-massblock-commit": "Block selected users",
"checkuser-block-success": "'''The {{PLURAL:$2|user|users}} $1 {{PLURAL:$2|is|are}} now blocked.'''",
"checkuser-block-failure": "'''No users blocked.'''",
@@ -61,8 +62,7 @@
"checkuser-block-noreason": "You must give a reason for the blocks.",
"checkuser-centralauth-multilock": "Multi lock selected accounts",
"checkuser-noreason": "You must give a reason for this query.",
- "checkuser-accounts": "$1 new {{PLURAL:$1|account|accounts}}",
- "checkuser-too-many": "Too many results (according to query estimate), please narrow down the CIDR.\nHere are the IP addresses used (5000 max, sorted by address):",
+ "checkuser-too-many": "Too many results (according to query estimate), please narrow down the CIDR.\nHere are the IP addresses used ($1 max, sorted by address):",
"checkuser-user-nonexistent": "The specified user does not exist.",
"checkuser-search": "Search check user log entries",
"checkuser-search-submit": "Search",
@@ -74,10 +74,10 @@
"checkuser-showmain": "Switch to CheckUser main form",
"checkuser-limited": "'''These results have been truncated for performance reasons.'''",
"checkuser-log-entry-userips": "$3, $1 got IP addresses for $2",
- "checkuser-log-entry-ipedits": "$3, $1 got edits for $2",
- "checkuser-log-entry-ipusers": "$3, $1 got users for $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 got edits for XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 got users for XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 got edits for <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 got users for <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 got edits for XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 got users for XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 got edits for $2",
"checkuser-autocreate-action": "was automatically created",
"checkuser-create-action": "was created",
@@ -90,26 +90,96 @@
"checkuser-login-success": "Successfully logged in to {{SITENAME}} as $1",
"group-checkuser.css": "/* CSS placed here will affect checkuser only */",
"group-checkuser.js": "/* JS placed here will affect checkuser only */",
- "apihelp-query+checkuser-description": "Check which IP addresses are used by a given username or which usernames are used by a given IP address.",
- "apihelp-query+checkuser-summary": "Check which IP addresses are used by a given username or which usernames are used by a given IP address.",
- "apihelp-query+checkuser-param-request": "Type of CheckUser request:\n;userips:Get IP address of target user.\n;edits:Get changes from target IP address or range.\n;ipusers:Get users from target IP address or range.",
- "apihelp-query+checkuser-param-target": "Username, IP address, or CIDR range to check.",
- "apihelp-query+checkuser-param-reason": "Reason to check.",
- "apihelp-query+checkuser-param-limit": "Limit of rows.",
- "apihelp-query+checkuser-param-timecond": "Time limit of user data (like \"-2 weeks\" or \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Use XFF data instead of IP address.",
- "apihelp-query+checkuser-example-1": "Check IP addresses for [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Check edits from 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Get entries from the CheckUser log.",
- "apihelp-query+checkuserlog-summary": "Get entries from the CheckUser log.",
- "apihelp-query+checkuserlog-param-user": "Username of the CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Checked user, IP address, or CIDR range.",
- "apihelp-query+checkuserlog-param-limit": "Limit of rows.",
- "apihelp-query+checkuserlog-param-from": "The timestamp to start enumerating from.",
- "apihelp-query+checkuserlog-param-to": "The timestamp to end enumerating.",
- "apihelp-query+checkuserlog-example-1": "Show checks of [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Show checks of 192.0.2.0/24 after 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "You must define reason for check.",
- "apierror-checkuser-timelimit": "You need use correct time limit (like \"-2 weeks\" or \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "Invalid request mode"
+ "checkuser-link-investigate-label": "Try the new CheckUser tool",
+ "checkuser-investigateblock": "Block users",
+ "checkuser-investigateblock-target": "Usernames and IP addresses",
+ "checkuser-investigateblock-actions": "Actions to block",
+ "checkuser-investigateblock-reason": "Reason",
+ "checkuser-investigateblock-options": "Additional options",
+ "checkuser-investigateblock-email-label": "Prevent from sending email",
+ "checkuser-investigateblock-usertalk-label": "Prevent from editing their own talk page while blocked",
+ "checkuser-investigateblock-reblock-label": "Override existing blocks",
+ "checkuser-investigateblock-notice-user-page-label": "Leave a notice on User page",
+ "checkuser-investigateblock-notice-talk-page-label": "Leave a notice on User Talk page",
+ "checkuser-investigateblock-notice-position-label": "Position",
+ "checkuser-investigateblock-notice-text-label": "Wikitext",
+ "checkuser-investigateblock-notice-append": "Append to page",
+ "checkuser-investigateblock-notice-prepend": "Prepend to page",
+ "checkuser-investigateblock-notice-replace": "Replace page",
+ "checkuser-investigateblock-failure": "No users were blocked. To override existing blocks, check: \"{{int:checkuser-investigateblock-reblock-label}}\". A block will not be overridden if the new block is identical to the existing block.",
+ "checkuser-investigateblock-success": "The {{PLURAL:$2|user|users}} $1 {{PLURAL:$2|is|are}} now blocked.",
+ "checkuser-investigateblock-notices-failed": "Some notices could not be added to the user pages or user talk pages.",
+ "checkuser-investigate-log": "Investigation logs",
+ "checkuser-investigate-log-entry": "$3, $1 looked up information for <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "No investigation log entries found.",
+ "checkuser-investigate-log-subtitle": "Switch to Investigate form",
+ "checkuser-investigate": "Investigate",
+ "checkuser-investigate-page-subtitle": "Current investigation for $1",
+ "checkuser-investigate-subtitle-block-button-label": "Block",
+ "checkuser-investigate-subtitle-cancel-button-label": "Cancel",
+ "checkuser-investigate-subtitle-continue-button-label": "Continue",
+ "checkuser-investigate-indicator-new-investigation": "New investigation",
+ "checkuser-investigate-indicator-logs": "Logs",
+ "checkuser-investigate-legend": "Search for usernames, IP addresses or IP ranges",
+ "checkuser-investigate-notice-no-results": "There are no results.",
+ "checkuser-investigate-tab-preliminary-check": "Account information",
+ "checkuser-investigate-tab-compare": "IPs & User agents",
+ "checkuser-investigate-tab-timeline": "Timeline",
+ "checkuser-investigate-targets-label": "Usernames and IP addresses",
+ "checkuser-investigate-targets-placeholder": "UserName or 1.1.1.1",
+ "checkuser-investigate-duration-label": "Duration",
+ "checkuser-investigate-duration-option-all": "All",
+ "checkuser-investigate-duration-option-1w": "Last week",
+ "checkuser-investigate-duration-option-2w": "Last 2 weeks",
+ "checkuser-investigate-duration-option-30d": "Last 30 days",
+ "checkuser-investigate-reason-label": "Reason",
+ "checkuser-investigate-preliminary-notice-ip-targets": "The Account information tab doesn't include any information on IPs. See the <span class=\"plainlinks\">[$1 IPs & User agents tab]</span> for those details.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Blocked",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|edit|edits}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Not blocked",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Edits",
+ "checkuser-investigate-preliminary-table-header-groups": "Groups",
+ "checkuser-investigate-preliminary-table-header-name": "Username",
+ "checkuser-investigate-preliminary-table-header-registration": "Date attached",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki not found",
+ "checkuser-investigate-filters-legend": "Filters",
+ "checkuser-investigate-filters-exclude-targets-label": "Hide the following users or IPs",
+ "checkuser-investigate-timeline-notice-no-results": "There are no results: there has been no recorded activity from these users or IPs in the last 90 days",
+ "checkuser-investigate-timeline-notice-no-results-filters": "There are no results matching these filtering criteria. Try removing some filters to broaden the search.",
+ "checkuser-investigate-compare-copy-button-label": "Show wikitext",
+ "checkuser-investigate-compare-toollinks": "[[https://whois.toolforge.org/gateway.py?lookup=true&ip=$1 {{int:checkuser-investigate-compare-toollinks-whois}}]\n[[https://ipcheck.toolforge.org/index.php?ip=$1 {{int:checkuser-investigate-compare-toollinks-ipcheck}}]",
+ "checkuser-investigate-compare-toollinks-whois": "WHOIS",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Proxy check",
+ "checkuser-investigate-compare-copy-message-label": "Would you like to copy this information as a Wikitext table?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Due to technical limitations we've reached the number of records that can be presented. The data returned for the following targets is incomplete: $1. Please try using fewer targets, smaller time window or narrower IP ranges.",
+ "checkuser-investigate-compare-notice-no-results": "There are no results: there have been no edits from these users or IPs in the last 90 days",
+ "checkuser-investigate-compare-notice-no-results-filters": "There are no results matching these filtering criteria. Try removing some filters to broaden the search.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Show all IPs of this user",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Show all users on this IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Add this IP to investigation",
+ "checkuser-investigate-compare-table-button-checks-label": "Checks",
+ "checkuser-investigate-compare-table-button-contribs-label": "Contributions",
+ "checkuser-investigate-compare-table-button-filter-label": "Filter from results",
+ "checkuser-investigate-compare-table-cell-unregistered": "Unregistered",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|edit|edits}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 from all users)</i>",
+ "checkuser-investigate-compare-table-header-username": "Username",
+ "checkuser-investigate-compare-table-header-activity": "Date range",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "User agent",
+ "checkuser-investigate-subtitle-link-restart-tour": "Restart Tour",
+ "checkuser-investigate-tour-targets-title": "Checking multiple users and IPs?",
+ "checkuser-investigate-tour-targets-desc": "Add up to $1 {{PLURAL:$1|Username or IP|Usernames or IPs}} and get all the information in one place. Don’t worry, we’ll create a separate CheckUser log for each of them.",
+ "checkuser-investigate-tour-useragents-title": "Matching User Agents?",
+ "checkuser-investigate-tour-useragents-desc": "Hover over a cell to highlight all other rows that have the same data. Click the pin icon to keep the highlight on as you go through the data.",
+ "checkuser-investigate-tour-addusertargets-title": "Need more context?",
+ "checkuser-investigate-tour-addusertargets-desc": "Click to see all other users on the IP. You can do this for Users too, and see all the IPs they’ve been using. We’ll automatically create a CheckUser log item for you.",
+ "checkuser-investigate-tour-filterip-title": "Narrowing your investigation?",
+ "checkuser-investigate-tour-filterip-desc": "Remove the clutter by filtering out user names, IPs or user agents. Want the data back? Use the Filters panel on top to remove the filters.",
+ "checkuser-investigate-tour-block-title": "Want to block?",
+ "checkuser-investigate-tour-block-desc": "Allows you to select the users you’d like to block and then takes you to the block form to pick the appropriate block.",
+ "checkuser-investigate-tour-copywikitext-title": "Want to copy the data?",
+ "checkuser-investigate-tour-copywikitext-desc": "Copy the compare table with one-click and take it to the CUWiki. Do note that you’re only copying what is visible and not all the pages of the investigation."
}
diff --git a/CheckUser/i18n/eo.json b/CheckUser/i18n/eo.json
index 6c82dfbd..17f961d0 100644
--- a/CheckUser/i18n/eo.json
+++ b/CheckUser/i18n/eo.json
@@ -3,8 +3,8 @@
"authors": [
"Blahma",
"Michawiki",
- "Yekrats",
- "Robin van der Vliet"
+ "Robin van der Vliet",
+ "Yekrats"
]
},
"checkuser-summary": "Ĉi tiu ilo skanas lastajn ŝanĝojn por akiri la IP-adresojn uzatajn de uzanto aŭ montri la datenojn de redakto/uzanto por aparta IP-adreso.\nUzantoj kaj redaktoj de klienta IP-adreso povas esti akirita per XFF-titolaro postaldonante al la IP-adreso kun \"/xff\".\nIPv4 (CIDR $1-32) kaj IPv6 (CIDR $2-128) estas subtenataj.\nNeniom pli ol 5000 redaktoj estos montrita pro bona datumbaza funkciado.\nUzu ĉi tion laŭ regularo.",
@@ -25,7 +25,7 @@
"checkuser-reason-api": "API: $1",
"checkuser-showlog": "Montri protokolon",
"checkuser-query": "Informomendi lastatempajn ŝanĝojn",
- "checkuser-target": "IP-adreso aŭ salutnomo:",
+ "checkuser-target": "IP-adreso aŭ uzantnomo:",
"checkuser-users": "Akiri uzantojn",
"checkuser-edits": "Mendi redaktojn",
"checkuser-ips": "Preni IP-adresojn",
@@ -57,7 +57,6 @@
"checkuser-block-limit": "Tro da uzantoj elektitaj.",
"checkuser-block-noreason": "Vi devas doni kialon por la forbaroj.",
"checkuser-noreason": "Vi devas doni kialon por ĉi tiu informomendo.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nova konto|novaj kontoj}}",
"checkuser-too-many": "Tro da rezultoj, laŭ taskoj de serĉomendo. Bonvolu malvastigi la CIDR.\nJen la IP-adresoj uzitaj (maksimume 5000, ordigita laŭ adresoj):",
"checkuser-user-nonexistent": "La donata uzanto ne ekzistas.",
"checkuser-search": "Serĉi",
diff --git a/CheckUser/i18n/es-formal.json b/CheckUser/i18n/es-formal.json
index 0d246a7f..af7ed310 100644
--- a/CheckUser/i18n/es-formal.json
+++ b/CheckUser/i18n/es-formal.json
@@ -6,8 +6,7 @@
},
"checkuser-summary": "Esta herramienta explora los cambios recientes para obtener las direcciones IP utilizadas por un usuario, o para mostrar la información de ediciones y usuarios de una cierta dirección IP.\nSe pueden obtener los usuarios y las ediciones de una dirección IP cliente vía XFF añadiendo \"/xff\" al final de la dirección IP. Funciona con IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128).\nNo se muestran más de 5000 ediciones por motivos de rendimiento.\nUtilícela de acuerdo con las políticas correspondientes.",
"checkuser-block-noreason": "Debe dar una razón para los bloqueos.",
+ "checkuser-noreason": "Debe dar una razón para esta consulta.",
"checkuser-too-many": "Hay demasiados resultados (de acuerdo al estimado de la consulta). Pruebe a limitar el CIDR.\nAquí se ven las IPs usadas (máximo 5000, ordenadas por dirección):",
- "checkuser-token-fail": "Fallo en la sesión. Por favor, inténtelo de nuevo.",
- "apierror-checkuser-missingsummary": "Debe introducir una razón para la comprobación.",
- "apierror-checkuser-timelimit": "Necesita introducir un plazo máximo de tiempo correcto (como \"-2 weeks\" o \"2 weeks ago\")."
+ "checkuser-token-fail": "Fallo en la sesión. Por favor, inténtelo de nuevo."
}
diff --git a/CheckUser/i18n/es.json b/CheckUser/i18n/es.json
index ac8fbc2d..ac737b54 100644
--- a/CheckUser/i18n/es.json
+++ b/CheckUser/i18n/es.json
@@ -4,36 +4,44 @@
"Aleator",
"AlimanRuna",
"Armando-Martin",
+ "Canaan9801",
"Crazymadlover",
"Dferg",
"Dmcdevit",
+ "Fitoschido",
+ "Geryescalier",
"Gustronico",
+ "Hasley",
"Hereñu",
"Imre",
+ "JasterTDC",
"Jatrobat",
+ "Joanmp17",
+ "KATRINE1993",
"Lin linao",
"Locos epraix",
+ "Macofe",
"Manuelt15",
"MarcoAurelio",
"Mr.Ajedrez",
"Muro de Aguas",
"Piolinfax",
"Platonides",
+ "PoLuX124",
"Remember the dot",
+ "Ryo567",
"Sanbec",
"Spacebirdy",
+ "Suecarmol",
+ "Sukanya121",
"Titoxd",
- "VegaDark",
- "Fitoschido",
- "JasterTDC",
- "Macofe",
- "Ryo567"
+ "VegaDark"
]
},
- "checkuser-summary": "Esta herramienta explora los cambios recientes para obtener las direcciones IP utilizadas por un usuario, o para mostrar la información de ediciones y usuarios de una cierta dirección IP.\nSe pueden obtener los usuarios y las ediciones de una dirección IP cliente vía XFF añadiendo \"/xff\" al final de la dirección IP. Funciona con IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128).\nNo se muestran más de 5000 ediciones por motivos de rendimiento.\nUtilízala de acuerdo con las políticas correspondientes.",
+ "checkuser-summary": "Esta herramienta explora los cambios recientes para obtener las direcciones IP utilizadas por un usuario, o para mostrar la información de ediciones y usuarios de una cierta dirección IP.\nSe pueden obtener los usuarios y las ediciones de una dirección IP cliente vía XFF añadiendo «/xff» al final de la dirección IP. Funciona con IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128).\nNo se muestran más de 5000 ediciones por motivos de rendimiento.\nUtilízala de acuerdo con las políticas correspondientes.",
"checkuser-desc": "Permite a los usuarios que tienen los permisos apropiados comprobar las direcciones IP de los usuarios además de otra información.",
"checkuser-logcase": "La búsqueda en el registro distingue entre mayúsculas y minúsculas.",
- "checkuser": "Verificador de usuarios",
+ "checkuser": "Verificación de usuarios",
"checkuserlog": "Registro de verificación de usuarios",
"checkuser-contribs": "verificar las direcciones IP del usuario",
"checkuser-contribs-log": "comprobaciones efectuadas sobre este usuario recientemente",
@@ -73,20 +81,20 @@
"checkuser-wasblocked": "Bloqueado anteriormente",
"checkuser-localonly": "No unificada",
"checkuser-massblock": "Bloquear usuarios seleccionados",
- "checkuser-massblock-text": "Las cuentas seleccionadas serán bloqueadas de forma indefinida, con el autobloqueo habilitado y la creación de cuentas deshabilitada.\nLas direcciones IP serán bloqueadas durante una semana para usuarios anónimos sólamente con la creación de cuentas deshabilitada.",
+ "checkuser-massblock-text": "Las cuentas seleccionadas serán bloqueadas de forma indefinida, con el autobloqueo habilitado y la creación de cuentas deshabilitada.\nLas direcciones IP serán bloqueadas durante una semana para usuarios anónimos solamente con la creación de cuentas deshabilitada.",
"checkuser-blockemail": "Impedir que envíe correo electrónico",
"checkuser-blocktalk": "Impedir la edición de su propia página de discusión mientras esté bloqueado",
"checkuser-blocktag": "Reemplazar páginas del usuario con:",
"checkuser-blocktag-talk": "Reemplazar las páginas de discusión con:",
+ "checkuser-reblock": "Hacer prevalecer sobre bloqueos existentes",
"checkuser-massblock-commit": "Bloquear usuarios seleccionados",
"checkuser-block-success": "'''{{PLURAL:$2|El usuario|Los usuarios}} $1 {{PLURAL:$2|está bloqueado|están bloqueados}}.'''",
"checkuser-block-failure": "'''No hay usuarios bloqueados.'''",
- "checkuser-block-limit": "Demasiados usarios seleccionados.",
+ "checkuser-block-limit": "Demasiados usuarios seleccionados.",
"checkuser-block-noreason": "Debes dar una razón para los bloqueos.",
"checkuser-centralauth-multilock": "Bloquear globalmente las cuentas seleccionadas",
"checkuser-noreason": "Debes dar una razón para esta consulta.",
- "checkuser-accounts": "$1 {{PLURAL:$1|cuenta nueva|cuentas nuevas}}",
- "checkuser-too-many": "Hay demasiados resultados (de acuerdo al estimado de la consulta). Prueba limitar el CIDR.\nAquí se ven las IPs usadas (máximo 5000, ordenadas por dirección):",
+ "checkuser-too-many": "Hay demasiados resultados (de acuerdo al estimado de la consulta). Prueba limitar el CIDR.\nAquí se ven las IPs usadas (máximo $1, ordenadas por dirección):",
"checkuser-user-nonexistent": "El usuario especificado no existe.",
"checkuser-search": "Buscar entradas del registro de CheckUser",
"checkuser-search-submit": "Buscar",
@@ -98,10 +106,10 @@
"checkuser-showmain": "Cambiar al formulario principal de verificador de usuarios (CheckUser)",
"checkuser-limited": "'''Estos resultados han sido truncados por motivos de rendimiento.'''",
"checkuser-log-entry-userips": "$3, $1 obtuvo las direcciones IP de $2",
- "checkuser-log-entry-ipedits": "$3, $1 obtuvo las contribuciones de $2",
- "checkuser-log-entry-ipusers": "$3, $1 obtuvo los usuarios de $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 obtuvo las contribuciones de XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 obtuvo los usuarios de XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 obtuvo las contribuciones de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 obtuvo los usuarios de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 obtuvo las contribuciones de XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 obtuvo los usuarios de XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 obtuvo las contribuciones de $2",
"checkuser-autocreate-action": "fue creada automáticamente",
"checkuser-create-action": "se creó",
@@ -112,26 +120,94 @@
"checkuser-login-success": "Inició sesión con éxito como \"$1\" en {{SITENAME}}",
"group-checkuser.css": "/* El código CSS colocado aquí sólo afectará a los usuarios con permisos de checkuser */",
"group-checkuser.js": "/* El código JavaScript colocado en esta página sólo afectará a los usuarios con permisos de checkuser */",
- "apihelp-query+checkuser-description": "Comprueba qué direcciones IP utiliza el nombre de usuario dado o qué nombres de usuario han utilizado una dirección IP específica.",
- "apihelp-query+checkuser-summary": "Comprobar qué direcciones IP han sido usadas por un determinado usuario o qué usuarios han usado una determinada dirección IP.",
- "apihelp-query+checkuser-param-request": "Tipos de solicitudes:\n;userips:Obtener las direcciones IP del usuario a verificar.\n;edits:Obtener las ediciones hechas desde una determinada dirección IP o rango de IPs.\n;ipusers:Obtener los usuarios que han usado una determinada dirección IP o rango de IPs.",
- "apihelp-query+checkuser-param-target": "Nombre de usuario, dirección IP o intervalo CIDR que comprobar.",
- "apihelp-query+checkuser-param-reason": "Motivo para comprobar.",
- "apihelp-query+checkuser-param-limit": "Límite de filas.",
- "apihelp-query+checkuser-param-timecond": "Límite de tiempo de datos del usuario (p. ej. \"-2 weeks\" o \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Utiliza datos XFF en lugar de direcciones IP.",
- "apihelp-query+checkuser-example-1": "Comprobar direcciones IP para [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Comprobar ediciones desde 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Obtener entradas del registro de verificación de usuarios.",
- "apihelp-query+checkuserlog-summary": "Obtener entradas del registro de verificación de usuarios.",
- "apihelp-query+checkuserlog-param-user": "Nombre del usuario con permiso de verificador de usuarios.",
- "apihelp-query+checkuserlog-param-target": "Se ha comprobado el usuario, dirección IP o CIDR.",
- "apihelp-query+checkuserlog-param-limit": "Límite de filas.",
- "apihelp-query+checkuserlog-param-from": "El sello de tiempo para comenzar la enumeración",
- "apihelp-query+checkuserlog-param-to": "El sello de tiempo para finalizar la enumeración",
- "apihelp-query+checkuserlog-example-1": "Mostrar verificaciones de [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Mostrar verificaciones de 192.0.2.0/24 después del 15 de octubre de 2011 a las 23:00:00",
- "apierror-checkuser-missingsummary": "Debes introducir una razón para la comprobación.",
- "apierror-checkuser-timelimit": "Necesitas introducir un plazo máximo de tiempo correcto (como \"-2 weeks\" o \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "Modo de solicitud no válido"
+ "checkuser-link-investigate-label": "Prueba la nueva herramienta CheckUser",
+ "checkuser-investigateblock": "Bloquear usuarios",
+ "checkuser-investigateblock-target": "Nombres de usuario y direcciones IP",
+ "checkuser-investigateblock-actions": "Acciones que bloquear",
+ "checkuser-investigateblock-reason": "Motivo",
+ "checkuser-investigateblock-options": "Opciones adicionales",
+ "checkuser-investigateblock-email-label": "Impedir que envíe correo electrónico",
+ "checkuser-investigateblock-usertalk-label": "Impedir la edición de su propia página de discusión mientras esté bloqueado",
+ "checkuser-investigateblock-reblock-label": "Hacer prevalecer sobre bloqueos existentes",
+ "checkuser-investigateblock-notice-user-page-label": "Dejar un aviso en la página del usuario",
+ "checkuser-investigateblock-notice-talk-page-label": "Dejar un aviso en la página de discusión del usuario",
+ "checkuser-investigateblock-notice-position-label": "Posición",
+ "checkuser-investigateblock-notice-text-label": "Wikitexto",
+ "checkuser-investigateblock-notice-append": "Añadir al final de la página",
+ "checkuser-investigateblock-notice-prepend": "Añadir al inicio de la página",
+ "checkuser-investigateblock-notice-replace": "Reemplazar página",
+ "checkuser-investigateblock-failure": "No se bloqueó a ningún usuario. Para hacer prevalecer este bloqueo sobre los ya existentes marca \"{{int:checkuser-investigateblock-reblock-label}}\". Si el bloqueo a imponer es idéntico a uno ya existente el bloqueo previo no se modificará.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|El usuario|Los usuarios}} $1 {{PLURAL:$2|ha|han}} sido {{PLURAL:$2|bloqueado|bloqueados}}.",
+ "checkuser-investigateblock-notices-failed": "Algunos avisos no han podido ser agregados a las páginas de usuario o sus páginas de discusión.",
+ "checkuser-investigate-log": "Registros de investigación",
+ "checkuser-investigate-log-entry": "El $3, $1 buscó información sobre <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "No se encontró ninguna entrada en el registro de investigación.",
+ "checkuser-investigate-log-subtitle": "Cambiar al formulario de investigación",
+ "checkuser-investigate": "Investigar",
+ "checkuser-investigate-page-subtitle": "Investigación actual para $1",
+ "checkuser-investigate-subtitle-block-button-label": "Bloquear",
+ "checkuser-investigate-subtitle-cancel-button-label": "Cancelar",
+ "checkuser-investigate-subtitle-continue-button-label": "Continuar",
+ "checkuser-investigate-indicator-new-investigation": "Investigación nueva",
+ "checkuser-investigate-indicator-logs": "Registros",
+ "checkuser-investigate-legend": "Buscar nombres de usuario, direcciones IP o intervalos de IP",
+ "checkuser-investigate-notice-no-results": "No hay resultados.",
+ "checkuser-investigate-tab-preliminary-check": "Información de la cuenta",
+ "checkuser-investigate-tab-compare": "Direcciones IP y agentes de usuario",
+ "checkuser-investigate-tab-timeline": "Cronograma",
+ "checkuser-investigate-targets-label": "Nombres de usuario y direcciones IP",
+ "checkuser-investigate-targets-placeholder": "Nombre de usuario o dirección IP",
+ "checkuser-investigate-duration-label": "Duración",
+ "checkuser-investigate-duration-option-all": "Todos",
+ "checkuser-investigate-duration-option-1w": "Semana pasada",
+ "checkuser-investigate-duration-option-2w": "Últimas 2 semanas",
+ "checkuser-investigate-duration-option-30d": "Últimos 30 días",
+ "checkuser-investigate-reason-label": "Motivo",
+ "checkuser-investigate-preliminary-notice-ip-targets": "La pestaña de información sobre las cuentas no incluye datos sobre direcciones IP. Para ver esos detalles ve a la <span class=\"plainlinks\">[$1 pestaña de usuarios y direcciones IP].</span>",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Bloqueado",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|edición|ediciones}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "No bloqueado",
+ "checkuser-investigate-preliminary-table-header-blocked": "Estado",
+ "checkuser-investigate-preliminary-table-header-editcount": "Ediciones",
+ "checkuser-investigate-preliminary-table-header-groups": "Grupos",
+ "checkuser-investigate-preliminary-table-header-name": "Nombre de usuario",
+ "checkuser-investigate-preliminary-table-header-registration": "Fecha de unificación",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki no encontrado",
+ "checkuser-investigate-filters-legend": "Filtros",
+ "checkuser-investigate-filters-exclude-targets-label": "Ocultar las cuentas o IP siguientes",
+ "checkuser-investigate-timeline-notice-no-results": "No hay resultados: no se ha registrado actividad de estos usuarios o IP en los últimos 90 días",
+ "checkuser-investigate-timeline-notice-no-results-filters": "No hay resultados que coincidan con estos criterios de filtrado. Intenta eliminar algunos filtros para ampliar la búsqueda.",
+ "checkuser-investigate-compare-copy-button-label": "Ver wikitexto",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Comprobar proxy",
+ "checkuser-investigate-compare-copy-message-label": "¿Deseas copiar esta información como tabla en formato wikitexto?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Como consecuencia de limitaciones técnicas hemos alcanzado el número máximo de registros que podemos presentarte. Los datos que se proporcionan en relación con este objetivo no están completos: $1. Prueba a usar menos objetivos, o bien reduce el rango de fechas o de direcciones IP.",
+ "checkuser-investigate-compare-notice-no-results": "No hay resultados: los usuarios o direcciones IP no han editado en los últimos 90 días",
+ "checkuser-investigate-compare-notice-no-results-filters": "No hay resultados que coincidan con los criterios de búsqueda empleados. Prueba a eliminar algunos filtros para ampliar la búsqueda.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Mostrar todas las IP de este usuario",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Mostrar todos los usuarios en esta IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Añadir esta IP a la investigación",
+ "checkuser-investigate-compare-table-button-checks-label": "Verificar",
+ "checkuser-investigate-compare-table-button-contribs-label": "Contribuciones",
+ "checkuser-investigate-compare-table-button-filter-label": "Filtrar desde resultados",
+ "checkuser-investigate-compare-table-cell-unregistered": "No registrado",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|edición|ediciones}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 de todos los usuarios)</i>",
+ "checkuser-investigate-compare-table-header-username": "Nombre de usuario",
+ "checkuser-investigate-compare-table-header-activity": "Intervalo de fechas",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Agente de usuario",
+ "checkuser-investigate-subtitle-link-restart-tour": "Reiniciar paseo",
+ "checkuser-investigate-tour-targets-title": "¿Comprobando múltiples usuarios y direcciones IP?",
+ "checkuser-investigate-tour-targets-desc": "Añade hasta $1 {{PLURAL:$1|usuario o dirección IP|usuarios o direcciones IP}} y obtén toda la información en un solo lugar. No te preocupes, crearemos una entrada de registro independiente para cada uno de ellos.",
+ "checkuser-investigate-tour-useragents-title": "¿Agentes de usuario que coincidan?",
+ "checkuser-investigate-tour-useragents-desc": "Pasa el puntero sobre una celda para resaltar todas las filas que tienen los mismos datos. Haz clic en el icono de la chincheta para mantener en resaltado mientras analizas el resto de la información.",
+ "checkuser-investigate-tour-addusertargets-title": "¿Hace falta más contexto?",
+ "checkuser-investigate-tour-addusertargets-desc": "Haz clic para ver todos los usuarios que usan esta dirección IP. Puedes hacer lo mismo con los usuarios y ver qué direcciones IP están utilizando. Crearemos entradas en el registro de verificaciones.",
+ "checkuser-investigate-tour-filterip-title": "¿Limitando tu investigación?",
+ "checkuser-investigate-tour-filterip-desc": "Elimina el desorden filtrando por nombres de usuario, direcciones IP o agentes de usuario. ¿Quieres obtener toda la información de vuelta? Usa el panel de filtros en la parte superior de la página para eliminarlos.",
+ "checkuser-investigate-tour-block-title": "¿Deseas bloquear?",
+ "checkuser-investigate-tour-block-desc": "Te permite seleccionar los usuarios que desees bloquear para posteriormente llevarte al formulario de bloqueo para que selecciones el que te parezca más apropiado.",
+ "checkuser-investigate-tour-copywikitext-title": "¿Quieres copiar los datos?",
+ "checkuser-investigate-tour-copywikitext-desc": "Copia la tabla comparativa con un solo clic y llévala a la wiki privada. Ten en cuenta que solo podrás copiar lo que ahora mismo es visible y no todas las páginas de la investigación."
}
diff --git a/CheckUser/i18n/et.json b/CheckUser/i18n/et.json
index fe9c0925..2896ed20 100644
--- a/CheckUser/i18n/et.json
+++ b/CheckUser/i18n/et.json
@@ -52,7 +52,6 @@
"checkuser-block-limit": "Liiga palju kasutajaid valitud.",
"checkuser-block-noreason": "Blokeeringule peab andma põhjenduse.",
"checkuser-noreason": "Päringu jaoks peab põhjuse andma.",
- "checkuser-accounts": "$1 {{PLURAL:$1|uus konto|uut kontot}}",
"checkuser-user-nonexistent": "Etteantud kasutajat pole olemas.",
"checkuser-search": "Kasutajakontrolli logi sissekannete otsimine",
"checkuser-search-submit": "Otsi",
diff --git a/CheckUser/i18n/eu.json b/CheckUser/i18n/eu.json
index 530cb322..6c59ea6f 100644
--- a/CheckUser/i18n/eu.json
+++ b/CheckUser/i18n/eu.json
@@ -2,10 +2,11 @@
"@metadata": {
"authors": [
"An13sa",
+ "Joseba",
"Kobazulo",
+ "Subi",
"Xabier Armendaritz",
- "පසිඳු කාවින්ද",
- "Subi"
+ "පසිඳු කාවින්ද"
]
},
"checkuser": "Erabiltzailea egiaztatu",
@@ -35,12 +36,13 @@
"checkuser-massblock-commit": "Blokeatu aukeratutako erabiltzaileak",
"checkuser-block-success": "'''$1 {{PLURAL:$2|erabiltzailea|erabiltzaileak}} blokeaturik {{PLURAL:$2|dago|daude}} orain.'''",
"checkuser-block-limit": "Lankide gehiegi hautatu duzu.",
- "checkuser-accounts": "{{PLURAL:$1|Kontu berri bat|$1 kontu berri}}",
- "checkuser-search": "Bilatu",
+ "checkuser-search": "Erregistroko sarrerak bilatu",
"checkuser-search-submit": "Bilatu",
"checkuser-search-target": "helburua",
"checkuser-autocreate-action": "automatikoki sortua izan da",
"checkuser-create-action": "sortu zen",
"checkuser-email-action": "\"$1\" lankideari posta elektroniko bat bidali",
- "checkuser-reset-action": "\"$1\" lankideari pasahitza berrezarri"
+ "checkuser-reset-action": "\"$1\" lankideari pasahitza berrezarri",
+ "checkuser-investigate-compare-notice-no-results-filters": "Filtratzeko irizpide hauek erabilita ez dago emaitzarik. Saiatu filtro batzuk ezabatzen bilaketa orokor baterako",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Ip honetako erabiltzaile guztiak erakutsi"
}
diff --git a/CheckUser/i18n/fa.json b/CheckUser/i18n/fa.json
index 1d537a8d..be9256c4 100644
--- a/CheckUser/i18n/fa.json
+++ b/CheckUser/i18n/fa.json
@@ -1,16 +1,18 @@
{
"@metadata": {
"authors": [
+ "Alirezaaa",
+ "Danialbehzadi",
+ "E THP",
"Ebraminio",
+ "FarsiNevis",
+ "GMozafarian",
"Huji",
"Mehran",
"MehranVB",
"Mjbmr",
"Reza1615",
- "ZxxZxxZ",
- "Alirezaaa",
- "Danialbehzadi",
- "GMozafarian"
+ "ZxxZxxZ"
]
},
"checkuser-summary": "این ابزار تغییرات اخیر را برای به دست آوردن نشانی‌های آی‌پی استفاده شده توسط یک کاربر و یا تعیین ویرایش‌ها و اطلاعات کاربری مرتبط با یک نشانی آی‌پی جستجو می‌کند.\nکاربرها و ویرایش‌های مرتبط با یک نشانی آی‌پی را می‌توان با توجه به اطلاعات سرآیند اکس‌اف‌اف (با افزودن «‏‎/xff» به انتهای نشانی آی‌پی) پیدا کرد.\nهر دو پروتکل IPv4 (معادل CIDR $1-32) و IPv6 (معادل CIDR $2-128) توسط این ابزار پشتیبانی می‌شوند.\nبنا به دلایل عملکردی، بیش از ۵۰۰۰ ویرایش بازگردانده نمی‌شود.\nاز این ابزار طبق سیاست‌ها استفاده کنید.",
@@ -68,7 +70,6 @@
"checkuser-block-noreason": "شما باید دلیلی برای قطع دسترسی‌ها ارائه کنید.",
"checkuser-centralauth-multilock": "بستن‌های چندگانه حساب‌های کاربری انتخاب‌شده",
"checkuser-noreason": "شما باید دلیلی برای این درخواست وارد کنید.",
- "checkuser-accounts": "$1 {{PLURAL:$1|حساب|حساب}} کاربری تازه",
"checkuser-too-many": "تعداد نتایج بسیار زیاد است (طبق تخمین‌های پرسمان)، لطفاً سی‌آی‌دی‌آر را محدودتر کنید.\nدر زیر نشانی‌های آی‌پی استفاده شده را می‌بینید (حداکثر ۵۰۰۰ مورد، به ترتیب نشانی):",
"checkuser-user-nonexistent": "کاربر مورد نظر وجود ندارد.",
"checkuser-search": "جستجوی موارد سیاههٔ بازرسی کاربر",
@@ -81,10 +82,10 @@
"checkuser-showmain": "رفتن به فرم اصلی بازرسی کاربر",
"checkuser-limited": "'''این نتایج برای کارآیی سامانه کوتاه شده‌اند.'''",
"checkuser-log-entry-userips": "$3، $1 نشانی‌های آی‌پی $2 را گرفت",
- "checkuser-log-entry-ipedits": "$3، $1 ویرایش‌های $2 را گرفت",
- "checkuser-log-entry-ipusers": "$3، $1 کاربرهای $2 را گرفت",
- "checkuser-log-entry-ipedits-xff": "$3، $1 ویرایش‌های اکس‌اف‌اف $2 را گرفت",
- "checkuser-log-entry-ipusers-xff": "$3، $1 کاربرهای اکس‌اف‌اف $2 را گرفت",
+ "checkuser-log-entry-ipedits": "$3، $1 ویرایش‌های <bdi>$2</bdi> را گرفت",
+ "checkuser-log-entry-ipusers": "$3، $1 کاربرهای <bdi>$2</bdi> را گرفت",
+ "checkuser-log-entry-ipedits-xff": "$3، $1 ویرایش‌های اکس‌اف‌اف <bdi>$2</bdi> را گرفت",
+ "checkuser-log-entry-ipusers-xff": "$3، $1 کاربرهای اکس‌اف‌اف <bdi>$2</bdi> را گرفت",
"checkuser-log-entry-useredits": "$3، $1 ویرایش‌های $2 را گرفت",
"checkuser-autocreate-action": "به طور خودکار ساخته شد",
"checkuser-create-action": "ایجاد شد",
@@ -93,26 +94,6 @@
"checkuser-token-fail": "نشست با شکست مواجه شد. لطفاً دوباره سعی کنید.",
"checkuser-login-failure": "در ورود به {{SITENAME}} با حساب $1 ناموفق بود",
"checkuser-login-success": "در ورود به {{SITENAME}} با حساب $1 موفق بود",
- "apihelp-query+checkuser-description": "بررسی کنید کدام نشانی‌های آی‌پی توسط یک حساب استفاده شده‌اند، یا کدام حساب‌ها توسط یک نشانی آی‌پی به کار رفته‌اند.",
- "apihelp-query+checkuser-summary": "بررسی کنید کدام نشانی‌های آی‌پی توسط یک حساب استفاده شده‌اند، یا کدام حساب‌ها توسط یک نشانی آی‌پی به کار رفته‌اند.",
- "apihelp-query+checkuser-param-request": "انواع درخواست‌های بازرسی کاربر:\n;userips: گرفتن نشانی آی‌پی کاربر هدف.\n;edits: گرفتن فهرست تغییرات مرتبط با یک نشانی یا بازهٔ آی‌پی\n;ipusers: گرفتن کاربرهای مرتبط با یک نشانی یا بازهٔ آی‌پی",
- "apihelp-query+checkuser-param-target": "نام کاربر، بازهٔ آی‌پی، یا بازهٔ سی‌آی‌دی‌آر که بازرسی می‌شود.",
- "apihelp-query+checkuser-param-reason": "دلیل بازرسی.",
- "apihelp-query+checkuser-param-limit": "محدودهٔ سطرها.",
- "apihelp-query+checkuser-param-timecond": "محدودهٔ زمانی دادهٔ کاربر (مثلاً «‎-2 weeks» یا «‎2 weeks ago»).",
- "apihelp-query+checkuser-param-xff": "به جای نشانی آی‌پی از اطلاعات اکس‌اف‌اف استفاده شود.",
- "apihelp-query+checkuser-example-1": "بازرسی نشانی‌های آی‌پی برای [[User:Example]]",
- "apihelp-query+checkuser-example-2": "بازرسی ویرایش‌های انجام شده از 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "دریافت موارد از سیاههٔ بازرسی.",
- "apihelp-query+checkuserlog-summary": "دریافت موارد از سیاههٔ بازرسی.",
- "apihelp-query+checkuserlog-param-user": "نام کاربری بازرس.",
- "apihelp-query+checkuserlog-param-target": "بازرسی کاربر، نشانی آی‌پی، یا بازهٔ سی‌آی‌دی‌آر.",
- "apihelp-query+checkuserlog-param-limit": "محدودیت ردیف‌ها.",
- "apihelp-query+checkuserlog-param-from": "برچسب زمان برای شروع شمارش.",
- "apihelp-query+checkuserlog-param-to": "برچسب زمان برای پایان شمارش.",
- "apihelp-query+checkuserlog-example-1": "نمایش بازرسی‌های [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "نمایش بازرسی‌های 192.0.2.0/24 پس از 2011‎-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "باید دلیل بازرسی را مشخص کنید.",
- "apierror-checkuser-timelimit": "باید بازهٔ زمانی درست استفاده کنید (نظیر «‎2 weeks ago» یا «‎-2 weeks»).",
- "apierror-checkuser-invalidmode": "شیوهٔ درخواست نامعتبر"
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "ویکی یافته نشد",
+ "checkuser-investigate-compare-table-button-filter-label": "پالایش نتایج"
}
diff --git a/CheckUser/i18n/fi.json b/CheckUser/i18n/fi.json
index cb09b0d0..8188324a 100644
--- a/CheckUser/i18n/fi.json
+++ b/CheckUser/i18n/fi.json
@@ -1,21 +1,23 @@
{
"@metadata": {
"authors": [
+ "01miki10",
"Agony",
"Beluga",
"Cimon Avaro",
"Crt",
"Jaakonam",
"Jack Phoenix",
+ "McSalama",
"Nike",
"Olli",
"Pxos",
+ "Pyscowicz",
"Str4nd",
"Stryn",
+ "Valtlait",
"Varusmies",
- "ZeiP",
- "McSalama",
- "01miki10"
+ "ZeiP"
]
},
"checkuser-summary": "Tämän työkalun avulla voidaan tutkia tuoreet muutokset ja paljastaa käyttäjien IP-osoitteet tai noutaa IP-osoitteiden muokkaukset ja käyttäjätiedot.\nKäyttäjät ja muokkaukset voidaan hakea myös uudelleenohjausosoitteen (X-Forwarded-For) takaa käyttämällä IP-osoitteen perässä <tt>/xff</tt> -merkintää. Työkalu tukee sekä IPv4 (CIDR $1–32) ja IPv6 (CIDR $2–128) -standardeja.",
@@ -36,7 +38,7 @@
"checkuser-reason-api": "API: $1",
"checkuser-showlog": "Näytä osoitepaljastinloki",
"checkuser-query": "Hae tuoreet muutokset",
- "checkuser-target": "IP-osoite tai käyttäjätunnus:",
+ "checkuser-target": "IP-osoite tai käyttäjänimi:",
"checkuser-users": "Hae käyttäjät",
"checkuser-edits": "Hae muokkaukset",
"checkuser-ips": "Hae IP-osoitteet",
@@ -61,7 +63,7 @@
"checkuser-wasblocked": "Aiemmin estetyt",
"checkuser-localonly": "Ei yhdistettynä",
"checkuser-massblock": "Estä valitut käyttäjät",
- "checkuser-massblock-text": "Valitut tunnukset estetään toistaiseksi (\"autoblocking\", \"tunnusten luonti estetty\").\nVain rekisteröimättömien käyttäjien IP-osoitteet estetään yhdeksi viikoksi (myös tunnusten luonti estetty).",
+ "checkuser-massblock-text": "Valitut tunnukset estetään toistaiseksi (”autoblocking”, ”tunnusten luonti estetty”).\nVain rekisteröimättömien käyttäjien IP-osoitteet estetään yhdeksi viikoksi (myös tunnusten luonti estetty).",
"checkuser-blockemail": "Estä sähköpostin lähettäminen",
"checkuser-blocktalk": "Estä käyttäjää muokkaamasta omaa keskustelusivuaan eston aikana",
"checkuser-blocktag": "Korvaa käyttäjäsivut sisällöllä:",
@@ -73,7 +75,6 @@
"checkuser-block-noreason": "Estoille on annettava syy.",
"checkuser-centralauth-multilock": "Lukitse valitut tunnukset",
"checkuser-noreason": "Sinun tulee antaa syy tälle kyselylle.",
- "checkuser-accounts": "$1 {{PLURAL:$1|uusi tunnus|uutta tunnusta}}",
"checkuser-too-many": "Liian monta tulosta (kyselyarvion mukaan), pienennä CIDR-aluetta.\nKäytetyt IP-osoitteet (enintään 5000, järjestetty osoitteen mukaan):",
"checkuser-user-nonexistent": "Määritettyä käyttäjää ei ole olemassa.",
"checkuser-search": "Etsi osoitinpaljastinlokin merkinnöistä",
@@ -86,12 +87,16 @@
"checkuser-showmain": "Siirry osoitepaljastimen päälomakkeeseen",
"checkuser-limited": "'''Nämä tulokset on lyhennetty suorituskykysyistä.'''",
"checkuser-log-entry-userips": "$3, $1 haki käyttäjän $2 IP-osoitteet",
- "checkuser-log-entry-ipedits": "$3, $1 haki IP-osoitteen $2 muokkaukset",
- "checkuser-log-entry-ipusers": "$3, $1 haki IP-osoitteen $2 käyttäjät",
+ "checkuser-log-entry-ipedits": "$3, $1 haki IP-osoitteen <bdi>$2</bdi> muokkaukset",
+ "checkuser-log-entry-ipusers": "$3, $1 haki IP-osoitteen <bdi>$2</bdi> käyttäjät",
"checkuser-log-entry-useredits": "$3, $1 haki käyttäjän $2 muokkaukset",
"checkuser-autocreate-action": "luotiin automaattisesti",
"checkuser-create-action": "luotiin",
"checkuser-email-action": "käyttäjälle ”$1” lähetetty sähköpostiviesti",
"checkuser-reset-action": "käyttäjän ”$1” salasana nollattu",
- "checkuser-token-fail": "Istuntovirhe. Ole hyvä ja yritä uudelleen."
+ "checkuser-token-fail": "Istuntovirhe. Ole hyvä ja yritä uudelleen.",
+ "checkuser-investigate-subtitle-block-button-label": "Estä",
+ "checkuser-investigate-subtitle-cancel-button-label": "Peruuta",
+ "checkuser-investigate-subtitle-continue-button-label": "Jatka",
+ "checkuser-investigate-compare-table-button-contribs-label": "Muokkaukset"
}
diff --git a/CheckUser/i18n/fit.json b/CheckUser/i18n/fit.json
new file mode 100644
index 00000000..a4c61431
--- /dev/null
+++ b/CheckUser/i18n/fit.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pyscowicz"
+ ]
+ },
+ "checkuser-edits": "Hae mookkaukset",
+ "checkuser-check": "Jysteeraa"
+}
diff --git a/CheckUser/i18n/fr.json b/CheckUser/i18n/fr.json
index afc7136b..599e238c 100644
--- a/CheckUser/i18n/fr.json
+++ b/CheckUser/i18n/fr.json
@@ -1,29 +1,35 @@
{
"@metadata": {
"authors": [
+ "Actualisateur",
"ChrisPtDe",
"DavidL",
+ "Derugon",
+ "Eihel",
+ "Element303",
+ "Eneelk",
"Gomoko",
"Grondin",
"IAlex",
+ "Lbayle",
+ "McDutchie",
+ "Orlodrim",
+ "Pamputt",
"Peter17",
"PieRRoMaN",
"Quentinv57",
"Sherbrooke",
+ "Thibaut120094",
"Urhixidur",
"Verdy p",
+ "Wladek92",
"Wyz",
- "Zetud",
- "Element303",
- "Orlodrim",
- "Lbayle",
"Yasten",
- "Wladek92",
- "McDutchie"
+ "Zetud"
]
},
"checkuser-summary": "Cet outil parcourt la liste des changements récents à la recherche des adresses IP employées par un utilisateur ou affiche toutes les données utilisateur d’une adresse IP.\nLes comptes et les modifications faites par une adresse IP cliente peuvent être récupérés via les entêtes XFF en suffixant l’adresse IP avec \"/xff\". Les adresses IPv4 (CIDR /$1 à /32) et IPv6 (CIDR /$2 à /128) sont prises en charge.\nPas plus de 5000 modifications ne seront renvoyées, pour des questions de performance.\nVeuillez utiliser cet outil dans le respect de la charte d’utilisation.",
- "checkuser-desc": "Donne la possibilité aux utilisateurs dûment autorisés de vérifier les adresses IP des utilisateurs ainsi que d’autres informations les concernant",
+ "checkuser-desc": "Donne la possibilité aux utilisateurs dûment autorisés de vérifier les adresses IP des utilisateurs ainsi que d’autres informations",
"checkuser-logcase": "La recherche dans le journal est sensible à la casse.",
"checkuser": "Vérificateur d’utilisateur",
"checkuserlog": "Journal des vérifications d’utilisateurs",
@@ -33,7 +39,7 @@
"group-checkuser-member": "{{GENDER:$1|vérificateur d’utilisateur|vérificatrice d’utilisateur}}",
"right-checkuser": "Vérifier les adresses IP et autres informations d’un utilisateur",
"right-checkuser-log": "Visualiser le journal des vérifications d’utilisateurs",
- "action-checkuser": "vérifier les adresses IP de l’utilisateur et d’autres informations",
+ "action-checkuser": "vérifier les adresses IP des utilisateurs et d’autres informations",
"action-checkuser-log": "Visualiser le journal des vérifications des utilisateurs",
"grouppage-checkuser": "{{ns:project}}:Vérificateurs d’utilisateurs",
"checkuser-reason": "Motif :",
@@ -70,6 +76,7 @@
"checkuser-blocktalk": "Empêcher l’utilisateur de modifier sa page de discussion pendant le blocage",
"checkuser-blocktag": "Remplacer les pages d’utilisateur par :",
"checkuser-blocktag-talk": "Remplacer les pages de discussion par :",
+ "checkuser-reblock": "Remplacer les blocs existants",
"checkuser-massblock-commit": "Bloquer les utilisateurs sélectionnés",
"checkuser-block-success": "'''{{PLURAL:$2|L’utilisateur $1 est maintenant bloqué|Les $2 utilisateurs suivants sont maintenant bloqués : $1}}.'''",
"checkuser-block-failure": "'''Aucun utilisateur bloqué.'''",
@@ -77,10 +84,9 @@
"checkuser-block-noreason": "Vous devez donner un motif justifiant les blocages.",
"checkuser-centralauth-multilock": "Verrouiller les comptes sélectionnés",
"checkuser-noreason": "Vous devez donner une raison pour cette requête.",
- "checkuser-accounts": "$1 nouveau{{PLURAL:$1||x}} compte{{PLURAL:$1||s}}",
- "checkuser-too-many": "Trop de résultats (selon l’estimation de la requête), veuillez affiner l’étendue CIDR.\nVoici un extrait des adresses IP utilisées ({{formatnum:5000}} maximum, triées par adresse) :",
+ "checkuser-too-many": "Trop de résultats (selon l’estimation de la requête), veuillez affiner l’étendue CIDR.\nVoici un extrait des adresses IP utilisées ($1 maximum, triées par adresse) :",
"checkuser-user-nonexistent": "L’utilisateur indiqué n’existe pas.",
- "checkuser-search": "Rechercher ,les entrées de journal de vérification utilisateur",
+ "checkuser-search": "Rechercher les entrées du journal de vérification d’utilisateur",
"checkuser-search-submit": "Rechercher",
"checkuser-search-initiator": "l’initiateur",
"checkuser-search-target": "la cible",
@@ -90,10 +96,10 @@
"checkuser-showmain": "Basculer vers le formulaire principal du vérificateur d’utilisateur",
"checkuser-limited": "'''Ces résultats ont été tronqués pour des raisons liées à la performance.'''",
"checkuser-log-entry-userips": "$3, $1 a récupéré les adresses IP pour $2",
- "checkuser-log-entry-ipedits": "$3, $1 a récupéré les modifications pour $2",
- "checkuser-log-entry-ipusers": "$3, $1 a récupéré les utilisateurs pour $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 a récupéré les modifications pour $2 XFF",
- "checkuser-log-entry-ipusers-xff": "$3, $1 a récupéré les utilisateurs pour $2 XFF",
+ "checkuser-log-entry-ipedits": "$3, $1 a récupéré les modifications pour <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 a récupéré les utilisateurs pour <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 a récupéré les modifications pour <bdi>$2</bdi> XFF",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 a récupéré les utilisateurs pour <bdi>$2</bdi> XFF",
"checkuser-log-entry-useredits": "$3, $1 a récupéré les modifications pour $2",
"checkuser-autocreate-action": "a été créé automatiquement",
"checkuser-create-action": "a été créé",
@@ -104,26 +110,95 @@
"checkuser-login-success": "Connexion réussie à {{SITENAME}} en tant que $1",
"group-checkuser.css": "/* Le CSS placé ici n’affectera que les membres du groupe « checkuser » */",
"group-checkuser.js": "/* Le Javascript placé ici n’affectera que les membres du groupe « checkuser » */",
- "apihelp-query+checkuser-description": "Vérifier quelles adresses IP sont utilisées par un nom d’utilisateur donné ou quels noms d’utilisateur sont utilisés par une adresse IP donnée.",
- "apihelp-query+checkuser-summary": "Vérifier quelles adresses IP sont utilisées pour un nom d’utilisateur donné, ou quels noms d’utilisateur sont utilisés pour une adresse IP donnée.",
- "apihelp-query+checkuser-param-request": "Type de demande CheckUser :\n;userips:Obtenir l’adresse IP de l’utilisateur cible.\n;edits:Obtenir les modifications de l’adresse IP ou de la plage cible.\n;ipusers:Obtenir les utilisateurs de l’adresse IP ou de la plage cible.",
- "apihelp-query+checkuser-param-target": "Nom d'utilisateur, adresse IP ou plage CIDR à vérifier.",
- "apihelp-query+checkuser-param-reason": "Motif de vérification.",
- "apihelp-query+checkuser-param-limit": "Limite de lignes.",
- "apihelp-query+checkuser-param-timecond": "Limite de temps des données de l'utilisateur (comme \"-2 weeks\" ou \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Utiliser des données XFF au lieu d'adresse IP.",
- "apihelp-query+checkuser-example-1": "Vérifier les adresses IP pour [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Vérifier les modifications pour 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Obtenir les entrées du journal CheckUser.",
- "apihelp-query+checkuserlog-summary": "Obtenir les entrées du journal de vérification des utilisateurs.",
- "apihelp-query+checkuserlog-param-user": "Nom d’utilisateur de CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Utilisateur, adresse IP ou plage CIDR vérifié.",
- "apihelp-query+checkuserlog-param-limit": "Limite de lignes.",
- "apihelp-query+checkuserlog-param-from": "L’horodatage auquel démarrer l’énumération.",
- "apihelp-query+checkuserlog-param-to": "L’horodatage auquel arrêter l’énumération.",
- "apihelp-query+checkuserlog-example-1": "Afficher les vérifications de [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Afficher les vérifications de 192.0.2.0/24 après 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Vous devez définir la raison pour laquelle le contrôle est fait.",
- "apierror-checkuser-timelimit": "Vous devez utiliser une limite de temps correcte (comme \"-2 weeks\" ou \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "Mode de requête invalide"
+ "checkuser-link-investigate-label": "Essayer le nouvel outil CheckUser",
+ "checkuser-investigateblock": "Bloquer les utilisateurs",
+ "checkuser-investigateblock-target": "Noms d’utilisateur et adresses IP",
+ "checkuser-investigateblock-actions": "Actions à bloquer",
+ "checkuser-investigateblock-reason": "Motif",
+ "checkuser-investigateblock-options": "Options supplémentaires",
+ "checkuser-investigateblock-email-label": "Empêcher l’envoi de courriel",
+ "checkuser-investigateblock-usertalk-label": "Empêcher de modifier sa propre page de discussion lorsque l'on est bloqué",
+ "checkuser-investigateblock-reblock-label": "Écraser les blocages existants",
+ "checkuser-investigateblock-notice-user-page-label": "Laisser une note sur une page utilisateur",
+ "checkuser-investigateblock-notice-talk-page-label": "Laisser une note sur une page de discussion utilisateur",
+ "checkuser-investigateblock-notice-position-label": "Position",
+ "checkuser-investigateblock-notice-text-label": "Wikitexte",
+ "checkuser-investigateblock-notice-append": "Ajouter à la page",
+ "checkuser-investigateblock-notice-prepend": "Mettre au début de la page",
+ "checkuser-investigateblock-notice-replace": "Remplacer la page",
+ "checkuser-investigateblock-failure": "Aucun utilisateur n’a été bloqué. Pour confirmer les blocages existants, cocher « {{int:checkuser-investigateblock-reblock-label}} ». Un blocage ne sera pas écrasé si le nouveau est identique à l’existant.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|L’utilisateur $1 est désormais bloqué|Les utilisateurs $1 sont désormais bloqués}}.",
+ "checkuser-investigateblock-notices-failed": "Certaines notes ne peuvent pas être ajoutées aux pages utilisateur ou aux pages de discussion utilisateur.",
+ "checkuser-investigate-log": "Journaux des investigations",
+ "checkuser-investigate-log-entry": "$3, $1 a recherché des informations sur <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Aucun entrée trouvée dans le journal des investigations.",
+ "checkuser-investigate-log-subtitle": "Basculer vers le formulaire d’investigation",
+ "checkuser-investigate": "Enquêter",
+ "checkuser-investigate-page-subtitle": "Investigation actuelle pour $1",
+ "checkuser-investigate-subtitle-block-button-label": "Bloquer",
+ "checkuser-investigate-subtitle-cancel-button-label": "Annuler",
+ "checkuser-investigate-subtitle-continue-button-label": "Continuer",
+ "checkuser-investigate-indicator-new-investigation": "Nouvelle investigation",
+ "checkuser-investigate-indicator-logs": "Journaux",
+ "checkuser-investigate-legend": "Rechercher des noms d’utilisateur, des adresses IP ou des plages d’adresse IP",
+ "checkuser-investigate-notice-no-results": "Il n’y a aucun résultat.",
+ "checkuser-investigate-tab-preliminary-check": "Information de compte",
+ "checkuser-investigate-tab-compare": "Adresses IP et agents utilisateur",
+ "checkuser-investigate-tab-timeline": "Planification",
+ "checkuser-investigate-targets-label": "Noms d’utilisateurs et adresses IP",
+ "checkuser-investigate-targets-placeholder": "Nom d’utilisateur ou 1.1.1.1",
+ "checkuser-investigate-duration-label": "Durée",
+ "checkuser-investigate-duration-option-all": "Toutes",
+ "checkuser-investigate-duration-option-1w": "Semaine dernière",
+ "checkuser-investigate-duration-option-2w": "2 dernières semaines",
+ "checkuser-investigate-duration-option-30d": "30 derniers jours",
+ "checkuser-investigate-reason-label": "Motif",
+ "checkuser-investigate-preliminary-notice-ip-targets": "L’onglet des informations de compte n’inclut aucune information sur les adresses IP. Voir l’<span class=\"plainlinks\">[$1 onglet Adresses IP et agents utilisateur]</span> pour ces détails.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Bloqué",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|modification|modifications}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Non bloqué",
+ "checkuser-investigate-preliminary-table-header-blocked": "État",
+ "checkuser-investigate-preliminary-table-header-editcount": "Modifications",
+ "checkuser-investigate-preliminary-table-header-groups": "Groupes",
+ "checkuser-investigate-preliminary-table-header-name": "Nom d’utilisateur",
+ "checkuser-investigate-preliminary-table-header-registration": "Date attachée",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki introuvable",
+ "checkuser-investigate-filters-legend": "Filtres",
+ "checkuser-investigate-filters-exclude-targets-label": "Masquer les utilisateurs ou adresses IP suivants",
+ "checkuser-investigate-timeline-notice-no-results": "Il n’y a pas de résultat : il n’y a pas eu d’activité enregistrée pour ces utilisateurs ou ces adresses IP dans les 90 derniers jours",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Il n’y a pas de résultat correspondant à ces critères de filtrage. Essayez de supprimer certains filtres pour élargir la recherche.",
+ "checkuser-investigate-compare-copy-button-label": "Afficher le wikitexte",
+ "checkuser-investigate-compare-toollinks-whois": "WHOIS/RDNS",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Vérification du mandataire",
+ "checkuser-investigate-compare-copy-message-label": "Souhaitez-vous copier ces informations sous forme de tableau wikitexte ?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Suite à des limitations techniques nous avons atteint la limite du nombre d’enregistrements présentables. Les données renvoyées pour les cibles suivantes sont incomplètes : $1. Veuillez réessayer en utilisant moins de cibles, une fenêtre de temps plus fine ou des plages IP plus étroites.",
+ "checkuser-investigate-compare-notice-no-results": "Il n’y a pas de résultat : il n’y a pas eu de modification faite par ces utilisateurs ou des adresses IP au cours des quatre-vingt-dix derniers jours",
+ "checkuser-investigate-compare-notice-no-results-filters": "Il n’y a pas de résultat correspondant à ces critères de filtrage. Essayez d'enlever certains filtres pour élargir la recherche.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Afficher toues les adresses IP de cet utilisateur",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Afficher tous les utilisateurs ayant cette adresse IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Ajouter cette adresse IP pour investigation",
+ "checkuser-investigate-compare-table-button-checks-label": "Vérifier",
+ "checkuser-investigate-compare-table-button-contribs-label": "Contributions",
+ "checkuser-investigate-compare-table-button-filter-label": "Filtrer les résultats",
+ "checkuser-investigate-compare-table-cell-unregistered": "Non inscrit",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|modification|modifications}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 de tous les utilisateurs)</i>",
+ "checkuser-investigate-compare-table-header-username": "Nom d’utilisateur",
+ "checkuser-investigate-compare-table-header-activity": "Plage de dates",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Agent utilisateur",
+ "checkuser-investigate-subtitle-link-restart-tour": "Recommencer le tour",
+ "checkuser-investigate-tour-targets-title": "Vérification de plusieurs utilisateurs et adresses IP ?",
+ "checkuser-investigate-tour-targets-desc": "Ajoutez jusqu’à $1 {{PLURAL:$1|Nom d’utilisateur ou IP|Noms d’utilisateur ou IP}} et obtenez toutes les informations en un seul endroit. Ne vous inquiétez pas, nous allons créer un journal Vérificateur d’adresses IP distinct pour chacun d’eux.",
+ "checkuser-investigate-tour-useragents-title": "Correspondance d'agents utilisateur",
+ "checkuser-investigate-tour-useragents-desc": "Passez la souris sur une cellule pour mettre en surbrillance toutes les autres lignes contenant les mêmes données. Cliquez sur l’icône de la punaise pour conserver la surbrillance pendant que vous parcourez les données.",
+ "checkuser-investigate-tour-addusertargets-title": "Besoin de plus de contexte ?",
+ "checkuser-investigate-tour-addusertargets-desc": "Cliquez pour voir tous les autres utilisateurs sur l’IP. Vous pouvez également le faire pour les utilisateurs et voir toutes les adresses IP qu’ils utilisent. Nous créerons automatiquement un élément de journal Vérificateurs d'adresses IP pour vous.",
+ "checkuser-investigate-tour-filterip-title": "Affiner votre investigation ?",
+ "checkuser-investigate-tour-filterip-desc": "Supprimez l’encombrement en filtrant les noms d’utilisateur, les adresses IP ou les agents utilisateurs. Désirez-vous récupérer les données ? Utilisez le panneau Filtres en haut pour retirer les filtres.",
+ "checkuser-investigate-tour-block-title": "Voulez-vous bloquer ?",
+ "checkuser-investigate-tour-block-desc": "Vous permet de sélectionner les utilisateurs que vous souhaitez bloquer, puis vous amène au formulaire de blocage pour choisir le blocage approprié.",
+ "checkuser-investigate-tour-copywikitext-title": "Voulez-vous copier les données ?",
+ "checkuser-investigate-tour-copywikitext-desc": "Copiez la table de comparaison en un seul clic et amenez-la dans CUWiki. Notez que vous ne copiez que ce qui est visible et non toutes les pages de l’enquête."
}
diff --git a/CheckUser/i18n/frp.json b/CheckUser/i18n/frp.json
index e098d679..8aa1999c 100644
--- a/CheckUser/i18n/frp.json
+++ b/CheckUser/i18n/frp.json
@@ -53,7 +53,6 @@
"checkuser-block-limit": "Trop d’usanciérs chouèsis.",
"checkuser-block-noreason": "Vos dête balyér una rêson por los blocâjos.",
"checkuser-noreason": "Vos dête balyér una rêson por cela requéta.",
- "checkuser-accounts": "$1 compto{{PLURAL:$1||s}} novél{{PLURAL:$1||s}}",
"checkuser-too-many": "Trop de rèsultats (d’aprés l’èstimacion de la requéta), volyéd èpurar l’ètendua CIDR.\nVê-que un èxtrèt a les adrèces IP utilisâs ({{formatnum:5000}} u més, triyês per adrèce) :",
"checkuser-user-nonexistent": "L’utilisator spècifiâ ègziste pas.",
"checkuser-search": "Rechèrche",
diff --git a/CheckUser/i18n/fy.json b/CheckUser/i18n/fy.json
index 5a817bea..0fb0bad6 100644
--- a/CheckUser/i18n/fy.json
+++ b/CheckUser/i18n/fy.json
@@ -1,11 +1,16 @@
{
"@metadata": {
"authors": [
- "Snakesteuben",
+ "PiefPafPier",
+ "Robin van der Vliet",
"Robin0van0der0vliet",
- "Robin van der Vliet"
+ "Snakesteuben"
]
},
+ "group-checkuser": "Meidoggerneisjoggers",
+ "group-checkuser-member": "meidogger{{GENDER:$1|neisjogger|neisjochster}}",
+ "right-checkuser": "IP-adressen en oare ynformaasje fan meidoggers kontrolearje",
+ "grouppage-checkuser": "{{ns:project}}:Meidoggerneisjoggers",
"checkuser-reason": "Reden:",
"checkuser-search": "Sykje",
"checkuser-search-submit": "Sykje"
diff --git a/CheckUser/i18n/ga.json b/CheckUser/i18n/ga.json
index c3832e08..bfa7650c 100644
--- a/CheckUser/i18n/ga.json
+++ b/CheckUser/i18n/ga.json
@@ -37,7 +37,6 @@
"checkuser-massblock-commit": "Cur cosc ar na n-úsáideoirí roghnaithe",
"checkuser-block-success": "'''Tá {{PLURAL:$2|an úsáideoir|na n-úsáideoirí}} $1 coiscthe anois.'''",
"checkuser-block-failure": "'''Níl aon úsáideoirí coiscthe.'''",
- "checkuser-accounts": "{{PLURAL:$1|Cuntas amháin|$1 cuntais}} nua",
"checkuser-too-many": "Tá le mórán torthaí (de réir meastachán cheist), caolaigh an CIDR le d'thoil.\nSeo iad na seolaidh IP (5000 uasta, sórtáilte le seoladh):",
"checkuser-search": "Cuardaigh",
"checkuser-search-submit": "Cuardaigh",
diff --git a/CheckUser/i18n/gan-hans.json b/CheckUser/i18n/gan-hans.json
index c3319e8b..42d0bdbc 100644
--- a/CheckUser/i18n/gan-hans.json
+++ b/CheckUser/i18n/gan-hans.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser-search": "寻吖",
"checkuser-search-submit": "寻吖"
}
diff --git a/CheckUser/i18n/gcr.json b/CheckUser/i18n/gcr.json
new file mode 100644
index 00000000..e126bec1
--- /dev/null
+++ b/CheckUser/i18n/gcr.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "LeGuyanaisPure"
+ ]
+ },
+ "group-checkuser": "Vérifikatò di itilizatò"
+}
diff --git a/CheckUser/i18n/gl.json b/CheckUser/i18n/gl.json
index e94aaade..e38517c5 100644
--- a/CheckUser/i18n/gl.json
+++ b/CheckUser/i18n/gl.json
@@ -2,13 +2,13 @@
"@metadata": {
"authors": [
"Alma",
- "Toliño",
- "Xosé",
"Banjo",
- "Fisterraeomar",
"Elisardojm",
+ "Fisterraeomar",
"Macofe",
- "McDutchie"
+ "McDutchie",
+ "Toliño",
+ "Xosé"
]
},
"checkuser-summary": "Esta ferramenta analiza os cambios para recuperar os enderezos IP utilizados por un usuario ou amosar as edicións ou os datos de usuario dun enderezo IP.\nOs usuarios e as edicións dun cliente IP poden recuperarse a través de cabeceiras XFF, engadindo o sufixo \"/xff\" ao enderezo IP. IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128) están soportados.\nNon se devolverán máis de 5.000 edicións por motivos de rendemento.\nUse isto de acordo coas políticas.",
@@ -66,7 +66,6 @@
"checkuser-block-noreason": "Debe dar unha razón para os bloqueos.",
"checkuser-centralauth-multilock": "Bloquear contas múltiples seleccionadas",
"checkuser-noreason": "Debe dar unha razón para esta pescuda.",
- "checkuser-accounts": "{{PLURAL:$1|Unha nova conta|$1 novas contas}}",
"checkuser-too-many": "Hai demasiados resultados (segundo a estimación da pescuda), restrinxa o CIDR.\nAquí están os enderezos IP usados (máximo de 5.000, ordenados por enderezo):",
"checkuser-user-nonexistent": "O usuario especificado non existe.",
"checkuser-search": "Procurar as entradas do rexistro de verificación de usuarios",
@@ -79,10 +78,10 @@
"checkuser-showmain": "Cambiar ao formulario principal de verificador de usuarios",
"checkuser-limited": "'''Estes resultados foron truncados por motivos de rendemento.'''",
"checkuser-log-entry-userips": "$3, $1 obtivo as direccións IP de $2",
- "checkuser-log-entry-ipedits": "$3, $1 obtivo as contribucións de $2",
- "checkuser-log-entry-ipusers": "$3, $1 obtivo os usuarios de $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 obtivo as contribucións de XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 obtivo os usuarios de XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 obtivo as contribucións de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 obtivo os usuarios de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 obtivo as contribucións de XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 obtivo os usuarios de XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 obtivo as contribucións de $2",
"checkuser-autocreate-action": "foi creada automaticamente",
"checkuser-create-action": "foi creada",
@@ -92,27 +91,5 @@
"checkuser-login-failure": "Non se puido acceder a {{SITENAME}} como $1",
"checkuser-login-success": "Acceso con éxito a {{SITENAME}} como $1",
"group-checkuser.css": "/* O CSS que se coloque aquí afectará soamente aos verificadores de usuarios */",
- "group-checkuser.js": "/* O JS que se coloque aquí afectará soamente aos verificadores de usuarios */",
- "apihelp-query+checkuser-description": "Comprobar que enderezos IP son empregados por un usuario concreto ou que nomes de usuario son empregados por un IP específico.",
- "apihelp-query+checkuser-summary": "Comprobar que enderezos IP son empregados por un usuario concreto ou que nomes de usuario son empregados por un IP específico.",
- "apihelp-query+checkuser-param-request": "Tipo da petición CheckUser:\n;userips: Retornar o enderezo IP do usuario obxetivo.\n;edits: Retornar os cambios do enderezo IP ou rango obxetivo.\n;ipusers: Retornar os usuarios do enderezo IP ou rango obxetivo.",
- "apihelp-query+checkuser-param-target": "Nome de usuario, dirección IP, ou rango CIDR a comprobar.",
- "apihelp-query+checkuser-param-reason": "Motivo para a comprobación.",
- "apihelp-query+checkuser-param-limit": "Límite de filas.",
- "apihelp-query+checkuser-param-timecond": "Límite de tempo dos datos de usuario (coma \"-2 weeks\" ou \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Usar datos XFF no canto do enderezo IP.",
- "apihelp-query+checkuser-example-1": "Comprobar enderezos IP para [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Comprobar as edicións de 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Retornar entradas do rexistro de CheckUser",
- "apihelp-query+checkuserlog-summary": "Retornar entradas do rexistro de CheckUser",
- "apihelp-query+checkuserlog-param-user": "Nome de usuario do CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Usuario comprobado, enderezo IP, ou rango CIDR.",
- "apihelp-query+checkuserlog-param-limit": "Límite de filas.",
- "apihelp-query+checkuserlog-param-from": "Selo de tempo no que comezar a enumeración.",
- "apihelp-query+checkuserlog-param-to": "Selo de tempo para rematar a enumeración.",
- "apihelp-query+checkuserlog-example-1": "Amosar as comprobacións de [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Amosar as comprobacións de 192.0.2.0/24 despois de 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Debes definir un motivo para comprobar.",
- "apierror-checkuser-timelimit": "Debe usar un límite de tempo correcto (como \"-2 weeks\" ou \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "Modo de petición non válido"
+ "group-checkuser.js": "/* O JS que se coloque aquí afectará soamente aos verificadores de usuarios */"
}
diff --git a/CheckUser/i18n/got.json b/CheckUser/i18n/got.json
index fb0fe917..b429ca11 100644
--- a/CheckUser/i18n/got.json
+++ b/CheckUser/i18n/got.json
@@ -4,7 +4,5 @@
"Gothicspeaker"
]
},
- "checkuser-reason": "𐍆𐌰𐌹𐍂𐌹𐌽𐌰:",
- "apihelp-query+checkuser-param-target": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉, IP 𐍂𐌰𐌸𐌾𐍉, 𐌰𐌹𐌸𐌸𐌰𐌿 CIDR",
- "apihelp-query+checkuser-param-xff": "𐌱𐍂𐌿𐌺𐌴𐌹 𐍇𐍆𐍆 𐌲𐌹𐌱𐍉𐍃 𐌽𐌹𐌷 IP 𐍂𐌰𐌸𐌾𐍉."
+ "checkuser-reason": "𐍆𐌰𐌹𐍂𐌹𐌽𐌰:"
}
diff --git a/CheckUser/i18n/gsw.json b/CheckUser/i18n/gsw.json
index 2a91744f..e0881695 100644
--- a/CheckUser/i18n/gsw.json
+++ b/CheckUser/i18n/gsw.json
@@ -56,7 +56,6 @@
"checkuser-block-limit": "S sin zvyl Benutzer usgwählt wore.",
"checkuser-block-noreason": "Du muesch e Grund fir d Sperri aagee.",
"checkuser-noreason": "Du muesch e Grund fir die Abfrog aagee.",
- "checkuser-accounts": "{{PLURAL:$1|1 nej Benutzerkonto|$1 neiji Benutzerkonte}}",
"checkuser-too-many": "D Ergebnislischt isch z lang (noch ere Abfrogs-Schätzig), bitte gränz dr IP-Beryych wyter yy. Do sin di benutzten IP-Adrässe (maximal 5000, sortiert noch Adrässe):",
"checkuser-user-nonexistent": "S Benutzerkonto, wu Du aagee hesch, isch nit vorhande.",
"checkuser-search": "Sueche",
diff --git a/CheckUser/i18n/gu.json b/CheckUser/i18n/gu.json
index 82c40e16..f1b6bd38 100644
--- a/CheckUser/i18n/gu.json
+++ b/CheckUser/i18n/gu.json
@@ -1,14 +1,19 @@
{
"@metadata": {
"authors": [
+ "CptViraj",
"Dsvyas",
"KartikMistry"
]
},
"checkuser-reason": "કારણ:",
+ "checkuser-all": "બધા",
"checkuser-nolog": "કોઇ લૉગ ફાઇલ મળી નહી.",
"checkuser-locked": "તાળું મારેલ",
"checkuser-search": "શોધો",
"checkuser-search-submit": "શોધો",
- "checkuser-search-target": "લક્ષ્ય"
+ "checkuser-search-target": "લક્ષ્ય",
+ "checkuser-investigate-reason-label": "કારણ",
+ "checkuser-investigate-preliminary-table-header-name": "સભ્યનામ",
+ "checkuser-investigate-compare-table-header-username": "સભ્યનામ"
}
diff --git a/CheckUser/i18n/ha.json b/CheckUser/i18n/ha.json
index 402f79e9..d1f7c91a 100644
--- a/CheckUser/i18n/ha.json
+++ b/CheckUser/i18n/ha.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser-reason": "Dalili:",
"checkuser-all": "duka",
"checkuser-search": "Nema",
diff --git a/CheckUser/i18n/he.json b/CheckUser/i18n/he.json
index 47550814..9eac0140 100644
--- a/CheckUser/i18n/he.json
+++ b/CheckUser/i18n/he.json
@@ -5,7 +5,9 @@
"Guycn2",
"Rotem Liss",
"Rotemliss",
- "YaronSh"
+ "Steeve815",
+ "YaronSh",
+ "דגש חזק"
]
},
"checkuser-summary": "כלי זה סורק את השינויים האחרונים במטרה למצוא את כתובות ה־IP שמשתמש מסוים עשה בהן שימוש או כדי להציג את כל המידע על המשתמשים שהשתמשו בכתובת IP מסוימת ועל העריכות שבוצעו ממנה.\nניתן לקבל עריכות ומשתמשים מכתובות IP של הכותרת X-Forwarded-For באמצעות הוספת הטקסט \"<span dir=\"ltr\">/xff</span>\" לסוף הכתובת. הן כתובות IPv4 (כלומר, CIDR $1-32) והן כתובות IPv6 (כלומר, CIDR $2-128) נתמכות.\nלא יוחזרו יותר מ־5,000 עריכות מסיבות של עומס על השרתים.\nיש להשתמש בכלי זה בהתאם למדיניות.",
@@ -53,9 +55,10 @@
"checkuser-massblock": "חסימת המשתמשים שנבחרו",
"checkuser-massblock-text": "חשבונות המשתמש שנבחרו ייחסמו לצמיתות, עם הפעלה של חסימה אוטומטית של כתובות IP וללא אפשרות ליצור חשבון.\nכתובות IP תיחסמנה לשבוע אחד עבור משתמשים אנונימיים בלבד, וללא אפשרות ליצור חשבון.",
"checkuser-blockemail": "למנוע שליחת דואר אלקטרוני",
- "checkuser-blocktalk": "למנוע עריכת את דף שיחת המשתמש בזמן החסימה",
- "checkuser-blocktag": "החלפת דפי המשתמש עם:",
- "checkuser-blocktag-talk": "החלפת דפי השיחה עם:",
+ "checkuser-blocktalk": "למנוע את עריכת דף שיחת המשתמש בזמן החסימה",
+ "checkuser-blocktag": "להחליף את דפי המשתמש ב־:",
+ "checkuser-blocktag-talk": "להחליף את דפי השיחה ב־:",
+ "checkuser-reblock": "לדרוס חסימות קיימות",
"checkuser-massblock-commit": "חסימת המשתמשים שנבחרו",
"checkuser-block-success": "'''{{PLURAL:$2|המשתמש|המשתמשים}} $1 {{PLURAL:$2|חסום|חסומים}} כעת.'''",
"checkuser-block-failure": "'''לא נחסמו משתמשים.'''",
@@ -63,10 +66,9 @@
"checkuser-block-noreason": "יש לתת סיבה לחסימות.",
"checkuser-centralauth-multilock": "נעילה מרובה של חשבונות שנבחרו",
"checkuser-noreason": "יש לכתוב סיבה לשאילתה הזאת.",
- "checkuser-accounts": "{{PLURAL:$1|חשבון חדש אחד|$1 חשבונות חדשים}}",
- "checkuser-too-many": "נמצאו תוצאות רבות מדי (לפי הערכה של השאילתה). נא לצמצם את ה־CIDR.\nלהלן כתובות ה־IP שנעשה בהן שימוש (מוצגות 5,000 לכל היותר, וממוינות לפי כתובת):",
+ "checkuser-too-many": "יותר מדי תוצאות (לפי ההערכה של השאילתה), נא לצמצם את ה־CIDR.\nהנה כתובת ה־IP שהיו בשימוש ($1 לכל היות, ממוינות לפי הכתובת):",
"checkuser-user-nonexistent": "המשתמש שצוין לא נמצא.",
- "checkuser-search": "חיפוש עיולים ביומן בדיקת משתמשים",
+ "checkuser-search": "חיפוש רשומות ביומן בדיקת משתמשים",
"checkuser-search-submit": "חיפוש",
"checkuser-search-initiator": "בודק",
"checkuser-search-target": "נבדק",
@@ -76,10 +78,10 @@
"checkuser-showmain": "מעבר לטופס הבדיקה הראשי",
"checkuser-limited": "'''הדף נקטע כדי לחסוך במשאבים.'''",
"checkuser-log-entry-userips": "$3, משתמש $1 קיבל כתובות IP עבור $2",
- "checkuser-log-entry-ipedits": "$3, משתמש $1 קיבל עריכות עבור $2",
- "checkuser-log-entry-ipusers": "$3, משתמש $1 קיבל משתמשים עבור $2",
- "checkuser-log-entry-ipedits-xff": "$3, משתמש $1 קיבל עריכות עבור ה־XFF בכתובת $2",
- "checkuser-log-entry-ipusers-xff": "$3, משתמש $1 קיבל משתמשים עבור ה־XFF בכתובת $2",
+ "checkuser-log-entry-ipedits": "$3, משתמש $1 קיבל עריכות עבור <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, משתמש $1 קיבל משתמשים עבור <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, משתמש $1 קיבל עריכות עבור ה־XFF בכתובת <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, משתמש $1 קיבל משתמשים עבור ה־XFF בכתובת <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, משתמש $1 קיבל עריכות עבור $2",
"checkuser-autocreate-action": "נוצר אוטומטית",
"checkuser-create-action": "נוצר",
@@ -90,26 +92,94 @@
"checkuser-login-success": "נכנס בהצלחה לאתר {{SITENAME}} בתור $1",
"group-checkuser.css": "/* הסגנונות הנכתבים כאן ישפיעו על בודקים בלבד */",
"group-checkuser.js": "/* כל הסקריפטים הנכתבים כאן ייטענו עבור בודקים בלבד */",
- "apihelp-query+checkuser-description": "בדיקה אילו כתובות IP משמשות שם משתמש מסוים או אילו שמות משתמש נמצאים בשימוש על־ידי כתובת IP מסוימת.",
- "apihelp-query+checkuser-summary": "בדיקה אילו כתובות IP משמשות שם משתמש מסוים או אילו שמות משתמש משמשות כתובת IP מסוימת.",
- "apihelp-query+checkuser-param-request": "סוגי בדיקת משתמש:\n;userips:קבלת כתובות IP של המשתמש המיועד.\n;edits:קבלת שינויים מכתובת ה־IP או מהטווח המיועדים.\n;ipusers:קבלת משתמשים מכתובת ה־IP או מהטווח המיועדים.",
- "apihelp-query+checkuser-param-target": "שם משתמש, כתובת IP, או טווח CIDR לבדיקה.",
- "apihelp-query+checkuser-param-reason": "סיבה לבדיקה.",
- "apihelp-query+checkuser-param-limit": "מגבלת שורות.",
- "apihelp-query+checkuser-param-timecond": "מגבלת זמן של נתוני משתמש (כמו \"-2 weeks\" או \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "להשתמש בנתוני XFF במקום בכתובת IP.",
- "apihelp-query+checkuser-example-1": "בדיקת כתובות IP עבור [[User:Example]]",
- "apihelp-query+checkuser-example-2": "בדיקת עריכות מ־192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "קבלת עיוליחם מיומן בדיקת משתמשים.",
- "apihelp-query+checkuserlog-summary": "קבלת עיולים מיומן בדיקת משתמשים.",
- "apihelp-query+checkuserlog-param-user": "שם משתמש של הבודק.",
- "apihelp-query+checkuserlog-param-target": "המשתמש הנבדק, כתובת IP או טווח CIDR.",
- "apihelp-query+checkuserlog-param-limit": "מגבלת שורות.",
- "apihelp-query+checkuserlog-param-from": "חותם־הזמן שהמנייה תתחיל ממנו.",
- "apihelp-query+checkuserlog-param-to": "חותם־הזמן שהמנייה תסתיים בו.",
- "apihelp-query+checkuserlog-example-1": "הצגת בדיקות של [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "קבלת בדיקות של 192.0.2.0/24 אחרי 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "עליך להגדיר סיבה לבדיקה.",
- "apierror-checkuser-timelimit": "עליך להגדיר מגבלת זמן נכונה (למשל \"-2 weeks\" או \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "מצב בקשה בלתי־תקין"
+ "checkuser-link-investigate-label": "לנסות את כלי בדיקת המשתמשים החדש",
+ "checkuser-investigateblock": "חסימת משתמשים",
+ "checkuser-investigateblock-target": "שמות משתמש וכתובות IP",
+ "checkuser-investigateblock-actions": "אילו פעולות לחסום",
+ "checkuser-investigateblock-reason": "סיבה",
+ "checkuser-investigateblock-options": "אפשרויות נוספות",
+ "checkuser-investigateblock-email-label": "למנוע שליחת דואר אלקטרוני",
+ "checkuser-investigateblock-usertalk-label": "למנוע את עריכת דף שיחת המשתמש בזמן החסימה",
+ "checkuser-investigateblock-reblock-label": "לדרוס חסימות קיימות",
+ "checkuser-investigateblock-notice-user-page-label": "להשאיר הודעה בדף המשתמש",
+ "checkuser-investigateblock-notice-talk-page-label": "להשאיר הודעה בדף שיחת המשתמש",
+ "checkuser-investigateblock-notice-position-label": "מיקום",
+ "checkuser-investigateblock-notice-text-label": "קוד ויקי",
+ "checkuser-investigateblock-notice-append": "להוסיף לסוף הדף",
+ "checkuser-investigateblock-notice-prepend": "להוסיף לתחילת הדף",
+ "checkuser-investigateblock-notice-replace": "להחליף את הדף בזה",
+ "checkuser-investigateblock-failure": "לא נחסם שום משתמש. כדי לדרוס חסימות קיימות, צריך לסמן את התיבה: \"{{int:checkuser-investigateblock-reblock-label}}\". החסימה לא תידרס אם החסימה החדשה זהה לחסימה הקיימת",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|המשתמש|המשתמשים}} $1 {{PLURAL:$2|חסום|חסומים}} כעת.",
+ "checkuser-investigateblock-notices-failed": "לא היה אפשר להוסיף הודעות מסוימות לדפי המשתמש או דפי שיחת המשתמש.",
+ "checkuser-investigate-log": "יומני חקירה",
+ "checkuser-investigate-log-entry": "$3, $1 {{GENDER:$1|חיפש|חיפשה}} מידע על <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "לא נמצאו רשומות יומן חקירה.",
+ "checkuser-investigate-log-subtitle": "מעבר לטופס חקירה",
+ "checkuser-investigate": "חקירה",
+ "checkuser-investigate-page-subtitle": "חקירה נוכחית עבור $1",
+ "checkuser-investigate-subtitle-block-button-label": "חסימה",
+ "checkuser-investigate-subtitle-cancel-button-label": "ביטול",
+ "checkuser-investigate-subtitle-continue-button-label": "למהשיך",
+ "checkuser-investigate-indicator-new-investigation": "חקירה חדשה",
+ "checkuser-investigate-indicator-logs": "יומנים",
+ "checkuser-investigate-legend": "חיפוש שמות משתמש, כתובות IP או טווחי IP",
+ "checkuser-investigate-notice-no-results": "אין תוצאות.",
+ "checkuser-investigate-tab-preliminary-check": "מידע על החשבון",
+ "checkuser-investigate-tab-compare": "כתובות IP וסוכני לקוח",
+ "checkuser-investigate-tab-timeline": "ציר זמן",
+ "checkuser-investigate-targets-label": "שמות משתמש וכתובות IP",
+ "checkuser-investigate-targets-placeholder": "שם־משתמש או 1.1.1.1",
+ "checkuser-investigate-duration-label": "משך זמן",
+ "checkuser-investigate-duration-option-all": "הכול",
+ "checkuser-investigate-duration-option-1w": "השבוע שעבר",
+ "checkuser-investigate-duration-option-2w": "השבועיים האחרונים",
+ "checkuser-investigate-duration-option-30d": "30 הימים האחרונים",
+ "checkuser-investigate-reason-label": "סיבה",
+ "checkuser-investigate-preliminary-notice-ip-targets": "לשונית \"מידע על החשבון\" אינה כוללת שום מידע על כתובות IP. ר' את <span class=\"plainlinks\">[$1 הלשונית \"כתובות IP וסוכני לקוח\"]</span> בשביל הפרטים האלה.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "חסום",
+ "checkuser-investigate-preliminary-table-cell-edits": "{{PLURAL:$1|עריכה אחת|$1 עריכות}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "לא חסום",
+ "checkuser-investigate-preliminary-table-header-blocked": "מצב",
+ "checkuser-investigate-preliminary-table-header-editcount": "עריכות",
+ "checkuser-investigate-preliminary-table-header-groups": "קבוצות",
+ "checkuser-investigate-preliminary-table-header-name": "שם משתמש",
+ "checkuser-investigate-preliminary-table-header-registration": "תאריך השיוך",
+ "checkuser-investigate-preliminary-table-header-wiki": "ויקי",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "ויקי לא נמצא",
+ "checkuser-investigate-filters-legend": "מסננים",
+ "checkuser-investigate-filters-exclude-targets-label": "הסתרת המשתמשים או כתובות ה־IP האלה",
+ "checkuser-investigate-timeline-notice-no-results": "אין תוצאות: לא הייתה פעילות רשומה מהמשתמשים או מכתובות ה־IP האלה ב־90 הימים האחרונים",
+ "checkuser-investigate-timeline-notice-no-results-filters": "אין תוצאות שמתאימות לחיפוש הזה. נא לנסות להסיר חלק מהמסננים כדי להרחיב את החיפוש.",
+ "checkuser-investigate-compare-copy-button-label": "להציג קוד ויקי",
+ "checkuser-investigate-compare-toollinks-ipcheck": "בדיקת פרוקסי",
+ "checkuser-investigate-compare-copy-message-label": "האם {{GENDER:|תרצה|תרצי}} להעתיק את המידע הזה בתור טבלה בקוד ויקי?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "בשל מגבלות טכניות, הגענו למספר המרבי של רשומות שאפשר להציג. הנתונים שהוחזרו ליעדים הבעים אינם מלאים $1. נא לנסות להשתמש בפחות יעדים, חלון זמן קטן יותר, או טווחי IP צרים יותר.",
+ "checkuser-investigate-compare-notice-no-results": "אין תוצאות: לא היו עריכות מהמשתמשים או מהכתובות האלה ב־90 הימים האחרונים",
+ "checkuser-investigate-compare-notice-no-results-filters": "אין תוצאות שמתאימות לחיפוש הזה. נא לנסות להסיר חלק מהמסננים כדי להרחיב את החיפוש.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "הצגת כל כתובות ה־IP של המשתמש הזה",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "הצגת כל המשתמשים בכתובת ה־IP הזאת",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "הוספת כתובת ה־IP הזאת לחקירה",
+ "checkuser-investigate-compare-table-button-checks-label": "בדיקות",
+ "checkuser-investigate-compare-table-button-contribs-label": "תרומות",
+ "checkuser-investigate-compare-table-button-filter-label": "לסנן מהתוצאות",
+ "checkuser-investigate-compare-table-cell-unregistered": "לא רשום",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[{{PLURAL:$1|עריכה אחת|$1 עריכות}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 מכל המשתמשים)</i>",
+ "checkuser-investigate-compare-table-header-username": "שם משתמש",
+ "checkuser-investigate-compare-table-header-activity": "טווח תאריכים",
+ "checkuser-investigate-compare-table-header-ip": "כתובת IP",
+ "checkuser-investigate-compare-table-header-useragent": "סוכן לקוח",
+ "checkuser-investigate-subtitle-link-restart-tour": "להתחיל את הסיור מחדש",
+ "checkuser-investigate-tour-targets-title": "{{GENDER:|בודק|בודקת}} מספר משתמשים וכתובות IP?",
+ "checkuser-investigate-tour-targets-desc": "{{GENDER:|הוסף|הוסיפי}} {{PLURAL:$1|שם משתמש או כתובת IP|עד $1 שמות משתמש או כתובות IP}} כדי לקבל את כל המידע במקום אחד. אין מה לדאוג, אנחנו ניצור יומן בדיקה נפרד עבור כל אחד מהם.",
+ "checkuser-investigate-tour-useragents-title": "התאמת סוכני לקוח?",
+ "checkuser-investigate-tour-useragents-desc": "{{GENDER:|רחף|רחפי}} מעל תא כדי להדגיש את כל השורות האחרות עם אותם התונים. {{GENDER:|לחץ|לחצי}} על סמל הסיכה כדי לשמור על ההדגשה בזמן המעבר על הנתונים.",
+ "checkuser-investigate-tour-addusertargets-title": "{{GENDER:|זקוק|זקוקה}} לעוד הקשר?",
+ "checkuser-investigate-tour-addusertargets-desc": "{{GENDER:|לחץ|לחצי}} כדי לראות את כל המשתמשים בכתובת ה־IP הזאת. {{GENDER:|אתה יכול|את יכולה}} לעשות את זה גם עבור משתמשים, ולראות את כל כתובות ה־IP שהם השתמשו בהן. אנחנו ניצור פריט יומן בדיקה באופן אוטומטי בשבילך.",
+ "checkuser-investigate-tour-filterip-title": "{{GENDER:|מצמצם|מצמצמת}} את החקירה שלך?",
+ "checkuser-investigate-tour-filterip-desc": "{{GENDER:|סלק|סלקי}} את הבלגן באמצעות סינון שמות משתמש, כתובות IP, או סוכני לקוח. רוצה את הנתונים חזרה? {{GENDER:|השתמש|השתמשי}} בחלונית \"מסננים\" למעלה כדי לכבות את המסננים.",
+ "checkuser-investigate-tour-block-title": "רוצה לחסום?",
+ "checkuser-investigate-tour-block-desc": "זה מאפשר לך לבחור את המשתמשים {{GENDER:|שתרצה|שתרצי}} לחסום ואז לוקח אותך לטופס החסימה כדי לבחור את החסימה המתאימה.",
+ "checkuser-investigate-tour-copywikitext-title": "רוצה להעתיק את הנתונים?",
+ "checkuser-investigate-tour-copywikitext-desc": "{{GENDER:|העתק|העתיקי}} את טבלת ההשוואה בלחיצה אחת {{GENDER:|וקח|וקחי}} אותה ל־CUWiki. {{GENDER:|שים|שימי}} לב לכך {{GENDER:|שאתה מעתיק|שאת מעתיקה}} רק את מה שמוצג ולא את כל הדפים של החקירה."
}
diff --git a/CheckUser/i18n/hi.json b/CheckUser/i18n/hi.json
index a9e417e7..6978b7cd 100644
--- a/CheckUser/i18n/hi.json
+++ b/CheckUser/i18n/hi.json
@@ -1,12 +1,14 @@
{
"@metadata": {
"authors": [
+ "Abijeet Patro",
"Ansumang",
+ "Archana mathur",
"Kaustubh",
+ "Sfic",
"Shyam",
"Siddhartha Ghai",
- "जनक राज भट्ट",
- "Sfic"
+ "जनक राज भट्ट"
]
},
"checkuser-summary": "यह उपकरण हाल में किये गये बदलावों की जाँच किसी सदस्य द्वारा प्रयुक्त सारे आई॰पी पते खोजने के लिए, अथवा किसी आई॰पी का उपयोग करने वाले सभी सदस्यों का सम्पादन एवं सदस्य डाटा खोजने के लिए करता है।\nXFF headers का प्रयोग कर के किसी आई॰पी से सम्बद्ध सदस्य एवं सम्पादन जानकारी आई॰पी पते के आगे \"/xff\" लगाकर खोजी जा सकती है। IPv4 (CIDR $1-32) और IPv6 (CIDR $2-128) समर्थित हैं।\nप्रदर्शन कारणों की वजह से पाँच हज़ार से अधिक सम्पादन नहीं दिखाए जाएँगे।\nइसे नीति के अनुसार प्रयोग करें।",
@@ -59,7 +61,6 @@
"checkuser-block-limit": "बहुत ज़्यादा सदस्य चुने हैं।",
"checkuser-block-noreason": "आपको अवरोध का कारण देना होगा।",
"checkuser-noreason": "आपको इस खोज का कारण देना होगा।",
- "checkuser-accounts": "$1 {{PLURAL:$1|नया खाता|नये खाते}}",
"checkuser-too-many": "बहुत सारे परिणाम (खोज अंदाज़े अनुसार)। कृपया CIDR छोटा करें।\nनीचे प्रयुक्त आई॰पी पतों की सूची हैं (अधिकतम पाँच हज़ार, अनुक्रम में):",
"checkuser-user-nonexistent": "निर्दिष्ट सदस्य मौजूद नहीं है।",
"checkuser-search": "खोजें",
@@ -76,6 +77,8 @@
"checkuser-reset-action": "\"$1\" के लिए पासवर्ड रीसेट करें",
"group-checkuser.css": "/* यहाँ पर दी सी॰एस॰एस केवल सदस्य जाँचकर्ताओं के लिये होगी */",
"group-checkuser.js": "/* यहाँ पर दी जावास्क्रिप्ट केवल सदस्य जाँचकर्ताओं के लिए होगी */",
- "apihelp-query+checkuser-param-limit": "पंक्तियों की सीमा",
- "apihelp-query+checkuserlog-param-limit": "पंक्तियों की सीमा"
+ "checkuser-link-investigate-label": "नया इस्तमाल करने वाला उपकरण आज़माएं",
+ "checkuser-investigateblock-reason": "कारण",
+ "checkuser-investigate-subtitle-cancel-button-label": "रद्द करें",
+ "checkuser-investigate-subtitle-continue-button-label": "जारी रखें"
}
diff --git a/CheckUser/i18n/hr.json b/CheckUser/i18n/hr.json
index 8046cce8..f02cd897 100644
--- a/CheckUser/i18n/hr.json
+++ b/CheckUser/i18n/hr.json
@@ -1,10 +1,12 @@
{
"@metadata": {
"authors": [
+ "Bugoslav",
"Dalibor Bosits",
"Ex13",
"Excaliboor",
"MaGa",
+ "Neptune, the Mystic",
"SpeedyGonsales",
"Tivek"
]
@@ -30,7 +32,7 @@
"checkuser-target": "IP adresa ili suradnik:",
"checkuser-users": "Suradnička imena",
"checkuser-edits": "Nađi izmjene",
- "checkuser-ips": "IP adrese",
+ "checkuser-ips": "Dohvati IP adrese",
"checkuser-period": "Vrijeme:",
"checkuser-week-1": "posljednji tjedan",
"checkuser-week-2": "posljednja dva tjedna",
@@ -59,8 +61,7 @@
"checkuser-block-limit": "Odabrano je previše suradnika.",
"checkuser-block-noreason": "Morate upisati razlog za blokiranje.",
"checkuser-noreason": "Morate navesti razlog za ovaj upit.",
- "checkuser-accounts": "$1 {{PLURAL:$1|novi račun|novih računa}}",
- "checkuser-too-many": "Previše rezultata, molimo suzite opseg (CIDR). Slijede korištene IP adrese (max 5000, poredano adresno):",
+ "checkuser-too-many": "Pronađeno je previše rezultata (prema procjeni upita), molimo Vas, suzite opseg CIDR-a. Slijede rabljene IP adrese (najviše njih $1, poredane po adresi):",
"checkuser-user-nonexistent": "Traženi suradnik (suradničko ime) ne postoji.",
"checkuser-search": "Traži",
"checkuser-search-submit": "Traži",
@@ -72,5 +73,34 @@
"checkuser-autocreate-action": "je automatski stvoren",
"checkuser-create-action": "je napravljen",
"checkuser-email-action": "poslan email za \"$1\"",
- "checkuser-reset-action": "ponovno postavi zaporku za suradnika \"$1\""
+ "checkuser-reset-action": "ponovno postavi zaporku za suradnika \"$1\"",
+ "checkuser-investigateblock": "Blokiranje suradnica / suradnika",
+ "checkuser-investigateblock-target": "Suradnička imena i IP-adrese",
+ "checkuser-investigateblock-options": "Dodatne mogućnosti",
+ "checkuser-investigateblock-notice-user-page-label": "Pošalji obavijest na suradničku stranicu",
+ "checkuser-investigateblock-notice-talk-page-label": "Pošalji poruku na suradničku razgovornu stranicu",
+ "checkuser-investigateblock-notice-text-label": "Wikitekst",
+ "checkuser-investigateblock-notice-append": "Dodaj na kraj stranice",
+ "checkuser-investigateblock-notice-prepend": "Dodaj stranici na početak",
+ "checkuser-investigateblock-notice-replace": "Zamijeni stranicu",
+ "checkuser-investigate-notice-no-results": "Nema rezultata.",
+ "checkuser-investigate-tab-preliminary-check": "Informacije o računu",
+ "checkuser-investigate-tab-compare": "Usporedi",
+ "checkuser-investigate-tab-timeline": "Vremenska crta",
+ "checkuser-investigate-targets-placeholder": "Suradničko ime ili 1.1.1.1",
+ "checkuser-investigate-preliminary-table-header-blocked": "Stanje",
+ "checkuser-investigate-preliminary-table-header-groups": "Skupine",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki nije pronađen",
+ "checkuser-investigate-filters-legend": "Filtri",
+ "checkuser-investigate-filters-exclude-targets-label": "Skrij navedene suradnike ili IP-adrese",
+ "checkuser-investigate-compare-copy-button-label": "Pokaži wikitekst",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Provjera proxyja",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Pokaži sve suradnike s ovoga IP-a",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Prikaži sve IP adrese ovog suradnika",
+ "checkuser-investigate-compare-table-button-checks-label": "Provjere",
+ "checkuser-investigate-compare-table-button-contribs-label": "Doprinosi",
+ "checkuser-investigate-compare-table-cell-unregistered": "Neregistrirani",
+ "checkuser-investigate-compare-table-header-username": "Suradničko ime",
+ "checkuser-investigate-tour-addusertargets-title": "Potrebnost širega konteksta?",
+ "checkuser-investigate-tour-filterip-title": "Sužavanje Vaše istrage?"
}
diff --git a/CheckUser/i18n/hsb.json b/CheckUser/i18n/hsb.json
index 572643d0..a4024780 100644
--- a/CheckUser/i18n/hsb.json
+++ b/CheckUser/i18n/hsb.json
@@ -54,7 +54,6 @@
"checkuser-block-limit": "Přewjele wužiwarjow wubrane.",
"checkuser-block-noreason": "Dyrbiš přičinu za zablokowanja podać.",
"checkuser-noreason": "Dyrbiš přičinu za tute wotprašowanje podać.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nowe konto|nowej konće|nowe konta|nowych kontow}}",
"checkuser-too-many": "Přewjele wuslědkow (po taksowanju naprašowanja), prošu zamjezuj CIDR.\nTu su wužiwane IP (maks. 5000, po adresy sortěrowane):",
"checkuser-user-nonexistent": "Podaty wužiwar njeeksistuje.",
"checkuser-search": "Pytać",
diff --git a/CheckUser/i18n/hu.json b/CheckUser/i18n/hu.json
index 585c2bbc..e0d86e13 100644
--- a/CheckUser/i18n/hu.json
+++ b/CheckUser/i18n/hu.json
@@ -1,7 +1,10 @@
{
"@metadata": {
"authors": [
+ "Bencemac",
"Bináris",
+ "Csega",
+ "Csigabi",
"Dani",
"Dj",
"Dorgan",
@@ -11,9 +14,7 @@
"KossuthRad",
"Terik",
"Tgr",
- "Wolf Rex",
- "Bencemac",
- "Csigabi"
+ "Wolf Rex"
]
},
"checkuser-summary": "Ez az eszköz végigvizsgálja a friss változásokat, hogy lekérje egy adott felhasználó IP-címeit vagy megjelenítse egy adott IP-címet használó szerkesztőket és az IP szerkesztéseit.\nEgy proxy mögötti kliens eredeti adatai XFF-fejlécek segítségével kérhetőek le, az IP-cím utáni „/xff” parancssal. Az IPv4 (CIDR $1-32) és az IPv6 (CIDR $2-128) is támogatott.\nMaximum 5000 szerkesztés fog megjelenni teljesítményi okok miatt. Az eszközt a szabályoknak megfelelően használd.",
@@ -70,7 +71,6 @@
"checkuser-block-limit": "Túl sok szerkesztőt választottál ki.",
"checkuser-block-noreason": "Meg kell adnod a blokkolások okát.",
"checkuser-noreason": "Meg kell adnod a lekérdezés okát.",
- "checkuser-accounts": "{{PLURAL:$1|egy|$1}} új felhasználói fiók",
"checkuser-too-many": "Túl sok találat (a lekérdezési becslés szerint), kérlek, szűkítsd le a CIDR-t.\nItt vannak a használt IP-címek (maximum 5000, cím alapján rendezve):",
"checkuser-user-nonexistent": "A megadott szerkesztő nem létezik.",
"checkuser-search": "Keresés a naplófájlokban",
@@ -83,10 +83,10 @@
"checkuser-showmain": "Vissza az IP-ellenőri oldalra",
"checkuser-limited": "'''Teljesítményi okok miatt nem az összes találat lett megjelenítve.'''",
"checkuser-log-entry-userips": "$3; $1 lekérte $2 IP-címeit",
- "checkuser-log-entry-ipedits": "$3; $1 lekérte $2 szerkesztéseit",
- "checkuser-log-entry-ipusers": "$3; $1 lekérte a(z) $2 IP-címet használók neveit",
- "checkuser-log-entry-ipedits-xff": "$3; $1 lekérte XFF $2 szerkesztéseit",
- "checkuser-log-entry-ipusers-xff": "$3; $1 lekérte az XFF $2 IP-címet használók neveit",
+ "checkuser-log-entry-ipedits": "$3; $1 lekérte <bdi>$2</bdi> szerkesztéseit",
+ "checkuser-log-entry-ipusers": "$3; $1 lekérte a(z) <bdi>$2</bdi> IP-címet használók neveit",
+ "checkuser-log-entry-ipedits-xff": "$3; $1 lekérte XFF <bdi>$2</bdi> szerkesztéseit",
+ "checkuser-log-entry-ipusers-xff": "$3; $1 lekérte az XFF <bdi>$2</bdi> IP-címet használók neveit",
"checkuser-log-entry-useredits": "$3; $1 lekérte $2 szerkesztéseit",
"checkuser-autocreate-action": "automatikusan létrehozva",
"checkuser-create-action": "készült",
@@ -95,24 +95,5 @@
"checkuser-token-fail": "Munkamenethiba. Kérlek próbáld újra.",
"checkuser-login-failure": "Nem sikerült belépned a(z) {{SITENAME}} oldalra mint $1",
"checkuser-login-success": "Sikeresen beléptél a(z) {{SITENAME}} oldalra mint $1",
- "apihelp-query+checkuser-description": "A megadott felhasználónév által használt IP-címek vagy egy megadott IP-cím által használt felhasználónevek ellenőrzése.",
- "apihelp-query+checkuser-summary": "A megadott felhasználónév által használt IP-címek vagy egy megadott IP-cím által használt felhasználónevek ellenőrzése.",
- "apihelp-query+checkuser-param-request": "IP-ellenőri kérelemtípusok:\n;userips:Konkrét felhasználó IP-címeinek lekérdezése.\n;edits:Konkrét IP vagy tartomány közreműködéseinek lekérdezése.\n;ipusers:Konkrét IP-t vagy tartományt használó felhasználók lekérdezése.",
- "apihelp-query+checkuser-param-target": "Ellenőrizendő felhasználói név, IP-cím vagy CIDR tartomány.",
- "apihelp-query+checkuser-param-reason": "Az ellenőrzés oka.",
- "apihelp-query+checkuser-param-timecond": "Felhasználói adatok időlimitje (pl. „-2 weeks” vagy „2 weeks ago”).",
- "apihelp-query+checkuser-param-xff": "XFF-adat használata IP-cím helyett.",
- "apihelp-query+checkuser-example-1": "[[User:Example]] IP-címeinek ellenőrzése",
- "apihelp-query+checkuser-example-2": "192.0.2.0/24 szerkesztéseinek ellenőrzése",
- "apihelp-query+checkuserlog-description": "Bejegyzések lekérése az IP-ellenőri naplóból",
- "apihelp-query+checkuserlog-summary": "Bejegyzések lekérése az IP-ellenőri naplóból",
- "apihelp-query+checkuserlog-param-user": "Az IP-ellenőr neve.",
- "apihelp-query+checkuserlog-param-target": "Ellenőrzött felhasználó, IP-cím vagy CIDR tartomány.",
- "apihelp-query+checkuserlog-param-from": "Listázás ettől az időbélyegtől.",
- "apihelp-query+checkuserlog-param-to": "Listázás eddig az időbélyegig.",
- "apihelp-query+checkuserlog-example-1": "[[User:Example]] ellenőrzéseinek mutatása",
- "apihelp-query+checkuserlog-example-2": "192.0.2.0/24 ellenőrzéseinek mutatása 2011-10-15T23:00:00Z után",
- "apierror-checkuser-missingsummary": "Meg kell adnod az ellenőrzés okát.",
- "apierror-checkuser-timelimit": "Helyes időlimitet kell használnod (pl. „-2 weeks” vagy „2 weeks ago”).",
- "apierror-checkuser-invalidmode": "Érvénytelen kérésmód."
+ "checkuser-investigate-preliminary-table-header-blocked": "Állapot"
}
diff --git a/CheckUser/i18n/hy.json b/CheckUser/i18n/hy.json
index f08d566b..d5c80616 100644
--- a/CheckUser/i18n/hy.json
+++ b/CheckUser/i18n/hy.json
@@ -1,9 +1,18 @@
{
"@metadata": {
"authors": [
+ "Kareyac",
"Togaed"
]
},
"checkuser-search": "Որոնել",
- "checkuser-search-submit": "Որոնել"
+ "checkuser-search-submit": "Որոնել",
+ "checkuser-investigate-subtitle-block-button-label": "Արգելափակում",
+ "checkuser-investigate-subtitle-cancel-button-label": "Չեղարկել",
+ "checkuser-investigate-subtitle-continue-button-label": "Շարունակել",
+ "checkuser-investigate-preliminary-table-header-groups": "Խմբեր",
+ "checkuser-investigate-preliminary-table-header-name": "Մասնակցային անուն",
+ "checkuser-investigate-preliminary-table-header-wiki": "Վիքի",
+ "checkuser-investigate-filters-legend": "Զտիչներ",
+ "checkuser-investigate-compare-table-header-username": "Մասնակցային անուն"
}
diff --git a/CheckUser/i18n/hyw.json b/CheckUser/i18n/hyw.json
new file mode 100644
index 00000000..e8c292a9
--- /dev/null
+++ b/CheckUser/i18n/hyw.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Շահէն"
+ ]
+ },
+ "checkuser-investigate-compare-table-button-contribs-label": "Ներդրումներ"
+}
diff --git a/CheckUser/i18n/ia.json b/CheckUser/i18n/ia.json
index d30f2d66..4c9428ec 100644
--- a/CheckUser/i18n/ia.json
+++ b/CheckUser/i18n/ia.json
@@ -37,6 +37,8 @@
"checkuser-nomatch": "Nihil trovate.",
"checkuser-nomatch-edits": "Nulle resultato trovate.\nLe ultime modification esseva le $1 a $2.",
"checkuser-check": "Verificar",
+ "checkuser-check-this-user": "Verificar iste usator",
+ "checkuser-recent-checks": "Verificationes recente pro iste usator",
"checkuser-log-fail": "Impossibile adder entrata al registro",
"checkuser-nolog": "Nulle file de registro trovate.",
"checkuser-blocked": "Blocate",
@@ -57,7 +59,6 @@
"checkuser-block-noreason": "Tu debe indicar un motivo pro le blocadas.",
"checkuser-centralauth-multilock": "Multi-blocar le contos seligite",
"checkuser-noreason": "Tu debe dar un motivo pro iste consulta.",
- "checkuser-accounts": "$1 nove {{PLURAL:$1|conto|contos}}",
"checkuser-too-many": "Troppo de resultatos (per estimation del consulta). Per favor, specifica un CIDR plus stricte.\nEcce le IPs usate (max. 5000, ordinate per adresse):",
"checkuser-user-nonexistent": "Le usator specificate non existe.",
"checkuser-search": "Cercar entratas de registro CheckUser",
@@ -70,36 +71,16 @@
"checkuser-showmain": "Cambiar al formulario principal del verification de usatores",
"checkuser-limited": "'''Iste resultatos ha essite truncate pro motivos de prestationes.'''",
"checkuser-log-entry-userips": "$3, $1 ha obtenite le adresses IP pro $2",
- "checkuser-log-entry-ipedits": "$3, $1 ha obtenite le modificationes pro $2",
- "checkuser-log-entry-ipusers": "$3, $1 ha obtenite le usatores pro $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 ha obtenite le modificationes pro XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 ha obtenite le usatores pro XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 ha obtenite le modificationes pro <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 ha obtenite le usatores pro <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 ha obtenite le modificationes pro XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 ha obtenite le usatores pro XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 ha obtenite le modificationes pro $2",
"checkuser-autocreate-action": "ha essite create automaticamente",
"checkuser-create-action": "ha essite create",
"checkuser-email-action": "inviava un e-mail al usator \"$1\"",
"checkuser-reset-action": "redefiniva contrasigno pro usator \"$1\"",
"checkuser-token-fail": "Session fallite. Per favor, essaya de novo.",
- "apihelp-query+checkuser-description": "Verificar qual nomines de usator usa un adresse IP date o qual adresses IP usa un nomine de usator date.",
- "apihelp-query+checkuser-summary": "Verificar qual nomines de usator usa un adresse IP date o qual adresses IP usa un nomine de usator date.",
- "apihelp-query+checkuser-param-request": "Typo de demanda CheckUser :\n;userips:Obtener le adresse IP del usator.\n;edits:Obtener le modificationes del adresse o intervallo IP.\n;ipusers:Obtener le usatores del adresse o intervallo IP.",
- "apihelp-query+checkuser-param-target": "Le nomine de usator, adresse IP o intervallo CIDR a verificar.",
- "apihelp-query+checkuser-param-reason": "Motivo pro verificar.",
- "apihelp-query+checkuser-param-limit": "Limite de lineas.",
- "apihelp-query+checkuser-param-timecond": "Limite de tempore del datos de usator (in anglese, como \"-2 weeks\" o \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Usar datos XFF in loco del adresse IP.",
- "apihelp-query+checkuser-example-1": "Verificar adresses IP pro [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Verificar modificationes ab 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Obtener entratas ab le registro CheckUser.",
- "apihelp-query+checkuserlog-summary": "Obtener entratas ab le registro CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Nomine del usator con le derecto CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Le usator, adresse IP o intervallo CIDR verificate.",
- "apihelp-query+checkuserlog-param-limit": "Limite de lineas.",
- "apihelp-query+checkuserlog-param-from": "Le data e hora al qual comenciar a enumerar.",
- "apihelp-query+checkuserlog-param-to": "Le data e hora al qual cessar de enumerar.",
- "apihelp-query+checkuserlog-example-1": "Monstrar verificationes de [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Monstrar verificationes de 192.0.2.0/24 post 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Tu debe scriber un motivo pro verificar.",
- "apierror-checkuser-timelimit": "Tu debe usar un limite de tempore correcte (in anglese, como \"-2 weeks\" or \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "Modo de requesta invalide"
+ "checkuser-login-failure": "Fallimento de aperir session in {{SITENAME}} como $1",
+ "checkuser-login-success": "Session aperite in {{SITENAME}} como $1"
}
diff --git a/CheckUser/i18n/id.json b/CheckUser/i18n/id.json
index e87e1ab8..3e775e84 100644
--- a/CheckUser/i18n/id.json
+++ b/CheckUser/i18n/id.json
@@ -1,6 +1,8 @@
{
"@metadata": {
"authors": [
+ "Akmaie Ajam",
+ "Arief",
"Bennylin",
"Borgx",
"Farras",
@@ -8,11 +10,11 @@
"IvanLanin",
"Iwan Novirion",
"Kenrick95",
- "Rex",
- "Arief",
- "Rachmat.Wahidi",
"McDutchie",
- "Rachmat04"
+ "Rachmat.Wahidi",
+ "Rachmat04",
+ "Rex",
+ "Veracious"
]
},
"checkuser-summary": "Peralatan ini memindai perubahan terbaru untuk mengetahui IP seorang pengguna atau menampilkan data suntingan/pengguna untuk suatu IP.\nPengguna dan suntingan suatu IP dapat diketahui melalui kepala XFF dengan menambahkan \"/xff\" pada IP tersebut. Alat ini mendukung baik IPv4 (CIDR $1-32) maupun IPv6 (CIDR $2-128).\nKarena alasan kinerja, maksimum hanya 5000 suntingan yang dapat diambil.\nHarap gunakan peralatan ini sesuai dengan kebijakan yang ada.",
@@ -26,7 +28,7 @@
"group-checkuser-member": "{{GENDER:$1|pemeriksa}}",
"right-checkuser": "Memeriksa alamat IP pengguna dan informasi lainnya",
"right-checkuser-log": "Melihat log pemeriksa",
- "action-checkuser": "alamat IP dan informasi pemeriksa lainnya",
+ "action-checkuser": "memeriksa alamat IP pengguna dan informasi lainnya",
"action-checkuser-log": "lihat log pemeriksa",
"grouppage-checkuser": "{{ns:project}}:Pemeriksa",
"checkuser-reason": "Alasan:",
@@ -68,7 +70,6 @@
"checkuser-block-noreason": "Anda harus mengisi alasan pemblokiran.",
"checkuser-centralauth-multilock": "Kunci beberapa akun terpilih",
"checkuser-noreason": "Anda harus memberikan alasan untuk kueri ini.",
- "checkuser-accounts": "$1 {{PLURAL:$1|akun|akun-akun}} baru",
"checkuser-too-many": "Terlalu banyak hasil pencarian (menurut perkiraan permintaan), mohon persempit CIDR. Berikut adalah alamat-alamat IP yang digunakan (5000 maksimum, diurut berdasarkan alamat):",
"checkuser-user-nonexistent": "Pengguna yang dimaksud tidak ditemukan",
"checkuser-search": "Cari entri log pengguna",
@@ -81,31 +82,16 @@
"checkuser-showmain": "Beralih ke bentuk utama Pemeriksa",
"checkuser-limited": "'''Hasil berikut telah dipotong agar tidak menurunkan kinerja.'''",
"checkuser-log-entry-userips": "$3, $1 mendapatkan alamat IP untuk $2",
- "checkuser-log-entry-ipedits": "$3, $1 mendapatkan suntingan untuk $2",
- "checkuser-log-entry-ipusers": "$3, $1 mendapatkan pengguna untuk $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 mendapatkan suntingan untuk XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 mendapatkan pengguna untuk XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 mendapatkan suntingan untuk <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 mendapatkan pengguna untuk <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 mendapatkan suntingan untuk XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 mendapatkan pengguna untuk XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 mendapatkan suntingan untuk $2",
"checkuser-autocreate-action": "dibuat secara otomatis",
"checkuser-create-action": "dibuat",
"checkuser-email-action": "mengirimkan surel ke \"$1\"",
"checkuser-reset-action": "Set ulang kata sandi pengguna \"$1\"",
"checkuser-token-fail": "Kegagalan sesi. Silakan coba kembali.",
- "apihelp-query+checkuser-description": "Periksa alamat IP mana yang digunakan oleh pengguna yang ditentukan atau nama pengguna manakah yang digunakan oleh alamat IP yang ditentukan.",
- "apihelp-query+checkuser-param-request": "Jenis permintaan CheckUser:\n;userips: Mendapatkan alamat IP dari pengguna yang dituju.\n;edits: Mendapatkan perubahan dari alamat IP atau rentang alamat IP tujuan.\n;ipusers: Mendapatkan pengguna dari alamat IP atau rentang alamat IP tujuan.",
- "apihelp-query+checkuser-param-target": "Nama pengguna, alamat IP atau rentang CIDR untuk diperiksa.",
- "apihelp-query+checkuser-param-reason": "Alasan pemeriksaan.",
- "apihelp-query+checkuser-param-limit": "Batas baris.",
- "apihelp-query+checkuser-param-timecond": "Batas waktu data pengguna (seperti \"-2 weeks\" atau \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Gunakan data XFF alih-alih alamat IP.",
- "apihelp-query+checkuser-example-1": "Periksa alamat IP untuk [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Periksa suntingan dari 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Dapatkan entri dari catatan CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Nama pengguna CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Pengguna yang telah diperiksa, alamat IP, atau rentang CIDR.",
- "apihelp-query+checkuserlog-param-limit": "Batas baris.",
- "apihelp-query+checkuserlog-param-from": "Stempel waktu untuk mulai menghitung.",
- "apihelp-query+checkuserlog-param-to": "Stempel waktu untuk mengakhiri hitungan.",
- "apihelp-query+checkuserlog-example-1": "Tampilkan pemeriksaan dari [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Tampilkan pemeriksaan dari 192.0.2.0/24 setelah 2011-10-15T23:00:00Z"
+ "checkuser-investigate-tab-preliminary-check": "Informasi akun",
+ "checkuser-investigate-subtitle-link-restart-tour": "Mulai Ulang Tur"
}
diff --git a/CheckUser/i18n/ie.json b/CheckUser/i18n/ie.json
new file mode 100644
index 00000000..c388cc82
--- /dev/null
+++ b/CheckUser/i18n/ie.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "OIS"
+ ]
+ },
+ "checkuser-investigate-tab-compare": "Comparar"
+}
diff --git a/CheckUser/i18n/ilo.json b/CheckUser/i18n/ilo.json
index 4940d17e..c5f21bb6 100644
--- a/CheckUser/i18n/ilo.json
+++ b/CheckUser/i18n/ilo.json
@@ -54,7 +54,6 @@
"checkuser-block-limit": "Adu unay ti agar-aramat a napili.",
"checkuser-block-noreason": "Masapul nga agitedka ti rason para kadagiti panagserra.",
"checkuser-noreason": "Masapul nga agited ka ti rason para kadagitoy panagsapul.",
- "checkuser-accounts": "$1 baro {{PLURAL:$1|a pakabilangan|a dagiti pakabilangan}}",
"checkuser-too-many": "Adu unay dagiti nagbanagan (babaen ti karkulo ti panagsapul), pangngaasi a pabassiten ti CIDR.\nAdda ditoy dagiti IP a nausar ( 5000 kangato, nailasin babaen ti pagtaengan):",
"checkuser-user-nonexistent": "Ti nainaganan nga agar-aramat ket awanen.",
"checkuser-search": "Biruken",
diff --git a/CheckUser/i18n/io.json b/CheckUser/i18n/io.json
index 483944c6..623f7fb5 100644
--- a/CheckUser/i18n/io.json
+++ b/CheckUser/i18n/io.json
@@ -1,15 +1,19 @@
{
"@metadata": {
"authors": [
+ "Joao Xavier",
"Malafaya",
- "Robin van der Vliet",
- "Joao Xavier"
+ "Robin van der Vliet"
]
},
+ "checkuser": "Kontrolero di adresi IP",
"group-checkuser": "Kontroleri dil uzeri",
+ "group-checkuser-member": "{{GENDER:$1|kontrolero di IP-adresi}}",
+ "grouppage-checkuser": "{{ns:project}}:Kontrolero di IP-adresi",
"checkuser-reason": "Motivo:",
"checkuser-showlog": "Montrez la registro 'CheckUser'",
"checkuser-target": "IP-adreso od uzeronomo:",
+ "checkuser-period": "Durado:",
"checkuser-week-1": "lasta semano",
"checkuser-week-2": "lasta du semani",
"checkuser-month": "lasta 30 dii",
@@ -18,7 +22,16 @@
"checkuser-blocked": "Blokusita",
"checkuser-gblocked": "Blokusita globale",
"checkuser-wasblocked": "Antee blokusita",
- "checkuser-accounts": "$1 nova {{PLURAL:$1|konto|konti}}",
+ "checkuser-block-success": "'''L'{{PLURAL:$2|uzero|uzeri}} $1 {{PLURAL:$2|nun esas}} blokusata.'''",
+ "checkuser-block-failure": "'''Nula uzeri blokusata.'''",
+ "checkuser-block-limit": "Multa uzeri selektata.",
+ "checkuser-block-noreason": "Vu mustas informar la motivo pri blokuso.",
"checkuser-search-submit": "Serchar",
- "checkuser-ipeditcount": "~$1 di omna uzanti"
+ "checkuser-ipeditcount": "~$1 di omna uzanti",
+ "checkuser-email-action": "sendar e-posto al uzero \"$1\"",
+ "checkuser-investigate-subtitle-block-button-label": "Blokusar",
+ "checkuser-investigate-subtitle-continue-button-label": "Durar",
+ "checkuser-investigate-tab-preliminary-check": "Informo pri la konto",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Montrez omna IP-adresi de ca uzero",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Montrez omna uzeri en ca IP"
}
diff --git a/CheckUser/i18n/is.json b/CheckUser/i18n/is.json
index 2d667cb4..9f21a35c 100644
--- a/CheckUser/i18n/is.json
+++ b/CheckUser/i18n/is.json
@@ -4,8 +4,8 @@
"S.Örvarr.S",
"Snævar",
"Spacebirdy",
- "පසිඳු කාවින්ද",
- "Sveinn í Felli"
+ "Sveinn í Felli",
+ "පසිඳු කාවින්ද"
]
},
"checkuser-desc": "Veitir notendum réttindi til að athuga vistföng notenda og aðrar notendaupplýsingar.",
@@ -30,7 +30,6 @@
"checkuser-nolog": "Engin skrá fundin.",
"checkuser-blocked": "Bannaður",
"checkuser-locked": "Læstur",
- "checkuser-accounts": "$1 {{PLURAL:$1|nýr aðgangur|nýir aðgangar}}",
"checkuser-search": "Leita",
"checkuser-search-submit": "Leita",
"checkuser-search-target": "markmið",
diff --git a/CheckUser/i18n/it.json b/CheckUser/i18n/it.json
index 611c633e..f2e12767 100644
--- a/CheckUser/i18n/it.json
+++ b/CheckUser/i18n/it.json
@@ -6,18 +6,21 @@
"Aushulz",
"Beta16",
"BrokenArrow",
+ "Daimona Eaytoy",
"Darth Kule",
"F. Cosoleto",
"Gianfranco",
+ "Lucas2",
+ "McDutchie",
"Melos",
"Nemo bis",
- "Pietrodn",
- "Stefano-c",
"Nivit",
- "Lucas2",
+ "Pietrodn",
+ "Ruthven",
+ "Sakretsu",
+ "Scompo",
"Selven",
- "McDutchie",
- "Daimona Eaytoy"
+ "Stefano-c"
]
},
"checkuser-summary": "Questo strumento analizza le modifiche recenti per recuperare gli indirizzi IP utilizzati da un utente o mostrare contributi e dati di un IP. Utenti e contributi di un client IP possono essere rintracciati attraverso gli header XFF aggiungendo all'IP il suffisso \"/xff\". Sono supportati IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128). Non saranno restituite più di 5.000 modifiche, per ragioni di prestazioni. Usa questo strumento in stretta conformità alle policy.",
@@ -30,7 +33,7 @@
"group-checkuser": "Check user",
"group-checkuser-member": "{{GENDER:$1|Check user}}",
"right-checkuser": "Visualizza gli indirizzi IP usati dall'utente e altre informazioni",
- "right-checkuser-log": "Visualizza il log dei checkuser",
+ "right-checkuser-log": "Visualizza il registro dei checkuser",
"action-checkuser": "controllare gli indirizzi IP dell'utente e altre informazioni",
"action-checkuser-log": "vedere il log dei checkuser",
"grouppage-checkuser": "{{ns:project}}:Check user",
@@ -41,7 +44,7 @@
"checkuser-target": "Indirizzo IP o nome utente:",
"checkuser-users": "Cerca utenti",
"checkuser-edits": "Vedi i contributi",
- "checkuser-ips": "Cerca IP",
+ "checkuser-ips": "Ottieni indirizzi IP",
"checkuser-period": "Periodo:",
"checkuser-week-1": "settimana scorsa",
"checkuser-week-2": "ultime due settimane",
@@ -49,7 +52,7 @@
"checkuser-all": "tutti gli edit",
"checkuser-cidr-label": "Trova l'intervallo comune e gli indirizzi interessati per una lista di IP",
"checkuser-cidr-res": "CIDR comune:",
- "checkuser-empty": "Il log non contiene dati.",
+ "checkuser-empty": "Il registro non contiene dati.",
"checkuser-nomatch": "Nessun risultato trovato.",
"checkuser-nomatch-edits": "Nessun risultato trovato.\nUltimo edit risalente alle $2 del $1.",
"checkuser-check": "Controlla",
@@ -68,15 +71,15 @@
"checkuser-blocktalk": "Impedisci di modificare la propria pagina di discussioni mentre è bloccato",
"checkuser-blocktag": "Sostituisci pagine utente con:",
"checkuser-blocktag-talk": "Sostituisci pagine di discussione con:",
+ "checkuser-reblock": "Cambia blocco esistente",
"checkuser-massblock-commit": "Blocca utenti selezionati",
- "checkuser-block-success": "'''{{PLURAL:$2|L'utente|Gli utenti}} $1 {{PLURAL:$2|è adesso bloccato|sono adesso bloccati}}.'''",
+ "checkuser-block-success": "'''{{PLURAL:$2|L'utente|Gli utenti}} $1 adesso {{PLURAL:$2|è bloccato|sono bloccati}}.'''",
"checkuser-block-failure": "'''Nessun utente bloccato.'''",
"checkuser-block-limit": "Troppi utenti selezionati.",
"checkuser-block-noreason": "È obbligatorio fornire una motivazione per i blocchi.",
"checkuser-centralauth-multilock": "Blocco multiplo degli utenti selezionati",
"checkuser-noreason": "È necessario fornire una motivazione per questa query.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nuova|nuove}} utenze",
- "checkuser-too-many": "Troppi risultati (per stima della query), per favore usa un CIDR più ristretto.\nQui di seguito ci sono gli indirizzi IP utilizzati (fino a un massimo di 5000, ordinati per indirizzo):",
+ "checkuser-too-many": "Troppi risultati (per stima della query), per favore usa un CIDR più ristretto.\nQui di seguito ci sono gli indirizzi IP utilizzati (fino a un massimo di $1, ordinati per indirizzo):",
"checkuser-user-nonexistent": "L'utente indicato non esiste.",
"checkuser-search": "Cerca nel registro check user",
"checkuser-search-submit": "Ricerca",
@@ -84,39 +87,111 @@
"checkuser-search-target": "obiettivo",
"checkuser-log-search-target": "Obiettivo:",
"checkuser-log-search-type": "Ricerca per:",
- "checkuser-ipeditcount": "~$1 complessivamente",
+ "checkuser-ipeditcount": "~$1 da tutti gli utenti",
"checkuser-showmain": "Passa al modulo principale CheckUser",
"checkuser-limited": "'''I risultati sono stati troncati per motivi di prestazioni.'''",
"checkuser-log-entry-userips": "$3, $1 ha ottenuto gli indirizzi IP di $2",
- "checkuser-log-entry-ipedits": "$3, $1 ha ottenuto le modifiche di $2",
- "checkuser-log-entry-ipusers": "$3, $1 ha ottenuto le utenze di $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 ha ottenuto le modifiche di $2 via XFF",
- "checkuser-log-entry-ipusers-xff": "$3, $1 ha ottenuto le utenze di $2 via XFF",
+ "checkuser-log-entry-ipedits": "$3, $1 ha ottenuto le modifiche di <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 ha ottenuto le utenze di <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 ha ottenuto le modifiche di <bdi>$2</bdi> via XFF",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 ha ottenuto le utenze di <bdi>$2</bdi> via XFF",
"checkuser-log-entry-useredits": "$3, $1 ha ottenuto le modifiche di $2",
"checkuser-autocreate-action": "è stato creato automaticamente",
"checkuser-create-action": "è stato creato",
"checkuser-email-action": "ha inviato una e-mail a \"$1\"",
"checkuser-reset-action": "reimposta password per l'utente \"$1\"",
"checkuser-token-fail": "Errore di sessione. Riprova ancora.",
- "apihelp-query+checkuser-description": "Controlla quali indirizzi IP vengono usati da un determinato nome utente o quali nomi utente vengono usati da un dato IP.",
- "apihelp-query+checkuser-summary": "Controlla quali indirizzi IP vengono usati da un determinato nome utente o quali nomi utente vengono usati da un dato indirizzo IP.",
- "apihelp-query+checkuser-param-request": "Tipo di richiesta CheckUser:\n;userips:Ottieni l'indirizzo IP dell'utente osservato.\n;edit:Ottieni i cambiamenti dell'indirizzo IP o range.\n;ipusers:Ottieni gli utenti da un indirizzo IP o range.",
- "apihelp-query+checkuser-param-target": "Nome utente, indirizzo IP, o range CIDR da controllare.",
- "apihelp-query+checkuser-param-reason": "Ragione per controllare.",
- "apihelp-query+checkuser-param-limit": "Limite di righe.",
- "apihelp-query+checkuser-param-timecond": "Il limite di tempo dei dati utente (come \"-2 weeks\" o \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Utilizzare dati XFF invece dell'indirizzo IP.",
- "apihelp-query+checkuser-example-1": "Verificare gli indirizzi IP per [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Controllare le modifiche di 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Vedi nel registro CheckUser.",
- "apihelp-query+checkuserlog-summary": "Ottieni i risultati dal registro CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Nome del CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Utente, indirizzo IP, o range CIDR controllato.",
- "apihelp-query+checkuserlog-param-limit": "Limite di righe.",
- "apihelp-query+checkuserlog-param-from": "Il timestamp da cui iniziare l'elenco.",
- "apihelp-query+checkuserlog-param-to": "Il timestamp al quale interrompere l'elenco.",
- "apihelp-query+checkuserlog-example-1": "Mostra controlli di [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Mostra controlli di 192.0.2.0/24 dopo il 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Devi indicare una motivazione per il controllo.",
- "apierror-checkuser-timelimit": "Devi utilizzare un corretto limite temporale (come \"-2 settimane\" o \"2 settimane fa\")."
+ "checkuser-login-failure": "Errore nell'effettuare l'accesso su {{SITENAME}} come $1",
+ "checkuser-login-success": "Accesso effettuato su {{SITENAME}} come $1",
+ "checkuser-link-investigate-label": "Prova il nuovo strumento CheckUser",
+ "checkuser-investigateblock": "Blocca utenti",
+ "checkuser-investigateblock-target": "Nomi utente o indirizzi IP",
+ "checkuser-investigateblock-actions": "Azioni da bloccare",
+ "checkuser-investigateblock-reason": "Motivo",
+ "checkuser-investigateblock-options": "Opzioni aggiuntive",
+ "checkuser-investigateblock-email-label": "Impedisci l'invio di email",
+ "checkuser-investigateblock-usertalk-label": "Impedisci di modificare la propria pagina di discussioni mentre è bloccato",
+ "checkuser-investigateblock-reblock-label": "Cambia blocco esistente",
+ "checkuser-investigateblock-notice-user-page-label": "Lascia un avviso nella pagina utente",
+ "checkuser-investigateblock-notice-talk-page-label": "Lascia un avviso nella pagina di discussione utente",
+ "checkuser-investigateblock-notice-position-label": "Posizione",
+ "checkuser-investigateblock-notice-text-label": "Wikitesto",
+ "checkuser-investigateblock-notice-append": "Aggiungi alla pagina",
+ "checkuser-investigateblock-notice-prepend": "Aggiungi in testa alla pagina",
+ "checkuser-investigateblock-notice-replace": "Sostituisci pagina",
+ "checkuser-investigateblock-failure": "Nessun utente è stato bloccato. Per sostituire i blocchi esistenti, controlla \"{{int:checkuser-investigateblock-reblock-label}}\". Il blocco non verrà applicato se è identico a quello già esistente.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|L'utente|Gli utenti}} $1 adesso {{PLURAL:$2|è bloccato|sono bloccati}}.",
+ "checkuser-investigateblock-notices-failed": "Non è stato possibile aggiungere alcuni avvisi alle pagine utente o alle pagine di discussione utente.",
+ "checkuser-investigate-log": "Registro dei controlli",
+ "checkuser-investigate-log-entry": "$3, $1 ha ottenuto informazioni su <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Registro dei controlli vuoto.",
+ "checkuser-investigate-log-subtitle": "Cambia modulo di controllo",
+ "checkuser-investigate": "Ricerca",
+ "checkuser-investigate-page-subtitle": "Ricerca corrente su $1",
+ "checkuser-investigate-subtitle-block-button-label": "Blocca",
+ "checkuser-investigate-subtitle-cancel-button-label": "Annulla",
+ "checkuser-investigate-subtitle-continue-button-label": "Continua",
+ "checkuser-investigate-indicator-new-investigation": "Nuova ricerca",
+ "checkuser-investigate-indicator-logs": "Registri",
+ "checkuser-investigate-legend": "Cerca per nome utente, indirizzi IP o intervalli di IP",
+ "checkuser-investigate-notice-no-results": "Non ci sono risultati.",
+ "checkuser-investigate-tab-preliminary-check": "Informazioni sull'utenza",
+ "checkuser-investigate-tab-compare": "IP e user agent",
+ "checkuser-investigate-tab-timeline": "Finestra temporale",
+ "checkuser-investigate-targets-label": "Nomi utente o indirizzi IP",
+ "checkuser-investigate-targets-placeholder": "Nome utente o 1.1.1.1",
+ "checkuser-investigate-duration-label": "Durata",
+ "checkuser-investigate-duration-option-all": "Tutto",
+ "checkuser-investigate-duration-option-1w": "Ultima settimana",
+ "checkuser-investigate-duration-option-2w": "Ultime 2 settimane",
+ "checkuser-investigate-duration-option-30d": "Ultimi 30 giorni",
+ "checkuser-investigate-reason-label": "Motivo",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Le informazioni sull'utenza non contengono nessuna informazione sugli IP. Vedi <span class=\"plainlinks\">[$1 IP e user agent]</span> per i dettagli.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Bloccato",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|modifica|modifiche}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Non bloccato",
+ "checkuser-investigate-preliminary-table-header-blocked": "Stato",
+ "checkuser-investigate-preliminary-table-header-editcount": "Modifiche",
+ "checkuser-investigate-preliminary-table-header-groups": "Gruppi",
+ "checkuser-investigate-preliminary-table-header-name": "Nome utente",
+ "checkuser-investigate-preliminary-table-header-registration": "Data di collegamento",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki non trovato",
+ "checkuser-investigate-filters-legend": "Filtri",
+ "checkuser-investigate-filters-exclude-targets-label": "Nascondi i seguenti utenti o IP",
+ "checkuser-investigate-timeline-notice-no-results": "Non ci sono risultati: non sono state registrate attività da questi utenti o IP negli ultimi 90 giorni",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Non ci sono risultati corrispondenti a questi criteri di filtro. Prova a rimuovere alcuni filtri per ampliare la ricerca.",
+ "checkuser-investigate-compare-copy-button-label": "Mostra wikitesto",
+ "checkuser-investigate-compare-toollinks-whois": "WHOIS/RDNS",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Proxy check",
+ "checkuser-investigate-compare-copy-message-label": "Desideri copiare quest'informazione in una tabella di wikitesto?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "A causa di limitazioni tecniche, abbiamo raggiunto il numero massimo di entrate visualizzabili. I dati sui seguenti bersagli sono incompleti: $1. Riprova indicando meno bersagli, una finestra temporale più piccola o un IP range meno ampio.",
+ "checkuser-investigate-compare-notice-no-results": "Non ci sono risultati: queste utenze o IP non hanno effettuato modifiche negli ultimi 90 giorni.",
+ "checkuser-investigate-compare-notice-no-results-filters": "Non ci sono risultati corrispondenti a questi criteri. Rimuovi alcuni filtri e riprova.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Mostra tutti gli IP di questo utente",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Mostra tutti gli utenti su questo IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Aggiungi questo IP alla ricerca",
+ "checkuser-investigate-compare-table-button-checks-label": "Controlla",
+ "checkuser-investigate-compare-table-button-contribs-label": "Contributi",
+ "checkuser-investigate-compare-table-button-filter-label": "Filtra dai risultati",
+ "checkuser-investigate-compare-table-cell-unregistered": "Non registrato",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|modifica|modifiche}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 da tutti gli utenti)</i>",
+ "checkuser-investigate-compare-table-header-username": "Nome utente",
+ "checkuser-investigate-compare-table-header-activity": "Intervallo di date",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "User agent",
+ "checkuser-investigate-subtitle-link-restart-tour": "Riavvia tour",
+ "checkuser-investigate-tour-targets-title": "Controlla molteplici utenti e IP?",
+ "checkuser-investigate-tour-targets-desc": "Aggiungi fino a $1 {{PLURAL:$1|nome|nomi}} utente o IP e visualizza tutte le informazioni assieme. Non ti preoccupare: creeremo una voce di registro separata per ognuno di essi.",
+ "checkuser-investigate-tour-useragents-title": "User Agent uguali?",
+ "checkuser-investigate-tour-useragents-desc": "Vai col mouse su una cella per evidenziare tutte le righe con gli stessi dati. Fai click sull'icona dello spillo per mantenere fissa l'evidenziazione mentre analizzi gli altri dati.",
+ "checkuser-investigate-tour-addusertargets-title": "Bisogno di maggior contesto?",
+ "checkuser-investigate-tour-addusertargets-desc": "Clicca per vedere tutti gli altri utenti con questo IP. Puoi anche farlo con gli utenti e visualizzare gli IP che hanno usato. Creeremo un'entrata di registro per ogni richiesta.",
+ "checkuser-investigate-tour-filterip-title": "Ridurre la ricerca?",
+ "checkuser-investigate-tour-filterip-desc": "Rimuovi l'informazione soverchia filtrando i nomi utente, IP o User Agent. Puoi visualizzare nuovamente i dati rimuovendo filtri dalla lista in alto.",
+ "checkuser-investigate-tour-block-title": "Applica blocco?",
+ "checkuser-investigate-tour-block-desc": "Consente di selezionare gli utenti da bloccare e poi apre il modulo di blocco per selezionare il blocco adeguato.",
+ "checkuser-investigate-tour-copywikitext-title": "Vuoi copiare i dati?",
+ "checkuser-investigate-tour-copywikitext-desc": "Ricopia la tabella di confronto con un clic e portala sul CUWiki. Nota che stai copiando solo ciò che è visibile e non tutte le pagine della ricerca."
}
diff --git a/CheckUser/i18n/ja.json b/CheckUser/i18n/ja.json
index 10979832..fe8b0289 100644
--- a/CheckUser/i18n/ja.json
+++ b/CheckUser/i18n/ja.json
@@ -1,33 +1,38 @@
{
"@metadata": {
"authors": [
+ "129femtoseconds",
+ "2nd-player",
"Aotake",
+ "Azeha",
+ "Bonfire12",
+ "Buntschann",
"Fievarsty",
"Fryed-peach",
"Hosiryuhosi",
"JtFuruhata",
"Kahusi",
"Kanjy",
+ "Kkairri",
"Marine-Blue",
+ "Mirinano",
"Muttley",
+ "Otokoume",
+ "Penn Station",
+ "Rxy",
"Schu",
"Shirayuki",
"Suisui",
+ "Sujiniku",
+ "Tmv",
"Vigorous action",
- "Whym",
- "青子守歌",
- "Rxy",
"W.CC",
- "2nd-player",
- "Azeha",
- "Otokoume",
- "Sujiniku",
- "Mirinano",
+ "Whym",
"Yusuke1109",
- "Penn Station"
+ "青子守歌"
]
},
- "checkuser-summary": "このツールは最近の更新をもとに、ある利用者が使用したIPアドレスの検索、または、あるIPアドレスからなされた編集および利用者名の表示を行います。\nIPアドレスと共に「/xff」オプションを指定すると、XFF (X-Forwarded-For) ヘッダーを通じてクライアントIPアドレスを取得し、そこからなされた編集および利用者名の検索をすることができます。\nIPv4 ($1から32ビットのCIDR表記) と IPv6 ($2から128ビットのCIDR表記) に対応しています。\nパフォーマンス上の理由により、最大5000件の編集しか表示できません。\n方針に従って使用してください。",
+ "checkuser-summary": "このツールは最近の更新をもとに、ある利用者が使用したIPアドレスの検索、または、あるIPアドレスからなされた編集および利用者名の表示を行います。\nIPアドレスと共に「/xff」オプションを指定すると、XFF (X-Forwarded-For) ヘッダーを通じてクライアントIPアドレスを取得し、そこからなされた編集および利用者名を検索できます。\nIPv4 ($1から32ビットのCIDR表記) と IPv6 ($2から128ビットのCIDR表記) に対応しています。\nパフォーマンス上の理由により、最大5000件の編集しか表示できません。\n方針に従って使用してください。",
"checkuser-desc": "利用者の IP アドレスなどの情報を、適切な権限を持つ利用者が調査できるようにする",
"checkuser-logcase": "記録の検索では大文字/小文字を区別します。",
"checkuser": "利用者の調査",
@@ -62,7 +67,7 @@
"checkuser-check": "調査",
"checkuser-check-this-user": "この利用者を調査",
"checkuser-recent-checks": "この利用者の最近の調査",
- "checkuser-log-fail": "ログに追加することができません",
+ "checkuser-log-fail": "ログに追加できません",
"checkuser-nolog": "ログファイルが見つかりません。",
"checkuser-blocked": "ブロック済",
"checkuser-gblocked": "グローバルブロック済",
@@ -71,10 +76,11 @@
"checkuser-localonly": "統合されていません",
"checkuser-massblock": "選択した利用者をブロック",
"checkuser-massblock-text": "選択した利用者は無期限ブロックされ、同時に自動ブロックが作動しアカウント作成も禁止されます。\nIPアドレスはIP利用者向けに1週間ブロックされ、アカウント作成が禁止されます。",
- "checkuser-blockemail": "メール送信を禁止させる",
- "checkuser-blocktalk": "この利用者がブロック中に自身のトークページを編集することを禁止",
+ "checkuser-blockemail": "メール送信を禁止する",
+ "checkuser-blocktalk": "この利用者がブロック中に自身のトークページを編集することを禁止する",
"checkuser-blocktag": "利用者ページを以下で置換:",
"checkuser-blocktag-talk": "トークページを以下で置換:",
+ "checkuser-reblock": "既に設定されているブロックを上書き",
"checkuser-massblock-commit": "選択した利用者をブロック",
"checkuser-block-success": "'''{{PLURAL:$2|利用者}} $1 はブロック{{PLURAL:$2|されました}}。'''",
"checkuser-block-failure": "'''ブロックされた利用者はありません。'''",
@@ -82,8 +88,7 @@
"checkuser-block-noreason": "ブロック理由の記入が必要です。",
"checkuser-centralauth-multilock": "選択したアカウントをロック",
"checkuser-noreason": "照会理由の記入が必要です。",
- "checkuser-accounts": "新しい$1{{PLURAL:$1|アカウント}}",
- "checkuser-too-many": "(クエリを見積もったところ) 検索結果が多すぎます。CIDRの指定を小さく絞り込んでください。\n使用したIPアドレスは以下の通り (上限 5000 件、並び順はアドレス順):",
+ "checkuser-too-many": "(クエリを見積もったところ) 検索結果が多すぎます。CIDRの指定を小さく絞り込んでください。\n使用したIPアドレスは以下の通り (上限 $1 件、並び順はアドレス順):",
"checkuser-user-nonexistent": "指定された利用者は存在しません。",
"checkuser-search": "利用者調査のログ項目を検索",
"checkuser-search-submit": "検索",
@@ -95,10 +100,10 @@
"checkuser-showmain": "利用者調査のメインフォームに切り替える",
"checkuser-limited": "'''パフォーマンス上の理由で、結果は省略されています。'''",
"checkuser-log-entry-userips": "$3 $1 は $2 が使用したIPアドレスを取得",
- "checkuser-log-entry-ipedits": "$3 $1 は $2 からの編集を取得",
- "checkuser-log-entry-ipusers": "$3 $1 は $2 から編集を行ったユーザーを取得",
- "checkuser-log-entry-ipedits-xff": "$3 $1 は XFF $2 からの編集を取得",
- "checkuser-log-entry-ipusers-xff": "$3 $1 は XFF $2 から編集を行ったユーザーを取得",
+ "checkuser-log-entry-ipedits": "$3 $1 は <bdi>$2</bdi> からの編集を取得",
+ "checkuser-log-entry-ipusers": "$3 $1 は <bdi>$2</bdi> から編集を行った利用者を取得",
+ "checkuser-log-entry-ipedits-xff": "$3 $1 は XFF <bdi>$2</bdi> からの編集を取得",
+ "checkuser-log-entry-ipusers-xff": "$3 $1 は XFF <bdi>$2</bdi> から編集を行った利用者を取得",
"checkuser-log-entry-useredits": "$3 $1 は $2 の編集を取得",
"checkuser-autocreate-action": "自動的に作成",
"checkuser-create-action": "作成済",
@@ -109,24 +114,40 @@
"checkuser-login-success": "$1として{{SITENAME}}にログインしました",
"group-checkuser.css": "/* ここに記述したCSSは利用者調査者のみに影響します */",
"group-checkuser.js": "/* ここに記述したJSは利用者調査者のみに影響します */",
- "apihelp-query+checkuser-description": "指定した利用者名の利用者が使用した IPアドレス や、指定した IPアドレス を使用した利用者名を調査します。",
- "apihelp-query+checkuser-summary": "指定した利用者名の利用者が使用した IPアドレス や、指定した IPアドレス を使用した利用者名を調査します。",
- "apihelp-query+checkuser-param-request": "利用者調査リクエストの種類です:\n;userips:対象利用者の IPアドレス を取得します。\n;edits:対象 IPアドレス または IPアドレス 範囲による編集を取得します。\n;ipusers:対象 IPアドレス または IPアドレス 範囲を使用した利用者を取得します。",
- "apihelp-query+checkuser-param-target": "調査する利用者名、IP アドレス、CIDR 範囲のいずれかです。",
- "apihelp-query+checkuser-param-reason": "調査の理由です。",
- "apihelp-query+checkuser-param-limit": "行数の上限です。",
- "apihelp-query+checkuser-param-timecond": "利用者データの期間の上限です (例: \"-2 weeks\" または \"2 weeks ago\")。",
- "apihelp-query+checkuser-param-xff": "IPアドレス の代わりに XFF データを使用します。",
- "apihelp-query+checkuser-example-1": "[[User:Example]] が使用した IPアドレス を調査",
- "apihelp-query+checkuser-example-2": "192.0.2.0/24 からなされた編集を調査",
- "apihelp-query+checkuserlog-description": "利用者調査の記録から項目を取得します。",
- "apihelp-query+checkuserlog-summary": "利用者調査の記録から項目を取得します。",
- "apihelp-query+checkuserlog-param-user": "利用者調査の実行者の利用者名です。",
- "apihelp-query+checkuserlog-param-target": "調査する対象の利用者、IP アドレス、CIDR範囲のいずれかです。",
- "apihelp-query+checkuserlog-param-limit": "行数の上限です。",
- "apihelp-query+checkuserlog-param-from": "一覧の開始点となる日時",
- "apihelp-query+checkuserlog-param-to": "一覧の終了点となる日時",
- "apihelp-query+checkuserlog-example-1": "[[User:Example]] の調査を表示",
- "apihelp-query+checkuserlog-example-2": "192.0.2.0/24 の 2011-10-15T23:00:00Z 以降の調査を表示",
- "apierror-checkuser-missingsummary": "調査理由を明確にする必要があります。"
+ "checkuser-investigateblock-actions": "ブロック操作",
+ "checkuser-investigateblock-notice-text-label": "ウィキテキスト",
+ "checkuser-investigateblock-notice-replace": "ページの置き換え",
+ "checkuser-investigate-subtitle-block-button-label": "ブロック",
+ "checkuser-investigate-subtitle-cancel-button-label": "キャンセル",
+ "checkuser-investigate-subtitle-continue-button-label": "続行",
+ "checkuser-investigate-indicator-logs": "記録",
+ "checkuser-investigate-legend": "利用者名、IPアドレス、IPアドレス範囲で検索",
+ "checkuser-investigate-notice-no-results": "結果はありません。",
+ "checkuser-investigate-tab-compare": "IPアドレスとユーザーエージェント",
+ "checkuser-investigate-tab-timeline": "時系列",
+ "checkuser-investigate-targets-label": "利用者名またはIPアドレス",
+ "checkuser-investigate-targets-placeholder": "利用者名 or 1.1.1.1",
+ "checkuser-investigate-reason-label": "理由",
+ "checkuser-investigate-preliminary-table-cell-blocked": "ブロック済",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1{{PLURAL:$1|回編集}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "ブロックされていない",
+ "checkuser-investigate-preliminary-table-header-blocked": "状態",
+ "checkuser-investigate-preliminary-table-header-editcount": "編集",
+ "checkuser-investigate-preliminary-table-header-groups": "グループ",
+ "checkuser-investigate-preliminary-table-header-name": "利用者名",
+ "checkuser-investigate-preliminary-table-header-wiki": "ウィキ",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "ウィキが見つかりませんでした",
+ "checkuser-investigate-filters-legend": "フィルター",
+ "checkuser-investigate-filters-exclude-targets-label": "次の利用者またはIPアドレスを非表示にする",
+ "checkuser-investigate-timeline-notice-no-results": "結果がありませんでした: 直近90日以内の利用者またはIPアドレスからの活動は記録されていません。",
+ "checkuser-investigate-timeline-notice-no-results-filters": "これらのフィルタ―条件に合致する結果はありません。フィルターの一部を解除して、検索範囲を拡大してみてください。",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "この利用者が使ったすべてのIPアドレスを表示",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "このIPアドレスを使ったすべての利用者を表示",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "このIPアドレスを調査に追加",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1{{PLURAL:$1|回編集}}]</b>",
+ "checkuser-investigate-compare-table-header-username": "利用者名",
+ "checkuser-investigate-compare-table-header-activity": "日付範囲",
+ "checkuser-investigate-compare-table-header-ip": "IPアドレス",
+ "checkuser-investigate-compare-table-header-useragent": "ユーザーエージェント",
+ "checkuser-investigate-tour-filterip-desc": "ユーザー名、IPアドレスまたはエージェント情報を除外してスッキリさせましょう。元へ戻したい?上部にある絞り込みパネルを使って絞り込み条件を削除して下さい。"
}
diff --git a/CheckUser/i18n/jv.json b/CheckUser/i18n/jv.json
index d013d7c9..8686d1e8 100644
--- a/CheckUser/i18n/jv.json
+++ b/CheckUser/i18n/jv.json
@@ -1,31 +1,33 @@
{
"@metadata": {
"authors": [
+ "Diki Ananta",
"Meursault2004",
"NoiX180",
- "Pras"
+ "Pras",
+ "Sumbukompor"
]
},
- "checkuser-summary": "Piranti iki nlusuri owah-owahan pungkasan kanggo golèk IP sing dienggo déning sawijining panganggo utawa nuduhaké data suntingan/panganggo kanggo sawijining IP.\nPanganggo lan suntingan bisa dirunut saka sawijining IP XFF mawa nambahaké \"/xff\" ing sawijining IP. IPv4 (CIDR $1-32) IPv6 (CIDR $2-128) bisa dienggo.\nAmerga déning alesan kinerja, ora luwih saka 5.000 suntingan sing bisa dijupuk. Mangga gunakna piranti iki miturut kawicaksanan sing wis ditetepaké.",
- "checkuser-desc": "Mènèhi panganggo fasilitas kanggo panganggo sing duwé idin kanggo mriksa alamat IP panganggo lan informasi liyané",
+ "checkuser-summary": "Piranti iki nlusuri owah-owahan pungkasan kanggo golèk IP sing dienggo déning sawijining naraguna utawa nuduhaké data suntingan/naraguna kanggo sawijining IP.\nNaraguna lan suntingan bisa dirunut saka sawijining IP XFF mawa nambahaké \"/xff\" ing sawijining IP. IPv4 (CIDR $1-32) IPv6 (CIDR $2-128) bisa dienggo.\nAmerga déning alesan kinerja, ora luwih saka 5.000 besutan sing bisa dijupuk. Mangga gunakna piranti iki miturut kawicaksanan sing wis ditetepaké.",
+ "checkuser-desc": "Mènèhi naraguna fasilitas kanggo naraguna sing duwé idin kanggo mriksa alamat IP naraguna lan informasi liyané",
"checkuser-logcase": "Log iki sènsitif marang panrapan aksara gedhé apa cilik",
- "checkuser": "Pamriksan panganggo",
- "checkuserlog": "Log pamriksan panganggo",
- "checkuser-contribs": "priksa alamat IP panganggo",
- "checkuser-contribs-log": "papriksan panganggo paling anyar",
- "group-checkuser": "Pamriksa panganggo",
+ "checkuser": "Pamriksan naraguna",
+ "checkuserlog": "Log pamriksan naraguna",
+ "checkuser-contribs": "priksa alamat IP naraguna",
+ "checkuser-contribs-log": "papriksan kang tembé marang naraguna",
+ "group-checkuser": "Pamriksa naraguna",
"group-checkuser-member": "{{GENDER:$1|pamiksa}}",
- "right-checkuser": "Priksa alamat-alamat IP panganggo lan informasi liyané",
+ "right-checkuser": "Priksa alamat-alamat IP naraguna lan informasi liyané",
"right-checkuser-log": "Pirsani log pamriksa",
- "action-checkuser": "priksa alamat IP lan inpormasi liya panganggo",
+ "action-checkuser": "priksa alamat IP lan inpormasi liya naraguna",
"action-checkuser-log": "deleng log pamriksa",
- "grouppage-checkuser": "{{ns:project}}:Pamriksa panganggo",
+ "grouppage-checkuser": "{{ns:project}}:Pamriksa naraguna",
"checkuser-reason": "Alesan:",
"checkuser-reason-api": "API: $1",
"checkuser-showlog": "Tuduhna log",
"checkuser-query": "Pitakonan owah-owahan pungkasan",
- "checkuser-target": "Alamat IP utawa jeneng panganggo:",
- "checkuser-users": "Golèk panganggo",
+ "checkuser-target": "Alamat IP utawa jeneng naraguna:",
+ "checkuser-users": "Golèk naraguna",
"checkuser-edits": "Golèk besutan",
"checkuser-ips": "Golèk IP",
"checkuser-period": "Jangka wektu:",
@@ -37,7 +39,7 @@
"checkuser-cidr-res": "CIDR umum:",
"checkuser-empty": "Log iki kosong.",
"checkuser-nomatch": "Ora ana data sing cocog bisa ditemokaké.",
- "checkuser-nomatch-edits": "Ora ana sing cocog.\nSuntingan pungkasan ing $2, $1.",
+ "checkuser-nomatch-edits": "Ora ana kang cocog.\nBesutan pungkasan ing $2, $1.",
"checkuser-check": "Priksa",
"checkuser-log-fail": "Log èntri ora bisa ditambahaké",
"checkuser-nolog": "Barkas log ora ana.",
@@ -46,28 +48,27 @@
"checkuser-locked": "Dikunci",
"checkuser-wasblocked": "Wis diblokir sadurungé",
"checkuser-localonly": "Ora digabungaké",
- "checkuser-massblock": "Blokir panganggo kapilih",
- "checkuser-massblock-text": "Akun-akun kapilih bakal diblokir salawasé, alamat-alamat IP pungkasan sing dipigunakaké otomatis diblokir lan ora bisa gawé akun.\nAlamat-alamat IP bakal diblokir jroning 1 minggu tumrap panganggo anonim lan ora bisa gawé akun.",
- "checkuser-blocktag": "Ganti kaca panganggo dadi:",
+ "checkuser-massblock": "Blokir naraguna kapilih",
+ "checkuser-massblock-text": "Akun-akun kapilih bakal diblokir salawasé, alamat-alamat IP pungkasan sing dipigunakaké otomatis diblokir lan ora bisa gawé akun.\nAlamat-alamat IP bakal diblokir jroning 1 minggu tumrap naraguna anonim lan ora bisa gawé akun.",
+ "checkuser-blocktag": "Ganti kaca naraguna dadi:",
"checkuser-blocktag-talk": "Ganti kaca parembugan karo:",
- "checkuser-massblock-commit": "Blokir panganggo kapilih",
- "checkuser-block-success": "'''{{PLURAL:$2|Panganggo|panganggo}} $1 {{PLURAL:$2|wis|wis}} diblokir.'''",
- "checkuser-block-failure": "'''Ora ana panganggo sing diblokir.'''",
- "checkuser-block-limit": "Cacahing panganggo sing dipilih kakèhan.",
+ "checkuser-massblock-commit": "Blokir naraguna kapilih",
+ "checkuser-block-success": "'''{{PLURAL:$2|Naraguna|Naraguna}} $1 {{PLURAL:$2|wis|wis}} diblokir.'''",
+ "checkuser-block-failure": "'''Ora ana naraguna sing diblokir.'''",
+ "checkuser-block-limit": "Cacahing naraguna sing dipilih kakèhan.",
"checkuser-block-noreason": "Panjenengan kudu wènèh alesan mblokir.",
"checkuser-noreason": "Panjenengan kudu ngawèhi alesan kanggo kuèri iki.",
- "checkuser-accounts": "$1 {{PLURAL:$1|akun|akun-akun}} anyar",
"checkuser-too-many": "Kakèhan pituwas (miturut estimasi piakonan), tulung CIDR diciyutaké.\nIng ngisor iki kapacak alamat-alamat IP sing dianggo (maks. 5.000, diurutaké miturut alamat):",
- "checkuser-user-nonexistent": "Panganggo iki ora ana.",
+ "checkuser-user-nonexistent": "Naraguna iki ora ana.",
"checkuser-search": "Golèk",
"checkuser-search-submit": "Golèk",
"checkuser-search-initiator": "pamriksa",
"checkuser-search-target": "tujuan",
- "checkuser-ipeditcount": "~$1 saka kabèh panganggo",
- "checkuser-showmain": "Ganti nèng pormulir utama CheckUser",
+ "checkuser-ipeditcount": "~$1 saka kabèh naraguna",
+ "checkuser-showmain": "Salin ing blangko pokok CheckUser",
"checkuser-limited": "'''Kasil iki wis dicekak amarga alesan kinerja.'''",
"checkuser-autocreate-action": "digawé sacara otomatis",
"checkuser-create-action": "digawé",
"checkuser-email-action": "ngirim layang-èl menyang \"$1\"",
- "checkuser-reset-action": "setèl ulang tembung wadiné panganggo \"$1\""
+ "checkuser-reset-action": "setèl ulang tembung sandiné naraguna \"$1\""
}
diff --git a/CheckUser/i18n/ka.json b/CheckUser/i18n/ka.json
index afc33ce9..6ca2db24 100644
--- a/CheckUser/i18n/ka.json
+++ b/CheckUser/i18n/ka.json
@@ -5,8 +5,8 @@
"David1010",
"Dawid Deutschland",
"Malafaya",
- "გიორგიმელა",
- "Otogi"
+ "Otogi",
+ "გიორგიმელა"
]
},
"checkuser-desc": "ეძლევა შესაძლებლობა შეამოწმოს IP და მომხმარებლების დამატებითი ინფორმაცია",
@@ -56,7 +56,6 @@
"checkuser-block-limit": "არჩეულია ზედმეტად ბევრი მომხმარებელი.",
"checkuser-block-noreason": "თქვენ უნდა მიუთითოთ ბლოკირების მიზეზი.",
"checkuser-noreason": "თქვენ უნდა მიუთითოთ მიზეზი ამ შეკითხვისთვის.",
- "checkuser-accounts": "$1 ახალი {{PLURAL:$1|ანგარიში|ანგარიშები}}",
"checkuser-too-many": "ძალიან ბევრი რეზულტატი, გთხოვთ შეავიწროოთ CIDR-ი.\nგამოყენებული IP (მაქსიმუმ 500, სორტირებულია მისამართის თანახმად)",
"checkuser-user-nonexistent": "ეს მომხმარებელი არ არსებობს.",
"checkuser-search": "ძიება",
@@ -70,8 +69,5 @@
"checkuser-create-action": "შეიქმნა",
"checkuser-email-action": "გაუგზავნა წერილი მომხმარებელ «$1»-ს",
"checkuser-reset-action": "პაროლის შეცვლა მომხმარებლისთვის \"$1\"",
- "checkuser-token-fail": "სესია შეწყდა. გთხოვთ, თავიდან სცადოთ.",
- "apihelp-query+checkuser-param-reason": "შეჩერების მიზეზი",
- "apihelp-query+checkuser-param-limit": "რიგების ლიმიტი",
- "apihelp-query+checkuserlog-param-limit": "რიგების ლიმიტი"
+ "checkuser-token-fail": "სესია შეწყდა. გთხოვთ, თავიდან სცადოთ."
}
diff --git a/CheckUser/i18n/kjp.json b/CheckUser/i18n/kjp.json
new file mode 100644
index 00000000..e1b071ee
--- /dev/null
+++ b/CheckUser/i18n/kjp.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rul1902"
+ ]
+ },
+ "checkuser-target": "အါင်ပီလင်ဍာ မွာဲအိုဝ် ဆ်ုသုံႋဏင့်ဆာႋမိင်:",
+ "checkuser-all": "လုက်ဆိင့်",
+ "checkuser-search-submit": "မ်ုအင်းၰူ့"
+}
diff --git a/CheckUser/i18n/kk-arab.json b/CheckUser/i18n/kk-arab.json
index 385bf4e5..c256cdda 100644
--- a/CheckUser/i18n/kk-arab.json
+++ b/CheckUser/i18n/kk-arab.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser-summary": "بۇل قۇرال پايدالانۋشى قولدانعان IP جايلار ٴۇشىن, نەمەسە IP جاي تۇزەتۋ/پايدالانۋشى دەرەكتەرىن كورسەتۋ ٴۇشىن جۋىقتاعى وزگەرىستەردى قاراپ شىعادى.\n\tپايدالانۋشىلاردى مەن تۇزەتۋلەردى XFF IP ارقىلى IP جايعا «/xff» دەگەندى قوسىپ كەلتىرۋگە بولادى. IPv4 (CIDR $1-32) جانە IPv6 (CIDR $2-128) ارقاۋلانادى.\n\tورىنداۋشىلىق سەبەپتەرىمەن 5000 تۇزەتۋدەن ارتىق قايتارىلمايدى. بۇنى ەرەجەلەرگە سايكەس پايدالانىڭىز.",
"checkuser-logcase": "جۋرنالدان ىزدەۋ ٴارىپ باس-كىشىلىگىن ايىرادى.",
"checkuser": "قاتىسۋشىنى سىناۋ",
diff --git a/CheckUser/i18n/kk-cyrl.json b/CheckUser/i18n/kk-cyrl.json
index 2232e6a1..f2e61761 100644
--- a/CheckUser/i18n/kk-cyrl.json
+++ b/CheckUser/i18n/kk-cyrl.json
@@ -42,7 +42,6 @@
"checkuser-block-limit": "Өте көп қатысушы таңдалды.",
"checkuser-block-noreason": "Бұғаттау себебін көрсетуіңіз керек.",
"checkuser-noreason": "Бұл сұраныс үшін себебін көрсетуіңіз керек.",
- "checkuser-accounts": "$1 жаңа {{PLURAL:$1|аккаунт|аккаунт}}",
"checkuser-too-many": "Тым көп нәтиже келтірілді, CIDR дегенді тарылтып көріңіз. Мында пайдаланылған IP жайлар көрсетілген (барынша 5000, жайымен сұрыпталған):",
"checkuser-user-nonexistent": "Енгізілген қатысушы жоқ.",
"checkuser-search": "Іздеу",
diff --git a/CheckUser/i18n/kk-latn.json b/CheckUser/i18n/kk-latn.json
index 57299fea..6ce95bf5 100644
--- a/CheckUser/i18n/kk-latn.json
+++ b/CheckUser/i18n/kk-latn.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser-summary": "Bul qural paýdalanwşı qoldanğan IP jaýlar üşin, nemese IP jaý tüzetw/paýdalanwşı derekterin körsetw üşin jwıqtağı özgeristerdi qarap şığadı.\n\tPaýdalanwşılardı men tüzetwlerdi XFF IP arqılı IP jaýğa «/xff» degendi qosıp keltirwge boladı. IPv4 (CIDR $1-32) jäne IPv6 (CIDR $2-128) arqawlanadı.\n\tOrındawşılıq sebepterimen 5000 tüzetwden artıq qaýtarılmaýdı. Bunı erejelerge säýkes paýdalanıñız.",
"checkuser-logcase": "Jwrnaldan izdew ärip bas-kişiligin aýıradı.",
"checkuser": "Qatıswşını sınaw",
diff --git a/CheckUser/i18n/km.json b/CheckUser/i18n/km.json
index f0a5fda1..b16ea982 100644
--- a/CheckUser/i18n/km.json
+++ b/CheckUser/i18n/km.json
@@ -24,7 +24,7 @@
"checkuser-reason": "មូលហេតុ៖",
"checkuser-reason-api": "API៖ $1",
"checkuser-showlog": "បង្ហាញកំណត់ហេតុ",
- "checkuser-query": "សំណើសុំបំលាស់ប្ដូរថ្មីៗ",
+ "checkuser-query": "សំណើសុំបន្លាស់ប្ដូរថ្មីៗ",
"checkuser-target": "អាសយដ្ឋានIP ឬ អត្តនាម៖",
"checkuser-users": "ទទួលអ្នកប្រើប្រាស់",
"checkuser-edits": "ទទួលកំណែប្រែ",
@@ -52,7 +52,6 @@
"checkuser-block-limit": "មានអ្នកប្រើប្រាស់ច្រើនពេកហើយត្រូវបានជ្រើសរើស។",
"checkuser-block-noreason": "អ្នកត្រូវតែផ្ដល់មូលហេតុសម្រាប់ការរាំងខ្ទប់។",
"checkuser-noreason": "អ្នកត្រូវតែផ្ដល់មូលហេតុសំរាប់សំណើសុំនេះ។",
- "checkuser-accounts": "គណនីថ្មីចំនួន $1",
"checkuser-too-many": "លទ្ធផល​ច្រើនពេក (ផ្អែកតាមការប៉ាន់ស្មាន)។ សូមបង្រួម CIDR ។\nនេះគឺ IP ដែលបានប្រើប្រាស់ (អតិបរមា ៥០០០, រៀបតាម​អាសយដ្ឋាន)​៖",
"checkuser-user-nonexistent": "មិនមានអ្នកប្រើប្រាស់ដូចដែលបានបញ្ជាក់ទេ។",
"checkuser-search": "ស្វែងរក",
diff --git a/CheckUser/i18n/ko.json b/CheckUser/i18n/ko.json
index b53c35b0..5ab09a53 100644
--- a/CheckUser/i18n/ko.json
+++ b/CheckUser/i18n/ko.json
@@ -2,19 +2,21 @@
"@metadata": {
"authors": [
"Albamhandae",
+ "Ellif",
"Ficell",
+ "IRTC1015",
+ "Jerrykim306",
"Klutzy",
"Kwj2772",
- "ToePeu",
- "관인생략",
- "아라",
+ "McDutchie",
+ "MemphisA5",
+ "Priviet",
"Revi",
"SeoJeongHo",
- "IRTC1015",
- "Priviet",
+ "ToePeu",
"Ykhwong",
- "Jerrykim306",
- "McDutchie"
+ "관인생략",
+ "아라"
]
},
"checkuser-summary": "이 도구는 최근의 변경 사항을 검사하여 특정 사용자가 이용한 IP 주소를 검색하거나 특정 IP 주소에 대한 편집/사용자 정보를 보여줍니다.\n클라이언트 IP를 통한 사용자와 편집은 IP 주소 뒤에 \"/xff\"를 추가함으로써 XFF 헤더를 통해 조사할 수 있습니다. IPv4 (CIDR $1-32)와 IPv6 (CIDR $2-128)을 지원합니다.\n성능 상의 이유로 최대 5,000개의 편집만 반환됩니다.\n이 도구는 정책에 맞게 사용하십시오.",
@@ -72,8 +74,7 @@
"checkuser-block-noreason": "차단하는 이유를 반드시 입력해야 합니다.",
"checkuser-centralauth-multilock": "선택한 여러 계정을 잠그기",
"checkuser-noreason": "이 명령에 대한 이유를 반드시 제시해야 합니다.",
- "checkuser-accounts": "새 {{PLURAL:$1|계정}} $1개",
- "checkuser-too-many": "쿼리 정보의 결과가 너무 많습니다. CIDR 범위를 좁혀 주세요.\n다음은 사용되고 있는 IP 주소의 목록입니다 (최대 5000개, 주소별로 정렬됨):",
+ "checkuser-too-many": "쿼리 정보의 결과가 너무 많습니다. CIDR 범위를 좁혀 주세요.\n다음은 사용되고 있는 IP 주소의 목록입니다 (최대 $1개, 주소별로 정렬됨):",
"checkuser-user-nonexistent": "해당 사용자가 존재하지 않습니다.",
"checkuser-search": "사용자 검사 기록 항목 검색",
"checkuser-search-submit": "검색",
@@ -85,10 +86,10 @@
"checkuser-showmain": "사용자검사 기본 양식으로 돌아가기",
"checkuser-limited": "'''성능 상의 이유로 결과 중 일부만 보여줍니다.'''",
"checkuser-log-entry-userips": "$3, $1님이 $2의 IP 주소를 조회했습니다",
- "checkuser-log-entry-ipedits": "$3, $1님이 $2의 편집을 조회했습니다",
- "checkuser-log-entry-ipusers": "$3, $1님이 $2 IP를 사용한 계정을 조회했습니다",
- "checkuser-log-entry-ipedits-xff": "$3, $1님이 XFF $2의 편집을 조회했습니다",
- "checkuser-log-entry-ipusers-xff": "$3, $1님이 XFF $2의 사용자를 조회했습니다",
+ "checkuser-log-entry-ipedits": "$3, $1님이 <bdi>$2</bdi>의 편집을 조회했습니다",
+ "checkuser-log-entry-ipusers": "$3, $1님이 <bdi>$2</bdi> IP를 사용한 계정을 조회했습니다",
+ "checkuser-log-entry-ipedits-xff": "$3, $1님이 XFF <bdi>$2</bdi>의 편집을 조회했습니다",
+ "checkuser-log-entry-ipusers-xff": "$3, $1님이 XFF <bdi>$2</bdi>의 사용자를 조회했습니다",
"checkuser-log-entry-useredits": "$3, $1님이 $2님의 편집을 조회했습니다",
"checkuser-autocreate-action": "자동으로 만들어졌습니다",
"checkuser-create-action": "만들어졌습니다",
@@ -99,26 +100,53 @@
"checkuser-login-success": "{{SITENAME}}에 $1님으로 성공적으로 로그인했습니다",
"group-checkuser.css": "/* 이 CSS 설정은 검사관에만 적용됩니다 */",
"group-checkuser.js": "/* 이 자바스크립트 설정은 검사관에만 적용됩니다 */",
- "apihelp-query+checkuser-description": "특정한 사용자가 어떤 IP 주소를 썼는지 확인하거나 특정한 IP 주소를 사용한 계정 이름을 확인합니다.",
- "apihelp-query+checkuser-summary": "특정한 사용자가 어떤 IP 주소를 썼는지 확인하거나 특정한 IP 주소를 사용한 계정 이름을 확인합니다.",
- "apihelp-query+checkuser-param-request": "검사 요청의 유형:\n;userips: 대상 사용자의 IP 주소를 불러옴.\n;edits: 대상 IP 주소나 대역에서 이루어진 편집을 불러옴.\n;ipusers: 대상 IP 주소나 대역을 사용한 계정을 불러옴.",
- "apihelp-query+checkuser-param-target": "검사할 계정 이름, IP 주소 혹은 CIDR 범위",
- "apihelp-query+checkuser-param-reason": "검사 이유.",
- "apihelp-query+checkuser-param-limit": "검사 한도",
- "apihelp-query+checkuser-param-timecond": "사용자 데이터의 시간 제약 (예: \"-2 weeks\" 또는 \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "IP 주소 대신 XFF 데이터를 이용.",
- "apihelp-query+checkuser-example-1": "[[User:Example]]에 대해 IP 주소 검사",
- "apihelp-query+checkuser-example-2": "192.0.2.0/24에 대해 편집 검사",
- "apihelp-query+checkuserlog-description": "검사관 기록에서 항목을 가져옵니다.",
- "apihelp-query+checkuserlog-summary": "검사관 기록에서 항목을 가져옵니다.",
- "apihelp-query+checkuserlog-param-user": "검사관의 사용자 이름",
- "apihelp-query+checkuserlog-param-target": "검사된 사용자, IP 주소, CIDR 범위",
- "apihelp-query+checkuserlog-param-limit": "검사 한도",
- "apihelp-query+checkuserlog-param-from": "나열을 시작할 타임스탬프",
- "apihelp-query+checkuserlog-param-to": "나열을 끝낼 타임스탬프",
- "apihelp-query+checkuserlog-example-1": "[[User:Example]]에 대한 검사 보기",
- "apihelp-query+checkuserlog-example-2": "192.0.2.0/24에 대한 2011-10-15T23:00:00Z 이후의 검사 보기",
- "apierror-checkuser-missingsummary": "검사 이유를 지정해야 합니다.",
- "apierror-checkuser-timelimit": "올바른 시간 형식(\"-2 weeks\" 혹은 \"2 weeks ago\"과 같이)으로 사용하셔야 합니다.",
- "apierror-checkuser-invalidmode": "잘못된 요청 모드"
+ "checkuser-investigateblock": "사용자 차단",
+ "checkuser-investigateblock-target": "계정 이름과 IP 주소",
+ "checkuser-investigateblock-actions": "차단할 행위",
+ "checkuser-investigateblock-options": "추가 옵션",
+ "checkuser-investigateblock-email-label": "이메일을 보내지 못하도록 막기",
+ "checkuser-investigateblock-notice-user-page-label": "사용자 문서에 알림 남기기",
+ "checkuser-investigateblock-notice-talk-page-label": "사용자 토론 문서에 알림 남기기",
+ "checkuser-investigateblock-notice-position-label": "위치",
+ "checkuser-investigateblock-notice-text-label": "위키텍스트",
+ "checkuser-investigateblock-notice-append": "페이지에 덧붙이기",
+ "checkuser-investigateblock-notice-replace": "페이지 바꾸기",
+ "checkuser-investigate": "조사하기",
+ "checkuser-investigate-subtitle-cancel-button-label": "취소",
+ "checkuser-investigate-subtitle-continue-button-label": "계속",
+ "checkuser-investigate-indicator-logs": "기록",
+ "checkuser-investigate-legend": "계정 이름, IP 주소 또는 IP 대역 검색",
+ "checkuser-investigate-notice-no-results": "결과가 없습니다.",
+ "checkuser-investigate-tab-preliminary-check": "계정 정보",
+ "checkuser-investigate-tab-compare": "IP 및 사용자 에이전트",
+ "checkuser-investigate-tab-timeline": "타임라인",
+ "checkuser-investigate-targets-label": "계정 이름과 IP 주소",
+ "checkuser-investigate-targets-placeholder": "사용자 이름 또는 1.1.1.1",
+ "checkuser-investigate-duration-option-all": "모두",
+ "checkuser-investigate-duration-option-2w": "지난 2주",
+ "checkuser-investigate-reason-label": "이유",
+ "checkuser-investigate-preliminary-table-header-blocked": "상태",
+ "checkuser-investigate-preliminary-table-header-editcount": "편집",
+ "checkuser-investigate-preliminary-table-header-groups": "그룹",
+ "checkuser-investigate-preliminary-table-header-name": "사용자 이름",
+ "checkuser-investigate-preliminary-table-header-wiki": "위키",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "위키를 찾을 수 없습니다",
+ "checkuser-investigate-filters-legend": "필터",
+ "checkuser-investigate-timeline-notice-no-results": "결과가 없습니다: 최근 90일 내에 이 사용자 또는 IP의 활동 기록이 없습니다",
+ "checkuser-investigate-timeline-notice-no-results-filters": "이 필터 조건에 일치하는 결과가 없습니다. 일부 필터를 제거하여 검색 범위를 확대해 보십시오.",
+ "checkuser-investigate-compare-copy-button-label": "위키텍스트 보기",
+ "checkuser-investigate-compare-toollinks-ipcheck": "프록시 검사",
+ "checkuser-investigate-compare-copy-message-label": "이 정보를 위키텍스트 표로 복사하시겠습니까?",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "이 사용자의 모든 IP 표시",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "이 IP의 모든 사용자 표시",
+ "checkuser-investigate-compare-table-button-contribs-label": "기여",
+ "checkuser-investigate-compare-table-button-filter-label": "결과 필터",
+ "checkuser-investigate-compare-table-cell-unregistered": "등록 안 됨",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|편집}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(모든 사용자 기준 ~$1건)</i>",
+ "checkuser-investigate-compare-table-header-username": "사용자 이름",
+ "checkuser-investigate-compare-table-header-activity": "날짜 범위",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "사용자 에이전트",
+ "checkuser-investigate-tour-copywikitext-title": "데이터를 복사하시겠습니까?"
}
diff --git a/CheckUser/i18n/krc.json b/CheckUser/i18n/krc.json
index 0f2f7181..1b3ff11f 100644
--- a/CheckUser/i18n/krc.json
+++ b/CheckUser/i18n/krc.json
@@ -1,8 +1,8 @@
{
"@metadata": {
"authors": [
- "Iltever",
- "Ernác"
+ "Ernác",
+ "Iltever"
]
},
"group-checkuser": "Къошулуучуланы тинтиучюле"
diff --git a/CheckUser/i18n/ksh.json b/CheckUser/i18n/ksh.json
index 4ee82ca0..5ce3a3d5 100644
--- a/CheckUser/i18n/ksh.json
+++ b/CheckUser/i18n/ksh.json
@@ -56,7 +56,6 @@
"checkuser-block-limit": "Zoh fill Metmaacher sin ußjesoht.",
"checkuser-block-noreason": "Do moß ävver ene Jrond för et Schpärre aanjävve.",
"checkuser-noreason": "Do moß ene Jrond för heh di Övverpröhvong aanjävve.",
- "checkuser-accounts": "{{PLURAL:$1|Eine|$1|Keine}} neue Metmaacher",
"checkuser-too-many": "Zoo fill jefonge, pä Övverschlaach. Beß esu jood un maach dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt kleijner.\nHeh sin de eetßte 5000 <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße, zottehrt:",
"checkuser-user-nonexistent": "Dä aanjejovve Metmaacher jidd_et jaa nit.",
"checkuser-search": "Söhk em Logbohch vum Metmaacher-Övverwaache",
@@ -68,10 +67,10 @@
"checkuser-showmain": "Zerök zom Houpfommolaa vum „Metmaacher Övverprööfe“",
"checkuser-limited": "'''Di Leß es affjeschnedde, öm nit der ẞööver onnühdesch ze belaste.'''",
"checkuser-log-entry-userips": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße för $2 jehollt.",
- "checkuser-log-entry-ipedits": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Ännderonge för $2 jehollt.",
- "checkuser-log-entry-ipusers": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Metmaacher för $2 jehollt.",
- "checkuser-log-entry-ipedits-xff": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Ännderonge för <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">XFF</i> $2 jehollt.",
- "checkuser-log-entry-ipusers-xff": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Metmaacher för <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">XFF</i> $2 jehollt.",
+ "checkuser-log-entry-ipedits": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Ännderonge för <bdi>$2</bdi> jehollt.",
+ "checkuser-log-entry-ipusers": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Metmaacher för <bdi>$2</bdi> jehollt.",
+ "checkuser-log-entry-ipedits-xff": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Ännderonge för <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">XFF</i> <bdi>$2</bdi> jehollt.",
+ "checkuser-log-entry-ipusers-xff": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Metmaacher för <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">XFF</i> <bdi>$2</bdi> jehollt.",
"checkuser-log-entry-useredits": "{{GENDER:$1|Dä|Dat|Dä Metmaacher|De|Dat}} „$1“ hät aam $4 öm $5 de Ännderonge för $2 jehollt.",
"checkuser-autocreate-action": "wohd automattesch aanjelaat",
"checkuser-create-action": "wood aanjelaat",
@@ -79,22 +78,5 @@
"checkuser-reset-action": "Däm Metmaacher „$1“ sing Paßwoot automattesch neu setze",
"checkuser-token-fail": "Fähler met de Sezongsdahte. Vershögk et norr_ens.",
"group-checkuser.css": "/* Dat CSS heh aan dä Stell wirrek nur op de Metmaacher-Övverpröhfer */",
- "group-checkuser.js": "/* Dat JavaSkrep heh aan dä Stell wirrek nur op de Metmaacher-Övverpröhfer */",
- "apihelp-query+checkuser-description": "Donn övverpröhve wat för en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße vun enem metmaacher med enem beschtemmpte Nahme udder wat för en nahme vun Metmaacher övver en beschtemmpte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß em Wikki opdouche.",
- "apihelp-query+checkuser-param-request": "De Zood Övverpröhvong:\n;userips:Holl enem Metmaacher sing <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß.\n;edits:Holl de Änderonge över en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß udder ene Berätt.\n;ipusers:Holl de Metmaacher för en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß udder ene Berätt.",
- "apihelp-query+checkuser-param-target": "Däm Metmaacher singe Nahme, de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß, udder dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt zom Övverpröhve.",
- "apihelp-query+checkuser-param-reason": "der Jrond för et Övverpröhfe.",
- "apihelp-query+checkuser-param-limit": "En Bejränzung för de Aanzahl Reihje.",
- "apihelp-query+checkuser-param-timecond": "En Bejränzung noh de Zigg för der Ömfang vun Aanjahbe övver Metmaacher, allso esu jät wi: „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">2 weeks</code>“",
- "apihelp-query+checkuser-param-xff": "Nemm de Aanjahbe uß dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"X-Forwarded-For\">XFF</i>-Koppreih un nit de tiräkte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß.",
- "apihelp-query+checkuser-example-1": "Övverpröhv de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße vum [[Metmaacher:Beijschpell]]\n<!--\nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Bcheckuser-example-1/en_(3)\n-->",
- "apihelp-query+checkuser-example-2": "Donn Änderonge vun <code>192.0.2.0/24</code> övverpröhfe.",
- "apihelp-query+checkuserlog-description": "Holl Enndrähsch vum {{int:Checkuserlog}}",
- "apihelp-query+checkuserlog-param-user": "Dä Nahme vun däm Metmaacher vum {{int:Checkuser}}.",
- "apihelp-query+checkuserlog-param-target": "Dä jepröhvte Metmaacher, de jepröhvte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß, udder dä jepröhvte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt.",
- "apihelp-query+checkuserlog-param-limit": "De Jränß aan Reihje.",
- "apihelp-query+checkuserlog-param-from": "Dattum un Uhrzigg, vun woh aan opzälle.",
- "apihelp-query+checkuserlog-param-to": "Dattum un Uhrzigg, bes wann opzälle.",
- "apihelp-query+checkuserlog-example-1": "Donn de Övverpröhfonge vum „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[User:Example]]</code>“ aanzeije.",
- "apihelp-query+checkuserlog-example-2": "Zeisch de Övverpröhvonge vun 192.0.2.0/24 aff 2011-10-15T23:00:00Z"
+ "group-checkuser.js": "/* Dat JavaSkrep heh aan dä Stell wirrek nur op de Metmaacher-Övverpröhfer */"
}
diff --git a/CheckUser/i18n/ku-latn.json b/CheckUser/i18n/ku-latn.json
index 3ac5ad03..01a3bfaa 100644
--- a/CheckUser/i18n/ku-latn.json
+++ b/CheckUser/i18n/ku-latn.json
@@ -2,6 +2,7 @@
"@metadata": {
"authors": [
"Bangin",
+ "Bikarhêner",
"George Animal"
]
},
@@ -14,5 +15,11 @@
"checkuser-search": "Lêbigere",
"checkuser-search-submit": "Lêbigere",
"checkuser-ipeditcount": "~$1 ji hemû bikarhêneran",
- "checkuser-create-action": "hat afirandin"
+ "checkuser-create-action": "hat afirandin",
+ "checkuser-investigateblock-notice-text-label": "Wîkînivîs",
+ "checkuser-investigate-duration-label": "Mawe",
+ "checkuser-investigate-duration-option-all": "Hemû",
+ "checkuser-investigate-duration-option-1w": "Hefteya dawî",
+ "checkuser-investigate-duration-option-2w": "2 heftiyên dawîn",
+ "checkuser-investigate-duration-option-30d": "30 rojên dawî"
}
diff --git a/CheckUser/i18n/kw.json b/CheckUser/i18n/kw.json
new file mode 100644
index 00000000..dd1678ee
--- /dev/null
+++ b/CheckUser/i18n/kw.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "GwikorFrank"
+ ]
+ },
+ "checkuser-investigate-duration-option-all": "Oll"
+}
diff --git a/CheckUser/i18n/lb.json b/CheckUser/i18n/lb.json
index 95ae7505..6b40938a 100644
--- a/CheckUser/i18n/lb.json
+++ b/CheckUser/i18n/lb.json
@@ -54,14 +54,14 @@
"checkuser-blocktalk": "Verhënnere fir seng eegen Diskussiounssäit z'ännere sou laang wéi e gespaart ass",
"checkuser-blocktag": "Benotzersäiten duerch dëst ersetzen:",
"checkuser-blocktag-talk": "Diskussiounssäiten ersetzen duerch:",
+ "checkuser-reblock": "Spären déi et gëtt iwwerschreiwen",
"checkuser-massblock-commit": "Ausgewielt Benotzer spären",
"checkuser-block-success": "'''{{PLURAL:$2|De Benotzer|D'Benotzer}} $1 {{PLURAL:$2|ass|sinn}} elo gespaart.'''",
"checkuser-block-failure": "'''Et si keng Benotzer gespaart.'''",
"checkuser-block-limit": "Zevill Benotzer ugewielt.",
"checkuser-block-noreason": "Dir musst e Grond fir d'Spären uginn.",
"checkuser-noreason": "Dir musst e Grond fir dës Ufro uginn.",
- "checkuser-accounts": "$1 {{PLURAL:$1|neie Benotzerkont|nei Benotzerkonten}}",
- "checkuser-too-many": "Zevill Resultater (am Vergäich zu der Schätzung vun der Ufro), reduzéiert w.e.g. de Beräich vum CIDR.\nHei sinn déi benotzten IP-Adressen (max 5000, zortéiert no der Adress):",
+ "checkuser-too-many": "Zevill Resultater (am Vergäich zu der Schätzung vun der Ufro), reduzéiert wgl. de Beräich vum CIDR.\nHei sinn déi benotzten IP-Adressen (max 5000, zortéiert no der Adress):",
"checkuser-user-nonexistent": "De gesichte Benotzer gëtt et net.",
"checkuser-search": "Am CheckUser-Logbuch sichen",
"checkuser-search-submit": "Sichen",
@@ -72,12 +72,52 @@
"checkuser-ipeditcount": "~$1 vun alle Benotzer",
"checkuser-showmain": "Op den Haaptformulaire vun CheckUser wiesselen",
"checkuser-limited": "'''Dës Lëscht gouf aus Grënn vun der performance vun de Servere gekierzt.'''",
- "checkuser-log-entry-ipedits": "$3, $1 huet d'Ännerunge vun $2 kritt",
+ "checkuser-log-entry-ipedits": "$3, $1 huet d'Ännerunge vun <bdi>$2</bdi> kritt",
"checkuser-autocreate-action": "gouf automatesch ugeluecht",
"checkuser-create-action": "gouf ugeluecht",
"checkuser-email-action": "dem Benotzer \"$1\" eng E-Mail geschéckt",
"checkuser-reset-action": "huet d'Passwuert fir de Benotzer \"$1\" zréckgesat",
- "checkuser-token-fail": "Sessiouns-Feeler.Probéiert w.e.g. nach eng Kéier.",
+ "checkuser-token-fail": "Sessiouns-Feeler.Probéiert wgl. nach eng Kéier.",
"checkuser-login-success": "Op {{SITENAME}} ageloggt als $1",
- "apihelp-query+checkuser-param-reason": "Grond fir nozekucken."
+ "checkuser-link-investigate-label": "Probéiert dat neit CheckUser-Geschier",
+ "checkuser-investigateblock": "Benotzer spären",
+ "checkuser-investigateblock-target": "Benotzernimm an IP-Adressen",
+ "checkuser-investigateblock-reason": "Grond",
+ "checkuser-investigateblock-options": "Zousätzlech Optiounen",
+ "checkuser-investigateblock-email-label": "Verhënnere fir E-Mailen ze verschécken",
+ "checkuser-investigateblock-notice-user-page-label": "Eng Notiz op d'Beno9tzersäit setzen",
+ "checkuser-investigateblock-notice-talk-page-label": "Eng Notiz op der Benotzer-Diskussiouns-Säit hannerloossen",
+ "checkuser-investigateblock-notice-position-label": "Positioun",
+ "checkuser-investigateblock-notice-text-label": "Wikitext",
+ "checkuser-investigateblock-notice-replace": "Säit ersetzen",
+ "checkuser-investigate-subtitle-block-button-label": "Spären",
+ "checkuser-investigate-subtitle-cancel-button-label": "Ofbriechen",
+ "checkuser-investigate-subtitle-continue-button-label": "Virufueren",
+ "checkuser-investigate-indicator-new-investigation": "Nei Enquête",
+ "checkuser-investigate-indicator-logs": "Logbicher",
+ "checkuser-investigate-notice-no-results": "Et gëtt keng Resultater.",
+ "checkuser-investigate-tab-preliminary-check": "Benotzerkontinformatioun",
+ "checkuser-investigate-tab-compare": "IP-Adressen a User Agents",
+ "checkuser-investigate-tab-timeline": "Chronologie",
+ "checkuser-investigate-targets-label": "Benotzernimm oder IP-Adressen",
+ "checkuser-investigate-targets-placeholder": "Benotzernumm oder 1.1.1.1",
+ "checkuser-investigate-duration-label": "Dauer",
+ "checkuser-investigate-duration-option-all": "All",
+ "checkuser-investigate-duration-option-1w": "Lescht Woch",
+ "checkuser-investigate-duration-option-2w": "Lescht 2 Wochen",
+ "checkuser-investigate-duration-option-30d": "Lescht 30 Deeg",
+ "checkuser-investigate-reason-label": "Grond",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki gouf net fonnt",
+ "checkuser-investigate-filters-legend": "Filteren",
+ "checkuser-investigate-filters-exclude-targets-label": "Dës Benotzer oder IPen verstoppen",
+ "checkuser-investigate-compare-copy-button-label": "Wikitext weisen",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "All IP-Adresse vun dësem Benotzer weisen",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Weist all Benotzer mat dëser IP-Adress",
+ "checkuser-investigate-compare-table-button-filter-label": "Aus de Resultater filteren",
+ "checkuser-investigate-compare-table-cell-unregistered": "Net-ugemellt",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 vun alle Benotzer)</i>",
+ "checkuser-investigate-compare-table-header-username": "Benotzernumm",
+ "checkuser-investigate-compare-table-header-activity": "Datumsberäich",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-tour-addusertargets-title": "Braucht Dir méi Kontext?"
}
diff --git a/CheckUser/i18n/li.json b/CheckUser/i18n/li.json
index 5d7f774d..06a00016 100644
--- a/CheckUser/i18n/li.json
+++ b/CheckUser/i18n/li.json
@@ -61,7 +61,6 @@
"checkuser-block-noreason": "De mós 'ne rieë ópgaeve veure blokkaazjes.",
"checkuser-centralauth-multilock": "Sloet alle gesillekteerde konto's",
"checkuser-noreason": "De mós 'ne rieë ópgaeve veure zeukópdrach.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nuuje gebroeker|nuuj gebroekers}}",
"checkuser-too-many": "Te väöl rezultaote (volges de sjatting). Maak de CIDR kleinder:\nHie zeen de gebroekde IPs (max. 5000, op adres gesorteerd):",
"checkuser-user-nonexistent": "De opgegaeve gebroeker besteit neet.",
"checkuser-search": "Doorzeuk checkuserlogbookregele",
@@ -74,10 +73,10 @@
"checkuser-showmain": "Gank nao 't huidformeleer van CheckUser",
"checkuser-limited": "'''Dees rizzeltaote zeen neet gans óm perstaasjereeje.'''",
"checkuser-log-entry-userips": "$3, $1 haet IP-adresse opgevraog veur $2",
- "checkuser-log-entry-ipedits": "$3, $1 haet bewirkinge opgevraog veur $2",
- "checkuser-log-entry-ipusers": "$3, $1 haet gebroekers opgevraog veur $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 haet bewirkinge opgevraog veur XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 haet gebroekers opgevraog veur XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 haet bewirkinge opgevraog veur <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 haet gebroekers opgevraog veur <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 haet bewirkinge opgevraog veur XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 haet gebroekers opgevraog veur XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 haet bewirkinge opgevraog veur $2",
"checkuser-autocreate-action": "is autematisch aangemaak",
"checkuser-create-action": "is aangemaak",
diff --git a/CheckUser/i18n/lld.json b/CheckUser/i18n/lld.json
new file mode 100644
index 00000000..29562f22
--- /dev/null
+++ b/CheckUser/i18n/lld.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Starladin"
+ ]
+ },
+ "checkuser-investigate-notice-no-results": "Degügn resultac.",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status"
+}
diff --git a/CheckUser/i18n/lt.json b/CheckUser/i18n/lt.json
index 1b080218..c4dab124 100644
--- a/CheckUser/i18n/lt.json
+++ b/CheckUser/i18n/lt.json
@@ -51,7 +51,6 @@
"checkuser-block-limit": "Pasirinkta per daug naudotojų.",
"checkuser-block-noreason": "Jūs turite nurodyti blokavimų priežastį.",
"checkuser-noreason": "Šiai užklausai turite pateikti priežastį.",
- "checkuser-accounts": "$1 nauja {{PLURAL:$1|paskyra|paskyros}}",
"checkuser-too-many": "Per daug rezultatų, susiaurinkite CIDR.\nČia pateikiami naudojami IP adresai (daugiausiai 5000, suskirstyti pagal adresus):",
"checkuser-user-nonexistent": "Nurodytas naudotojas neegzistuoja.",
"checkuser-search": "Ieškoti",
@@ -62,23 +61,11 @@
"checkuser-log-search-type": "Ieškoti pagal:",
"checkuser-ipeditcount": "~$1 iš visų vartotojų",
"checkuser-log-entry-userips": "$3, $1 gauti $2 IP adresai",
- "checkuser-log-entry-ipedits": "$3, $1 gavo $2 keitimus",
- "checkuser-log-entry-ipusers": "$3, $1 gavo $2 vartotojus",
+ "checkuser-log-entry-ipedits": "$3, $1 gavo <bdi>$2</bdi> keitimus",
+ "checkuser-log-entry-ipusers": "$3, $1 gavo <bdi>$2</bdi> vartotojus",
"checkuser-autocreate-action": "buvo automatiškai sukurtas",
"checkuser-create-action": "buvo sukurta",
"checkuser-email-action": "siųsti el. laišką naudotojui \"$1\"",
"checkuser-reset-action": "iš naujo nustatyti slaptažodį naudotojui \"$1\"",
- "checkuser-token-fail": "Sesijos klaida. Prašome bandyti dar kartą.",
- "apihelp-query+checkuser-description": "Patikrinti kokie IP adresai yra naudojami pateikto vartotojo vardo arba kokie vartotojų vardai yra naudojami pateikto IP adreso.",
- "apihelp-query+checkuser-param-reason": "Tikrinimo priežastis.",
- "apihelp-query+checkuser-param-limit": "Eilučių limitas.",
- "apihelp-query+checkuser-example-1": "Patikrinti [[User:Example]] IP adresus",
- "apihelp-query+checkuser-example-2": "Patikrinti 192.0.2.0/24 keitimus",
- "apihelp-query+checkuserlog-description": "Gauti įrašus iš CheckUser žurnalo.",
- "apihelp-query+checkuserlog-param-user": "CheckUser vartotojo vardas.",
- "apihelp-query+checkuserlog-param-limit": "Eilučių limitas.",
- "apihelp-query+checkuserlog-example-1": "Rodyti [[User:Example]] patikrinimus",
- "apihelp-query+checkuserlog-example-2": "Rodyti 192.0.2.0/24 patikrinimus, po 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Privalote nurodyti tikrinimo priežastį.",
- "apierror-checkuser-invalidmode": "Negalimas prašymo režimas"
+ "checkuser-token-fail": "Sesijos klaida. Prašome bandyti dar kartą."
}
diff --git a/CheckUser/i18n/lv.json b/CheckUser/i18n/lv.json
index 7f1af626..955eaa09 100644
--- a/CheckUser/i18n/lv.json
+++ b/CheckUser/i18n/lv.json
@@ -4,10 +4,10 @@
"Geimeris",
"GreenZeb",
"Papuass",
+ "Silraks",
"Xil",
"Yyy",
- "Zuiks",
- "Silraks"
+ "Zuiks"
]
},
"checkuser-desc": "Atļauj lietotājiem ar attiecīgām pilnvarām pārbaudīt lietotāja IP adresi un citu informāciju.",
@@ -40,11 +40,16 @@
"checkuser-block-failure": "\"' Neviens lietotājs netika bloķēts.\" \"",
"checkuser-block-limit": "Izvēlēti pārāk daudzi lietotāji.",
"checkuser-block-noreason": "Jums jānorāda bloķēšanas iemesli.",
- "checkuser-accounts": "$1 {{PLURAL:$1|jauni konti|jauns konts|jauni konti}}",
"checkuser-search": "Meklēt",
"checkuser-search-submit": "Meklēt",
"checkuser-search-initiator": "iniciators",
"checkuser-log-search-target": "Mērķis:",
"checkuser-log-search-type": "Meklēt pēc:",
- "checkuser-email-action": "aizsūtīt ziņu uz lietotāja \"$1\" e-pastu"
+ "checkuser-email-action": "aizsūtīt ziņu uz lietotāja \"$1\" e-pastu",
+ "checkuser-investigate-tab-compare": "Salīdzināt",
+ "checkuser-investigate-reason-label": "Iemesls",
+ "checkuser-investigate-preliminary-table-header-blocked": "Statuss",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|labojumi|labojums|labojumi}}]</b>",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Lietotāja aģents"
}
diff --git a/CheckUser/i18n/lzh.json b/CheckUser/i18n/lzh.json
index 83987945..181f718b 100644
--- a/CheckUser/i18n/lzh.json
+++ b/CheckUser/i18n/lzh.json
@@ -2,8 +2,8 @@
"@metadata": {
"authors": [
"LNDDYL",
- "逆襲的天邪鬼",
- "WAN233"
+ "WAN233",
+ "逆襲的天邪鬼"
]
},
"group-checkuser": "知簿",
diff --git a/CheckUser/i18n/mai.json b/CheckUser/i18n/mai.json
index 960a9bf8..74f4a969 100644
--- a/CheckUser/i18n/mai.json
+++ b/CheckUser/i18n/mai.json
@@ -1,8 +1,8 @@
{
"@metadata": {
"authors": [
- "बिप्लब आनन्द",
- "Tulsi Bhagat"
+ "Tulsi Bhagat",
+ "बिप्लब आनन्द"
]
},
"checkuser": "प्रयोक्ता जाँच",
@@ -19,7 +19,7 @@
"checkuser-reason": "कारण:",
"checkuser-reason-api": "ए॰पी॰आई: $1",
"checkuser-showlog": "प्रयोगकर्ताजाँच लगक लेल जाए",
- "checkuser-query": "सन्निकट में भेल परिवर्त्तन खोजु",
+ "checkuser-query": "सन्निकटमे भेल परिवर्तन ताकी",
"checkuser-target": "आई॰पी॰ पता वा प्रयोक्तानाम:",
"checkuser-users": "प्रयोक्ता ताकी",
"checkuser-edits": "सम्पादन खोजु",
@@ -53,6 +53,5 @@
"checkuser-ipeditcount": "~$1 सभ प्रयोक्ता सs",
"checkuser-autocreate-action": "स्वचालित रूप से निर्माण करल गेल",
"checkuser-create-action": "निर्माण करल गेल",
- "checkuser-email-action": "प्रयोक्ता \"$1\" के ई-पत्र भेजल गेल",
- "apihelp-query+checkuser-param-reason": "जाँच करे के कारण"
+ "checkuser-email-action": "प्रयोक्ता \"$1\" के ई-पत्र भेजल गेल"
}
diff --git a/CheckUser/i18n/mk.json b/CheckUser/i18n/mk.json
index 56c27ee3..aa8a6b6b 100644
--- a/CheckUser/i18n/mk.json
+++ b/CheckUser/i18n/mk.json
@@ -3,8 +3,9 @@
"authors": [
"Bjankuloski06",
"Brest",
+ "McDutchie",
"Misos",
- "McDutchie"
+ "Vlad5250"
]
},
"checkuser-summary": "Оваа алатка врши преглед на скорешни промени за да ги добие IP-адресите користени од некој корисник или да ги прикаже податоците за уредувања/корисници за некоја IP-адреса.\nКорисниците и уредувањата од клиентска IP-адреса можат да се добијат преку XFF наслови со додавање на „/xff“ на IP-адресата. Поддржани се IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128).\nЌе се прикажат највеќе до 5000 уредувања од функционални причини.\nКористете го ова во согласност со правилата.",
@@ -14,15 +15,15 @@
"checkuserlog": "Дневник на проверки",
"checkuser-contribs": "провери IP-адреси на корисникот",
"checkuser-contribs-log": "скорешни проверки",
- "group-checkuser": "Проверувачи на корисници",
- "group-checkuser-member": "{{GENDER:$1|проверувач на корисници}}",
+ "group-checkuser": "Проверувачи",
+ "group-checkuser-member": "{{GENDER:$1|проверувач}}",
"right-checkuser": "Проверување на корисничка IP-адреса и други информации",
"right-checkuser-log": "Гледање дневник на проверување на корисник",
"action-checkuser": "проверување на корисничка IP-адреса и други информации",
"action-checkuser-log": "гледање дневник на проверување на корисник",
- "grouppage-checkuser": "{{ns:project}}:Проверувачи на корисници",
+ "grouppage-checkuser": "{{ns:project}}:Проверувачи",
"checkuser-reason": "Причина:",
- "checkuser-reason-api": "Извршник: $1",
+ "checkuser-reason-api": "API: $1",
"checkuser-showlog": "Префрли на дневникот на проверки",
"checkuser-query": "Побарај скорешни промени",
"checkuser-target": "IP-адреса или корисничко име:",
@@ -50,11 +51,12 @@
"checkuser-wasblocked": "Претходно блокиран",
"checkuser-localonly": "Необединета",
"checkuser-massblock": "Блокирај ги избраните корисници",
- "checkuser-massblock-text": "Избраните сметки ќе бидат трајно блокирани, со овозможено автоблокирање и оневозможено создавање на сметки.\nIP-адресите ќе бидат блокирани 1 недела за само за корисници со IP-адреса, и со оневозможено создавање на сметка.",
+ "checkuser-massblock-text": "Избраните сметки ќе бидат трајно блокирани, со овозможено автоблокирање на IP-адреси и оневозможено создавање на сметки.\nIP-адресите ќе бидат блокирани една недела за само за анонимни корисници, и со оневозможено создавање на сметка.",
"checkuser-blockemail": "Оневозможи испраќање е-пошта",
"checkuser-blocktalk": "Спречи уредување своја разговорна страница додека е блокиран",
"checkuser-blocktag": "Замени ги корисничките страници со:",
"checkuser-blocktag-talk": "Замени ги разговорните страници со:",
+ "checkuser-reblock": "Презапис врз постоечки блокови",
"checkuser-massblock-commit": "Блокирај ги избраните корисници",
"checkuser-block-success": "'''{{PLURAL:$2|Корисникот|Корисниците}} $1 {{PLURAL:$2|е|се}} {{PLURAL:$2|блокиран|блокирани}}.'''",
"checkuser-block-failure": "'''Никој не е блокиран.'''",
@@ -62,23 +64,22 @@
"checkuser-block-noreason": "Мора да наведете причина за блокирањата.",
"checkuser-centralauth-multilock": "Повеќекратно заклучување на сметки",
"checkuser-noreason": "Мора да наведете причина за ова барање.",
- "checkuser-accounts": "$1 {{PLURAL:$1|нова сметка|нови сметки}}",
- "checkuser-too-many": "Премногу ставки (според процената на барањето). Уточнете го CIDR.\nЕве ги користените IP-адреси (највеќе 5000, подредени по адреса):",
+ "checkuser-too-many": "Премногу ставки (според процената на барањето). Уточнете го CIDR.\nЕве ги користените IP-адреси (највеќе $1, подредени по адреса):",
"checkuser-user-nonexistent": "Наведениот корисник не постои.",
"checkuser-search": "Пребарај по ставките од дневникот на проверки",
"checkuser-search-submit": "Пребарај",
- "checkuser-search-initiator": "иницијатор",
+ "checkuser-search-initiator": "покренувач",
"checkuser-search-target": "цел",
"checkuser-log-search-target": "Цел:",
"checkuser-log-search-type": "Пребарај по:",
"checkuser-ipeditcount": "~$1 од сите корисници",
"checkuser-showmain": "Префрли ме на главниот образец за проверување корисници",
"checkuser-limited": "'''Исходов е скратен од делотворрни причини.'''",
- "checkuser-log-entry-userips": "$3, $1 доби IP-адреси за за $2",
- "checkuser-log-entry-ipedits": "$3, $1 доби уредувања за $2",
- "checkuser-log-entry-ipusers": "$3, $1 доби корисници за $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 доби уредувања за XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 доби корисници за XFF $2",
+ "checkuser-log-entry-userips": "$3, $1 доби IP-адреси за $2",
+ "checkuser-log-entry-ipedits": "$3, $1 доби уредувања за <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 доби корисници за <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 доби уредувања за XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 доби корисници за XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 доби уредувања за $2",
"checkuser-autocreate-action": "беше автоматски создадена",
"checkuser-create-action": "е создаден",
@@ -87,28 +88,96 @@
"checkuser-token-fail": "Седницата не успеа. Обидете се повторно.",
"checkuser-login-failure": "Не успеав да ве најавам на {{SITENAME}} како $1",
"checkuser-login-success": "Успешно ве најавив на {{SITENAME}} како $1",
- "group-checkuser.css": "/* Тука поставениот CSS ќе се применува само врз проверувачи на корисници */",
- "group-checkuser.js": "/* Тука поставениот JS ќе се применува само врз проверувачи на корисници */",
- "apihelp-query+checkuser-description": "Провери кои IP-адреси ги користи дадено корисничко име или пак кои кориснички имиња ги користи дадена IP-адреса.",
- "apihelp-query+checkuser-summary": "Провери кои IP-адреси ги користи дадено корисничко име или пак кои кориснички имиња ги користи дадена IP-адреса.",
- "apihelp-query+checkuser-param-request": "Тип на барање со CheckUser:\n;userips: Дај IP-адреса на целен корисник.\n;edits: Дај промени од целна IP-адреса или опсег.\n;ipusers: Дај корисници од целна IP-адреса или опсег.",
- "apihelp-query+checkuser-param-target": "Корисничко име, IP-адреса или CIDR-опсег за проверка.",
- "apihelp-query+checkuser-param-reason": "Причина за проверката.",
- "apihelp-query+checkuser-param-limit": "Ограничување на редовите.",
- "apihelp-query+checkuser-param-timecond": "Временско ограничување за корисничките податоци (како на пр. „-2 weeks“ или „2 weeks ago“).",
- "apihelp-query+checkuser-param-xff": "Користи XFF-податоци наместо IP-адреса.",
- "apihelp-query+checkuser-example-1": "Провери го [[User:Example]] по IP-адресите",
- "apihelp-query+checkuser-example-2": "Провери ги уредувањата од 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Дај ставки од записникот на CheckUser.",
- "apihelp-query+checkuserlog-summary": "Дај ставки од записникот на CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Кориснилчко име на проверувачот (CheckUser).",
- "apihelp-query+checkuserlog-param-target": "Проверен корисник, IP-адреса или CIDR-опсег.",
- "apihelp-query+checkuserlog-param-limit": "Ограничување на редовите.",
- "apihelp-query+checkuserlog-param-from": "Од кој датум и време да почне набројувањето.",
- "apihelp-query+checkuserlog-param-to": "На кој датум и време да запре набројувањето.",
- "apihelp-query+checkuserlog-example-1": "Прикажи проверки на [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Прикажи проверки на 192.0.2.0/24 по 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Мора да зададете причина за проверка.",
- "apierror-checkuser-timelimit": "Ќе треба да употребите исправно временско ограничување (на пр. „-2 weeks“ „2 weeks ago“).",
- "apierror-checkuser-invalidmode": "Неважечки режим на побарување"
+ "group-checkuser.css": "/* Тука поставениот CSS ќе се применува само врз проверувачи */",
+ "group-checkuser.js": "/* Тука поставениот JS ќе се применува само врз проверувачи */",
+ "checkuser-link-investigate-label": "Пробајте ја новата алатка „Проверка на корисници“",
+ "checkuser-investigateblock": "Блокирај корисници",
+ "checkuser-investigateblock-target": "Кориснички имиња и IP-адреси",
+ "checkuser-investigateblock-actions": "Дејства за блокирање",
+ "checkuser-investigateblock-reason": "Причина",
+ "checkuser-investigateblock-options": "Дополнителни можности",
+ "checkuser-investigateblock-email-label": "Оневозможи испраќање е-пошта",
+ "checkuser-investigateblock-usertalk-label": "Спречи уредување своја разговорна страница додека е блокиран",
+ "checkuser-investigateblock-reblock-label": "Презапис врз постоечки блокови",
+ "checkuser-investigateblock-notice-user-page-label": "Испрати напомена на корисничката страница",
+ "checkuser-investigateblock-notice-talk-page-label": "Испрати напомена на разговорната страница на корисникот",
+ "checkuser-investigateblock-notice-position-label": "Положба",
+ "checkuser-investigateblock-notice-text-label": "Викитекст",
+ "checkuser-investigateblock-notice-append": "Природај на крајот од страницата",
+ "checkuser-investigateblock-notice-prepend": "Придодај на почетокот од страницата",
+ "checkuser-investigateblock-notice-replace": "Замени страница",
+ "checkuser-investigateblock-failure": "Не е блокиран ниеден корисник. За да замените постоечки блокови, стиснете го штикларникот „{{int:checkuser-investigateblock-reblock-label}}“. Блокот нема да се замени ако новиот е истоветен на постоечкиот.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|Корисникот|Корисниците}} $1 сега {{PLURAL:$2|е|се}} {{PLURAL:$2|блокиран|блокирани}}.",
+ "checkuser-investigateblock-notices-failed": "Некои напомени не можеа да се додадат кон корисничките или разговорните страници.",
+ "checkuser-investigate-log": "Дневници на иследувања",
+ "checkuser-investigate-log-entry": "$3, $1 побара информации за <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Нема ставки во дневникот на иследувања",
+ "checkuser-investigate-log-subtitle": "Префрли се на иследувачкиот образец",
+ "checkuser-investigate": "Иследи",
+ "checkuser-investigate-page-subtitle": "Тековно иследување на $1",
+ "checkuser-investigate-subtitle-block-button-label": "Блокирај",
+ "checkuser-investigate-subtitle-cancel-button-label": "Откажи",
+ "checkuser-investigate-subtitle-continue-button-label": "Продолжи",
+ "checkuser-investigate-indicator-new-investigation": "Ново иследување",
+ "checkuser-investigate-indicator-logs": "Дневници",
+ "checkuser-investigate-legend": "Пребсрајте кориснички имиња, IP-адреси или IP-опсези",
+ "checkuser-investigate-notice-no-results": "Не пронајдов ништо.",
+ "checkuser-investigate-tab-preliminary-check": "Информации за сметката",
+ "checkuser-investigate-tab-compare": "IP-адреса и кориснички застапници",
+ "checkuser-investigate-tab-timeline": "Времеслед",
+ "checkuser-investigate-targets-label": "Кориснички имиња и IP-адреси",
+ "checkuser-investigate-targets-placeholder": "Корисничко име или 1.1.1.1",
+ "checkuser-investigate-duration-label": "Траење",
+ "checkuser-investigate-duration-option-all": "Сите",
+ "checkuser-investigate-duration-option-1w": "Минатата седмица",
+ "checkuser-investigate-duration-option-2w": "Минатите две седмици",
+ "checkuser-investigate-duration-option-30d": "Последниве 30 дена",
+ "checkuser-investigate-reason-label": "Причина",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Јазичето за информации за сметка не вклучува никакви информации за IP-адреси. Тие поединости можете да ги погледате на <span class=\"plainlinks\">[$1 јазичето за IP-адреси и кориснички застапници]</span>.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Блокиран",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|уредување|уредувања}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Неблокиран",
+ "checkuser-investigate-preliminary-table-header-blocked": "Статус",
+ "checkuser-investigate-preliminary-table-header-editcount": "Уредувања",
+ "checkuser-investigate-preliminary-table-header-groups": "Групи",
+ "checkuser-investigate-preliminary-table-header-name": "Корисничко име",
+ "checkuser-investigate-preliminary-table-header-registration": "Датум на приложување",
+ "checkuser-investigate-preliminary-table-header-wiki": "Вики",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Викито не е пронајдено",
+ "checkuser-investigate-filters-legend": "Филтри",
+ "checkuser-investigate-filters-exclude-targets-label": "Скриј ги следиве корисници или IP-адреси",
+ "checkuser-investigate-timeline-notice-no-results": "Нема исход: нема заведена активност од овие корисници или IP-адреси во последниве 90 дена",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Нема исход што одговара на филтрираното. Отстранете некои филтри за да го проширите пребарувањето.",
+ "checkuser-investigate-compare-copy-button-label": "Прик. викитекст",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Проверка на застапник",
+ "checkuser-investigate-compare-copy-message-label": "Дали би сакале да ги прекопирате овие информации како викитекстна табела?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Поради технички ограничувања, прикажан е најголемиот можен број на записи. Податоците дадени за следниве цели се непотполни: $1. Обидете се со помалку цели, помал временски опсег или потесни IP-опсези.",
+ "checkuser-investigate-compare-notice-no-results": "Нема исход: нема уредувања од овие корисници или IP-адреси во последниве 90 дена",
+ "checkuser-investigate-compare-notice-no-results-filters": "Нема исход што одговара на филтрираното. Отстранете некои филтри за да го проширите пребарувањето.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Прикажи ги сите IP-адреси на овој корисник",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Прикажи ги сите корисници на оваа IP-адреса",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Додај ја оваа IP-адреса во иследувањето",
+ "checkuser-investigate-compare-table-button-checks-label": "Проверки",
+ "checkuser-investigate-compare-table-button-contribs-label": "Придонеси",
+ "checkuser-investigate-compare-table-button-filter-label": "Филтрирај од исходот",
+ "checkuser-investigate-compare-table-cell-unregistered": "Незачленети",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|уредување|уредувања}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 од сите корисници)</i>",
+ "checkuser-investigate-compare-table-header-username": "Корисничко име",
+ "checkuser-investigate-compare-table-header-activity": "Датумски опсег",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Кориснички застапник",
+ "checkuser-investigate-subtitle-link-restart-tour": "Пушти го водичот одново",
+ "checkuser-investigate-tour-targets-title": "Да проверуваме повеќе корисници и IP-адреси?",
+ "checkuser-investigate-tour-targets-desc": "Додајте до $1 {{PLURAL:$1|корисничко име или IP-адреса|кориснички имиња или IP-адреси}} и добијте ги сите информации на едно место. Не грижете се, ќе направиме посебен проверувачки дневник за секое од нив.",
+ "checkuser-investigate-tour-useragents-title": "Се совпаѓаат корисничките застапници?",
+ "checkuser-investigate-tour-useragents-desc": "Одете со стрелката врз ќелија за да ги истакнете сите други редови што имаат слични податоци. Стиснете на иглата за да ја задржите истакнатоста додека работите на податоците.",
+ "checkuser-investigate-tour-addusertargets-title": "Ви треба повеќе контекст?",
+ "checkuser-investigate-tour-addusertargets-desc": "Стиснете за да ги видите сите други корисници на таа IP-адреса. Ова може да се направи и за Корисници, и да ги видите сите IP-адреси што ги користеле. Ние автоматски ќе создадеме ставка во дневникот на проверки.",
+ "checkuser-investigate-tour-filterip-title": "Го уточнувате иследувањето?",
+ "checkuser-investigate-tour-filterip-desc": "Расчитете го нередот филтрирајќи кориснички имиња, IP-адреси или кориснички застапници. Сакате да се повратат податоците? Послужете се со управувачницата „Филтри“ погоре за да ги отстраните.",
+ "checkuser-investigate-tour-block-title": "Сакате да блокирате?",
+ "checkuser-investigate-tour-block-desc": "Ви овозможува да ги одберете корисниците што сакате да ги блокирате, и потоа ве одведува на образецот кој ви дава да го изберете соодветниот блок.",
+ "checkuser-investigate-tour-copywikitext-title": "Сакате да ги прекопирате податоците?",
+ "checkuser-investigate-tour-copywikitext-desc": "Прекопирајте ја споредбената табела со еден стисок и пренесете ја на CUWiki. Имајте на ум дека го копирате само она што е видливо, а не сите страници на иследувањето."
}
diff --git a/CheckUser/i18n/ml.json b/CheckUser/i18n/ml.json
index cbeb0745..74c3cdbe 100644
--- a/CheckUser/i18n/ml.json
+++ b/CheckUser/i18n/ml.json
@@ -1,6 +1,7 @@
{
"@metadata": {
"authors": [
+ "Adithyak1997",
"Kiran Gopi",
"Praveenp",
"Shijualex"
@@ -56,7 +57,6 @@
"checkuser-block-limit": "നിരവധി ഉപയോക്താക്കളെ തിരഞ്ഞെടുത്തിരിക്കുന്നു.",
"checkuser-block-noreason": "തടയലിനു ഒരു കാരണം താങ്കൾ നൽകുക.",
"checkuser-noreason": "ഈ ചോദ്യത്തിനു താങ്കൾ നിർബന്ധമായും കാരണം നൽകേണ്ടതാണ്.",
- "checkuser-accounts": "പുതിയ {{PLURAL:$1|അംഗത്വം|$1അംഗത്വങ്ങൾ}}",
"checkuser-too-many": "വളരെയധികം ഫലങ്ങൾ (ലഭിച്ച ക്വറി അനുസരിച്ച്). CIDR ചുരുക്കുക.\nഉപയോഗിച്ച IPകൾ താഴെ പ്രദർശിപ്പിച്ചിരിക്കുന്നു (പരമാവധി 5000, വിലാസം അനുസരിച്ച് ക്രമീകരിച്ചത്):",
"checkuser-user-nonexistent": "ഇങ്ങനൊരു ഉപയോക്താവ് വിക്കിയിൽ നിലവിലില്ല.",
"checkuser-search": "തിരയൂ",
@@ -69,5 +69,7 @@
"checkuser-autocreate-action": "സ്വയം സൃഷ്ടിച്ചതാണ്",
"checkuser-create-action": "സൃഷ്ടിച്ചിരിക്കുന്നു",
"checkuser-email-action": "\"$1\" എന്ന ഉപയോക്താവിന് ഇമെയിൽ അയച്ചുകഴിഞ്ഞു",
- "checkuser-reset-action": "\"$1\" എന്ന ഉപയോക്താവിന്റെ രഹസ്യവാക്ക് പുനഃക്രമീകരിക്കുക"
+ "checkuser-reset-action": "\"$1\" എന്ന ഉപയോക്താവിന്റെ രഹസ്യവാക്ക് പുനഃക്രമീകരിക്കുക",
+ "checkuser-investigate-targets-label": "ഉപയോക്തൃനാമങ്ങളും ഐ.പി വിലാസങ്ങളും",
+ "checkuser-investigate-reason-label": "കാരണം"
}
diff --git a/CheckUser/i18n/mr.json b/CheckUser/i18n/mr.json
index f4ea878c..3fb4be43 100644
--- a/CheckUser/i18n/mr.json
+++ b/CheckUser/i18n/mr.json
@@ -4,8 +4,8 @@
"Htt",
"Kaustubh",
"Mahitgar",
- "V.narsikar",
- "McDutchie"
+ "McDutchie",
+ "V.narsikar"
]
},
"checkuser-summary": "हे उपकरण अलीकडील बदलांमधून एखाद्या सदस्याने वापरलेले अंकपत्ते किंवा एखाद्या अंकपत्त्याची संपादने/सदस्य दाखविते.\nक्लायंट अंकपत्त्यावरील सदस्य अथवा संपादने पाहण्यासाठी अंकपत्त्यानंतर \"/xff\" द्यावे लागेल.\nIPv4 (CIDR $1-32) आणि IPv6 (CIDR $2-128) वापरता येऊ शकेल.\nएका वेळी ५००० पेक्षा जास्त संपादने दाखविली जाणार नाहीत. हे उपकरण पॉलिसीच्या नियमांना धरून वापरावे.",
@@ -58,7 +58,6 @@
"checkuser-block-limit": "खूपच सदस्य निवडल्या गेलेत.",
"checkuser-block-noreason": "प्रतिबंधनासाठी आपण कारण द्यावयास हवे.",
"checkuser-noreason": "या पृच्छेस आपण कारण द्यावयास हवे.",
- "checkuser-accounts": "$1 नविन {{PLURAL:$1|खाते|खाती}}",
"checkuser-too-many": "(पृच्छा अनुमानापेक्षा) खूप निकाल आलेले आहेत, कृपया शोधशब्दांमध्ये योग्य बदल करा. खाली, वापरलेल्या अंकपत्त्यांची यादी आहे (जास्तीत जास्त ५०००, पत्यानूसार विल्हेवारीत):",
"checkuser-user-nonexistent": "हे सदस्यनाम अस्तित्त्वात नाही.",
"checkuser-search": "सदस्य तपास नोंदी शोधा",
@@ -71,18 +70,12 @@
"checkuser-showmain": "सदस्यतपासच्या मुख्य अर्जाकडे परत जा",
"checkuser-limited": "'''उत्तम कामगिरी देण्यासाठीच्या कारणास्तव, निकालात काटछाट करण्यात आली आहे.'''",
"checkuser-log-entry-userips": "$3,$1ने $2साठी अंकपत्ते मिळविले",
- "checkuser-log-entry-ipedits": "$3,$1ने $2साठी संपादने मिळविली",
- "checkuser-log-entry-ipusers": "$3,$1ने $2साठी सदस्य मिळविले",
+ "checkuser-log-entry-ipedits": "$3,$1ने <bdi>$2</bdi>साठी संपादने मिळविली",
+ "checkuser-log-entry-ipusers": "$3,$1ने <bdi>$2</bdi>साठी सदस्य मिळविले",
"checkuser-log-entry-useredits": "$3,$1ने $2साठी संपादने मिळविली",
"checkuser-autocreate-action": "आपोआप निर्माण केल्या गेले",
"checkuser-create-action": "निर्माण केल्या गेले",
"checkuser-email-action": "\"$1\"ला विपत्र पाठविले",
"checkuser-reset-action": "सदस्य $1चा परवलीचा शब्द पुनर्स्थापित करा",
- "checkuser-token-fail": "सत्र अयशस्वी.कृपया पुन्हा प्रयत्न करा.",
- "apihelp-query+checkuser-description": "दिलेले सदस्यनाव कोणते अंकपत्ते वापरते किंवा दिलेल्या अंकपत्त्याद्वारे कोणती सदस्यनावे वापरल्या जातात ते तपासा.",
- "apihelp-query+checkuser-param-target": "तपासावयाचे सदस्यनाव, अंकपत्ता किंवा सीआयडीआर रेंज.",
- "apihelp-query+checkuser-param-reason": "तपासण्याचे कारण.",
- "apihelp-query+checkuser-param-limit": "ओळींची मर्यादा.",
- "apihelp-query+checkuser-param-timecond": "सदस्यडाटाची काल मर्यादा(जसे \"-2 weeks\" किंवा \"2 weeks ago\").",
- "apihelp-query+checkuserlog-param-limit": "ओळींची मर्यादा."
+ "checkuser-token-fail": "सत्र अयशस्वी.कृपया पुन्हा प्रयत्न करा."
}
diff --git a/CheckUser/i18n/mrh.json b/CheckUser/i18n/mrh.json
new file mode 100644
index 00000000..9679c6f1
--- /dev/null
+++ b/CheckUser/i18n/mrh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Teitei Para"
+ ]
+ },
+ "checkuser-too-many": "Too many results (according to query estimate), please narrow down the CIDR.\nHere are the IP addresses used ($1 max, sorted by address):"
+}
diff --git a/CheckUser/i18n/ms.json b/CheckUser/i18n/ms.json
index f71a1e5d..e765b8e4 100644
--- a/CheckUser/i18n/ms.json
+++ b/CheckUser/i18n/ms.json
@@ -4,7 +4,8 @@
"Anakmalaysia",
"Aviator",
"Izzudin",
- "Kurniasan"
+ "Kurniasan",
+ "Tofeiku"
]
},
"checkuser-summary": "Alat ini mengimbas senarai perubahan terkini untuk mendapatkan senarai IP yang digunakan oleh seseorang pengguna atau memaparkan data sunting/pengguna bagi sesebuah IP. Pengguna dan suntingan oleh sesebuah IP boleh didapatkan melalui pengatas XFF dengan menambah \\\"/xff\\\" selepas IP tersebut. Kedua-dua format IPv4 (CIDR $1-32) dan IPv6 (CIDR $2-128) disokong. Atas sebab-sebab prestasi, pulangan dihadkan kepada 5000 buah suntingan sahaja. Sila patuhi dasar yang telah ditetapkan.",
@@ -57,7 +58,6 @@
"checkuser-block-limit": "Terlalu banyak pengguna dipilih.",
"checkuser-block-noreason": "Anda hendaklah memberikan sebab sekatan.",
"checkuser-noreason": "Anda hendaklah memberikan sebab bagi pertanyaan ini.",
- "checkuser-accounts": "$1 akaun baru",
"checkuser-too-many": "Terlalu banyak keputusan (berdasarkan anggaran pertanyaan); sila kecilkan CIDR. Yang berikut ialah senarai IP yang digunakan (had 5000, diisihkan mengikut alamat):",
"checkuser-user-nonexistent": "Pengguna yang dinyatakan tidak wujud.",
"checkuser-search": "Cari",
@@ -71,7 +71,11 @@
"checkuser-create-action": "telah dicipta",
"checkuser-email-action": "hantar e-mel kepada \"$1\"",
"checkuser-reset-action": "set semula kata laluan \"$1\"",
- "apihelp-query+checkuser-param-target": "Nama pengguna, alamat IP atau 'CIDR range' untuk disemak.",
- "apihelp-query+checkuser-param-xff": "Gunakan data XFF daripada alamat IP.",
- "apihelp-query+checkuser-example-1": "Semak alamat IP untuk [[User:Example]]"
+ "checkuser-investigate-tab-preliminary-check": "Maklumat akaun",
+ "checkuser-investigate-duration-label": "Tempoh",
+ "checkuser-investigate-duration-option-all": "Semua",
+ "checkuser-investigate-duration-option-1w": "Minggu lepas",
+ "checkuser-investigate-duration-option-2w": "2 minggu lepas",
+ "checkuser-investigate-duration-option-30d": "30 hari lepas",
+ "checkuser-investigate-compare-copy-button-label": "Tunjuk wikiteks"
}
diff --git a/CheckUser/i18n/mt.json b/CheckUser/i18n/mt.json
index b86cbfc0..e882b22d 100644
--- a/CheckUser/i18n/mt.json
+++ b/CheckUser/i18n/mt.json
@@ -2,6 +2,7 @@
"@metadata": {
"authors": [
"Chrisportelli",
+ "ToniSant",
"පසිඳු කාවින්ද"
]
},
@@ -55,7 +56,6 @@
"checkuser-block-limit": "Ġew magħżulta ħafna utenti.",
"checkuser-block-noreason": "Trid tagħti raġuni għall-imblukkar.",
"checkuser-noreason": "Trid tagħti raġuni għal din it-tfittxija.",
- "checkuser-accounts": "{{PLURAL:$1|kont ġdid|$1 kontijiet ġodda}}",
"checkuser-user-nonexistent": "L-utent speċifikat ma jeżistix.",
"checkuser-search": "Fittex",
"checkuser-search-submit": "Fittex",
@@ -67,5 +67,8 @@
"checkuser-autocreate-action": "ġie maħluq awtomatikament",
"checkuser-create-action": "ġie maħluq",
"checkuser-email-action": "bagħat ittra-e lill-utent \"$1\"",
- "checkuser-reset-action": "irrisettja l-password għall-utent \"$1\""
+ "checkuser-reset-action": "irrisettja l-password għall-utent \"$1\"",
+ "checkuser-investigateblock-reason": "Raġuni",
+ "checkuser-investigate-duration-option-30d": "L-aħħar 30 jum",
+ "checkuser-investigate-reason-label": "Raġuni"
}
diff --git a/CheckUser/i18n/my.json b/CheckUser/i18n/my.json
index 00672dfa..be0b33ae 100644
--- a/CheckUser/i18n/my.json
+++ b/CheckUser/i18n/my.json
@@ -1,7 +1,9 @@
{
"@metadata": {
"authors": [
- "Ninjastrikers"
+ "Dr Lotus Black",
+ "Ninjastrikers",
+ "Teitei Para"
]
},
"checkuser": "စုံစမ်းစစ်ဆေးသူ",
@@ -29,5 +31,10 @@
"checkuser-check": "စုံစမ်းစစ်ဆေးရန်",
"checkuser-check-this-user": "ဤအသုံးပြုသူအား စုံစမ်းစစ်ဆေးရန်",
"checkuser-recent-checks": "ဤအသုံးပြုသူအတွက် မကြာသေးမီက စုံစမ်းစစ်ဆေးမှုများ",
- "checkuser-search-submit": "ရှာဖွေရန်"
+ "checkuser-search-submit": "ရှာဖွေရန်",
+ "checkuser-investigateblock": "အသုံးပြုသူများကို ပိတ်ပင်ရန်",
+ "checkuser-investigateblock-reason": "အကြောင်းပြချက်",
+ "checkuser-investigateblock-email-label": "အီးမေးလ်ပို့ခြင်းကို တားဆီးရန်",
+ "checkuser-investigate-notice-no-results": "ရလဒ်များ မရှိပါ။",
+ "checkuser-investigate-preliminary-table-header-blocked": "အခြေအနေ"
}
diff --git a/CheckUser/i18n/nah.json b/CheckUser/i18n/nah.json
index 9744e7e5..9bc19b99 100644
--- a/CheckUser/i18n/nah.json
+++ b/CheckUser/i18n/nah.json
@@ -1,9 +1,9 @@
{
"@metadata": {
"authors": [
+ "Akapochtli",
"Fluence",
- "Teòtlalili",
- "Akapochtli"
+ "Teòtlalili"
]
},
"checkuser-reason": "Īxtlamatiliztli:",
diff --git a/CheckUser/i18n/nap.json b/CheckUser/i18n/nap.json
index 235bea49..2588419c 100644
--- a/CheckUser/i18n/nap.json
+++ b/CheckUser/i18n/nap.json
@@ -1,4 +1,8 @@
{
- "@metadata": [],
- "checkuser-search": "Truova"
+ "@metadata": {
+ "authors": [
+ "Ruthven"
+ ]
+ },
+ "checkuser-search": "Ascia"
}
diff --git a/CheckUser/i18n/nb.json b/CheckUser/i18n/nb.json
index f7b47738..e23a0e85 100644
--- a/CheckUser/i18n/nb.json
+++ b/CheckUser/i18n/nb.json
@@ -4,10 +4,10 @@
"Audun",
"Danmichaelo",
"Finnrind",
- "Laaknor",
- "Nghtwlkr",
"Jon Harald Søby",
- "McDutchie"
+ "Laaknor",
+ "McDutchie",
+ "Nghtwlkr"
]
},
"checkuser-summary": "Dette verktøyet går gjennom siste endringer for å hente IP-ene som er brukt av en bruker, eller viser redigerings- eller brukerinformasjonen for en IP.\n\nBrukere og redigeringer kan hentes med en XFF-IP ved å legge til «/xff» bak IP-en. IPv4 (CIDR $1-32) og IPv6 (CIDR $2-128) støttes.\n\nAv ytelsesgrunner vises maksimalt 5000 redigeringer. Bruk dette verktøyet i samsvar med retningslinjer.",
@@ -58,6 +58,7 @@
"checkuser-blocktalk": "Forhindre fra å redigere deres egen diskusjonsside mens han/hun er blokkert",
"checkuser-blocktag": "Erstatt brukersider med:",
"checkuser-blocktag-talk": "Erstatt diskusjonssider med:",
+ "checkuser-reblock": "Overstyr eksisterende blokkeringer",
"checkuser-massblock-commit": "Blokker valgte brukere",
"checkuser-block-success": "'''{{PLURAL:$2|Brukeren|Brukerne}} $1 er nå blokkert.'''",
"checkuser-block-failure": "'''Ingen brukere blokkert.'''",
@@ -65,8 +66,7 @@
"checkuser-block-noreason": "Du må oppgi en blokkeringsgrunn.",
"checkuser-centralauth-multilock": "Lås flere valgte kontoer",
"checkuser-noreason": "Du må oppgi en grunn for denne spørringen.",
- "checkuser-accounts": "$1 {{PLURAL:$1|ny konto|nye kontoer}}",
- "checkuser-too-many": "For mange resultater (ifølge overslag for spørringen), vennligst innskrenk CIDR.\nHer er de brukte IP-ene (maks 5000, sortert etter adresse):",
+ "checkuser-too-many": "For mange resultater (ifølge overslag for spørringen), vennligst innskrenk CIDR.\nHer er de brukte IP-ene (maks $1, sortert etter adresse):",
"checkuser-user-nonexistent": "Det gitte brukernavnet finnes ikke.",
"checkuser-search": "Søk i IP-kontroll-loggoppføringer",
"checkuser-search-submit": "Søk",
@@ -78,10 +78,10 @@
"checkuser-showmain": "Gå til hovedskjemaet for CheckUser",
"checkuser-limited": "'''Disse resultatene har blitt avkortet av ytelsesgrunner.'''",
"checkuser-log-entry-userips": "$3, $1 hentet IP-adresser for $2",
- "checkuser-log-entry-ipedits": "$3, $1 hentet redigeringer for $2",
- "checkuser-log-entry-ipusers": "$3, $1 hentet brukere for $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 hentet redigeringer for XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 hentet brukere for XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 hentet redigeringer for <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 hentet brukere for <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 hentet redigeringer for XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 hentet brukere for XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 hentet redigeringer for $2",
"checkuser-autocreate-action": "ble automatisk opprettet",
"checkuser-create-action": "ble opprettet",
@@ -90,26 +90,96 @@
"checkuser-token-fail": "Øktfeil. Prøv igjen.",
"checkuser-login-failure": "Kunne ikke logge inn på {{SITENAME}} som $1",
"checkuser-login-success": "Logget inn på {{SITENAME}} som $1",
- "apihelp-query+checkuser-description": "Sjekk hvilke IP-adresser som er brukt av et gitt brukernavn eller hvilke brukernavn som brukes av en gitt IP-adresse.",
- "apihelp-query+checkuser-summary": "Sjekk hvilke IP-adresser som brukes av et gitt brukernavn eller hvilke brukernavn som brukes av ei gitt IP-adresse.",
- "apihelp-query+checkuser-param-request": "Type IP-kontrollforespørsel:\n;userips:Hent IP-adresse for målbrukeren.\n;edits:Hent endringer fra mål-IP-en.\n;ipusers:Hent brukere fra mål-IP-en.",
- "apihelp-query+checkuser-param-target": "Brukernavn, IP-adresse eller CIDR-område å sjekke.",
- "apihelp-query+checkuser-param-reason": "Årsak for kontrollen.",
- "apihelp-query+checkuser-param-limit": "Begrensning av rader.",
- "apihelp-query+checkuser-param-timecond": "Tidsgrense for brukerdata (som «-2 weeks» eller «2 weeks ago»).",
- "apihelp-query+checkuser-param-xff": "Bruk XFF-data i stedet for IP-adresse.",
- "apihelp-query+checkuser-example-1": "Sjekk IP-adresser for [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Sjekk redigeringer fra 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Hent oppføringer fra IP-kontroll-loggen.",
- "apihelp-query+checkuserlog-summary": "Hent oppføringer fra IP-kontroll-loggen.",
- "apihelp-query+checkuserlog-param-user": "Brukernavnet til IP-kontrolløren.",
- "apihelp-query+checkuserlog-param-target": "Sjekket bruker, IP-adresse eller CIDR-område.",
- "apihelp-query+checkuserlog-param-limit": "Begrensning av rader.",
- "apihelp-query+checkuserlog-param-from": "Tidsstempelet det skal startes fra.",
- "apihelp-query+checkuserlog-param-to": "Tidsstempelet det skal sluttes på.",
- "apihelp-query+checkuserlog-example-1": "Vis sjekker av [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Vis sjekker av 192.0.2.0/24 etter 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Du må angi en årsak for sjekken.",
- "apierror-checkuser-timelimit": "Du må bruke en korrekt tidsgrense (som «-2 weeks» eller «2 weeks ago»).",
- "apierror-checkuser-invalidmode": "Ugyldig forespørselsmodus"
+ "group-checkuser.css": "/* CSS plassert her vil kun gjelde IP-kontrollører */",
+ "group-checkuser.js": "/* JavaScript plassert her vil kun gjelde IP-kontrollører */",
+ "checkuser-link-investigate-label": "Prøv det nye IP-kontrollverktøyet",
+ "checkuser-investigateblock": "Blokker brukere",
+ "checkuser-investigateblock-target": "Brukernavn og IP-adresser",
+ "checkuser-investigateblock-actions": "Handlinger som skal blokkeres",
+ "checkuser-investigateblock-reason": "Årsak",
+ "checkuser-investigateblock-options": "Ekstra alternativer",
+ "checkuser-investigateblock-email-label": "Forhindre fra å sende epost",
+ "checkuser-investigateblock-usertalk-label": "Forhindre fra å redigere deres egen diskusjonsside mens han/hun er blokkert",
+ "checkuser-investigateblock-reblock-label": "Overstyr eksisterende blokkeringer",
+ "checkuser-investigateblock-notice-user-page-label": "Legg igjen en beskjed på brukersiden",
+ "checkuser-investigateblock-notice-talk-page-label": "Legg igjen en beskjed på brukerdiskusjonssiden",
+ "checkuser-investigateblock-notice-position-label": "Posisjon",
+ "checkuser-investigateblock-notice-text-label": "Wikitekst",
+ "checkuser-investigateblock-notice-append": "Legg til i slutten av siden",
+ "checkuser-investigateblock-notice-prepend": "Legg til i begynnelsen av siden",
+ "checkuser-investigateblock-notice-replace": "Erstatt siden",
+ "checkuser-investigateblock-failure": "Ingen brukere ble blokkert. Huk av «{{int:checkuser-investigateblock-reblock-label}}» for å overstyre eksisterende blokkeringer. En blokkering blir ikke overstyrt hvis den nye blokkeringen er identisk med den eksisterende.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|Brukeren|Brukerne}} $1 er nå blokkert.",
+ "checkuser-investigateblock-notices-failed": "Noen beskjeder kunne ikke bli lagt til på brukersidene eller brukerdiskusjonssidene.",
+ "checkuser-investigate-log": "Undersøkelseslogger",
+ "checkuser-investigate-log-entry": "$3 undersøkte $1 informasjon for <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Ingen undersøkelsesloggoppføringer funnet.",
+ "checkuser-investigate-log-subtitle": "Bytt til undersøkelsesskjema",
+ "checkuser-investigate": "Undersøk",
+ "checkuser-investigate-page-subtitle": "Pågående undersøkelse for $1",
+ "checkuser-investigate-subtitle-block-button-label": "Blokker",
+ "checkuser-investigate-subtitle-cancel-button-label": "Avbryt",
+ "checkuser-investigate-subtitle-continue-button-label": "Fortsett",
+ "checkuser-investigate-indicator-new-investigation": "Ny undersøkelse",
+ "checkuser-investigate-indicator-logs": "Logger",
+ "checkuser-investigate-legend": "Søk etter brukernavn, IP-adresser eller IP-intervaller",
+ "checkuser-investigate-notice-no-results": "Det er ingen resultater.",
+ "checkuser-investigate-tab-preliminary-check": "Kontoinformasjon",
+ "checkuser-investigate-tab-compare": "IP-er og brukeragenter",
+ "checkuser-investigate-tab-timeline": "Tidslinje",
+ "checkuser-investigate-targets-label": "Brukernavn og IP-adresser",
+ "checkuser-investigate-targets-placeholder": "Brukernavn eller 1.1.1.1",
+ "checkuser-investigate-duration-label": "Varighet",
+ "checkuser-investigate-duration-option-all": "Alle",
+ "checkuser-investigate-duration-option-1w": "Forrige uke",
+ "checkuser-investigate-duration-option-2w": "De siste 2 ukene",
+ "checkuser-investigate-duration-option-30d": "De siste 30 dagene",
+ "checkuser-investigate-reason-label": "Årsak",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Kontoinformasjonsfanen inkluderer ikke informasjon om IP-er. Se fanen <span class=\"plainlinks\">[$1 IP-er og brukeragenter]</span> for disse detaljene.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Blokkert",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|redigering|redigeringer}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Ikke blokkert",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Redigeringer",
+ "checkuser-investigate-preliminary-table-header-groups": "Grupper",
+ "checkuser-investigate-preliminary-table-header-name": "Brukernavn",
+ "checkuser-investigate-preliminary-table-header-registration": "Dato tilknyttet",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki ikke funnet",
+ "checkuser-investigate-filters-legend": "Filtre",
+ "checkuser-investigate-filters-exclude-targets-label": "Skjul følgende brukere eller IP-er",
+ "checkuser-investigate-timeline-notice-no-results": "Det er ingen resultater: det har ikke vært noen aktivitet fra disse brukerne eller IP-ene de siste 90 dagene",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Det er ingen resultater som matcher disse filtreringskriteriene. Prøv å fjerne noen filtre for å utvide søket.",
+ "checkuser-investigate-compare-copy-button-label": "Vis wikitekst",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Proxysjekk",
+ "checkuser-investigate-compare-copy-message-label": "Ønsker du å kopiere denne informasjonen til en wikiteksttabell?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "På grunn av tekniske begrensninger har vi nådd maksimalt antall oppføringer som kan presenteres. Dataene som returneres for følgende mål er ufullstendige: $1. Prøv med færre mål, et mindre tidsvindu eller smalere IP-intervaller.",
+ "checkuser-investigate-compare-notice-no-results": "Det er ingen resultater: det har ikke vært noen redigeringer fra disse brukerne eller IP-adressene de siste 90 dagene",
+ "checkuser-investigate-compare-notice-no-results-filters": "Det er ingen resultater som matcher filterkriteriene. Prøv å fjerne noen filtre for å utvide søket.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Vis alle IP-ene til denne brukeren",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Vis alle brukere på denne IP-en",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Legg til denne IP-en i etterforskningen",
+ "checkuser-investigate-compare-table-button-checks-label": "Sjekker",
+ "checkuser-investigate-compare-table-button-contribs-label": "Bidrag",
+ "checkuser-investigate-compare-table-button-filter-label": "Filtrer fra resultater",
+ "checkuser-investigate-compare-table-cell-unregistered": "Uregistrert",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|redigering|redigeringer}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 fra alle brukere)</i>",
+ "checkuser-investigate-compare-table-header-username": "Brukernavn",
+ "checkuser-investigate-compare-table-header-activity": "Datoområde",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Brukeragent",
+ "checkuser-investigate-subtitle-link-restart-tour": "Begynn omvisningen på nytt",
+ "checkuser-investigate-tour-targets-title": "Sjekke flere brukere og IP-er?",
+ "checkuser-investigate-tour-targets-desc": "Legg til opptil $1 {{PLURAL:$1|brukernavn eller IP|brukernavn eller IP-er}} og få all informasjonen på ett sted. Vi vil opprette en separat brukersjekklogg for hver av dem.",
+ "checkuser-investigate-tour-useragents-title": "Matchende brukeragenter?",
+ "checkuser-investigate-tour-useragents-desc": "Hold over ei celle for å markere alle de andre radene som har samme data. Klikk på nålikonet for å beholde markeringen mens du går gjennom dataene.",
+ "checkuser-investigate-tour-addusertargets-title": "Trenger du mer kontekst?",
+ "checkuser-investigate-tour-addusertargets-desc": "Klikk for å se alle andre brukere på IP-en. Du kan gjøre dette for brukere også for å se hvilke IP-er de har brukt. Vi oppretter automatisk brukersjekkloggoppføringer for deg.",
+ "checkuser-investigate-tour-filterip-title": "Innskrenke etterforskningen?",
+ "checkuser-investigate-tour-filterip-desc": "Fjern rot ved å filtrere vekk brukernavn, IP-er eller brukeragenter. Vil du ha tilbake dataene? Bruk filter-panelet ved toppen for å fjerne filtre.",
+ "checkuser-investigate-tour-block-title": "Ønsker du å blokkere?",
+ "checkuser-investigate-tour-block-desc": "Lar deg velge brukerne du ønsker å blokkere, og tar deg tilbake til blokkeringsskjemaet for å velge en passende blokkering.",
+ "checkuser-investigate-tour-copywikitext-title": "Ønsker du å kopiere dataene?",
+ "checkuser-investigate-tour-copywikitext-desc": "Kopier sammenligningstabellen med ett klikk og ta den med til CUWiki. Merk at du kun kopierer det som er synlig, og ikke alle sidene i etterforskningen."
}
diff --git a/CheckUser/i18n/nds-nl.json b/CheckUser/i18n/nds-nl.json
index e9a6558c..a0bd19e7 100644
--- a/CheckUser/i18n/nds-nl.json
+++ b/CheckUser/i18n/nds-nl.json
@@ -9,9 +9,9 @@
"checkuser-logcase": "De zeukfunksie van t logboek is heufdlettergeveulig",
"checkuser": "Gebruker naokieken",
"checkuserlog": "Logboek gebrukersscheumers",
- "group-checkuser": "gebrukers naokieken",
- "group-checkuser-member": "{{GENDER:$1|gebrukersscheumerd}}",
- "grouppage-checkuser": "{{ns:project}}:Gebrukersscheumerd",
+ "group-checkuser": "gebrukers nåkyken",
+ "group-checkuser-member": "{{GENDER:$1|gebrukerkontrolöör}}",
+ "grouppage-checkuser": "{{ns:project}}:Gebrukerkontrolöör",
"checkuser-reason": "Reden:",
"checkuser-showlog": "Logboek bekieken",
"checkuser-query": "Zeukopdrachte leste wiezigingen",
@@ -30,5 +30,5 @@
"checkuser-search": "Zeuken",
"checkuser-search-submit": "Zeuken",
"checkuser-search-initiator": "anvrager",
- "checkuser-search-target": "onderwarp"
+ "checkuser-search-target": "dool"
}
diff --git a/CheckUser/i18n/nds.json b/CheckUser/i18n/nds.json
index b6381fd7..35392bba 100644
--- a/CheckUser/i18n/nds.json
+++ b/CheckUser/i18n/nds.json
@@ -1,8 +1,8 @@
{
"@metadata": {
"authors": [
- "Slomox",
- "Joachim Mos"
+ "Joachim Mos",
+ "Slomox"
]
},
"checkuser-summary": "Dit Warktüüch dörsöcht de lesten Ännern na de IP-Adressen, de en Bruker bruukt hett, oder na de Ännern un Brukernaams, de vun en bestimmte IP maakt/bruukt worrn sünd.\nBrukers un Ännern vun XFF-IPs ut köönt ankeken warrn, wenn „/xff“ achter de IP toschreven warrt. IPv4 (CIDR $1-32) un IPv6 (CIDR $2-128) warrt all beid ünnerstütt.\nDe Maximaltall vun trüchlevert Ännern is 5000.\nDit Warktüüch dröff blot na de Regeln mit de Richtlienen bruukt warrn.",
@@ -50,7 +50,6 @@
"checkuser-block-failure": "'''Kene Brukers sperrt.'''",
"checkuser-block-limit": "Toveel Brukers utwählt.",
"checkuser-block-noreason": "Du musst en Grund för de Sperr angeven.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nee Brukerkonto|ne’e Brukerkonten}}",
"checkuser-too-many": "To veel funnen, grenz de IP-Reeg wieder in. Dit sünd de bruukten IP-Adressen (maximal 5000, sorteert na Adress):",
"checkuser-user-nonexistent": "Den angevene Bruker gifft dat nich.",
"checkuser-search": "Söken",
diff --git a/CheckUser/i18n/ne.json b/CheckUser/i18n/ne.json
index 320357ac..e6b47836 100644
--- a/CheckUser/i18n/ne.json
+++ b/CheckUser/i18n/ne.json
@@ -3,8 +3,10 @@
"authors": [
"Bhawani Gautam",
"Bhawani Gautam Rhk",
- "बिप्लब आनन्द",
- "NehalDaveND"
+ "NehalDaveND",
+ "Nirajan pant",
+ "पर्वत सुबेदी",
+ "बिप्लब आनन्द"
]
},
"checkuser": "प्रयोगकर्ता जाँच",
@@ -46,9 +48,23 @@
"checkuser-localonly": "एकीकृत छैन",
"checkuser-search": "खोज्ने",
"checkuser-search-submit": "खोज",
- "apihelp-query+checkuser-param-reason": "जाँच्ने कारण।",
- "apihelp-query+checkuser-param-limit": "पङ्क्तिहरूको सीमा।",
- "apihelp-query+checkuserlog-param-user": "प्रयोगकर्ताजाँचको प्रयोगकर्ता नाम।",
- "apihelp-query+checkuserlog-param-target": "प्रयोगकर्ता जाँच, आइपी ठेगाना, वा सिआइडिआर सीमा।",
- "apihelp-query+checkuserlog-param-limit": "पङ्क्तिहरूको सीमा।"
+ "checkuser-investigate-notice-no-results": "कुनैपनि नतिजाहरू भेटिएनन्",
+ "checkuser-investigate-tab-compare": "आइपी तथा प्रयोगकर्ता एजेन्टहरू",
+ "checkuser-investigate-tab-timeline": "समयरेखा",
+ "checkuser-investigate-reason-label": "कारण",
+ "checkuser-investigate-preliminary-table-cell-blocked": "निषेधित",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|सम्पादन|सम्पादनहरू}}",
+ "checkuser-investigate-preliminary-table-header-blocked": "स्थिति",
+ "checkuser-investigate-preliminary-table-header-editcount": "सम्पादनहरू",
+ "checkuser-investigate-preliminary-table-header-groups": "समूहहरू",
+ "checkuser-investigate-preliminary-table-header-name": "प्रयोगकर्ता नाम",
+ "checkuser-investigate-preliminary-table-header-wiki": "विकि",
+ "checkuser-investigate-filters-legend": "छनाेटहरू",
+ "checkuser-investigate-compare-table-cell-unregistered": "दर्ता नभएकाे",
+ "checkuser-investigate-compare-table-cell-edits": "$1 {{PLURAL:$1|सम्पादन|सम्पादनहरू}}",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 सबै प्रयाेगकर्ताहरूबाट)</i>",
+ "checkuser-investigate-compare-table-header-username": "प्रयोगकर्ता नाम",
+ "checkuser-investigate-compare-table-header-activity": "मिति सीमा",
+ "checkuser-investigate-compare-table-header-ip": "आइपी",
+ "checkuser-investigate-compare-table-header-useragent": "प्रयोगकर्ता दलाल"
}
diff --git a/CheckUser/i18n/nl.json b/CheckUser/i18n/nl.json
index 6ffcdac8..6965ed26 100644
--- a/CheckUser/i18n/nl.json
+++ b/CheckUser/i18n/nl.json
@@ -1,13 +1,17 @@
{
"@metadata": {
"authors": [
+ "Akoopal",
+ "Dutchy45",
+ "Elroy",
"Erwin",
+ "Mainframe98",
+ "Nieuwsgierige Gebruiker",
+ "PonkoSasuke",
"SPQRobin",
"Siebrand",
- "Troefkaart",
"Sjoerddebruin",
- "Akoopal",
- "Mainframe98"
+ "Troefkaart"
]
},
"checkuser-summary": "Dit hulpmiddel bekijkt recente wijzigingen om IP-adressen die een gebruiker heeft gebruikt te achterhalen of geeft de bewerkings- en gebruikersgegegevens weer voor een IP-adres.\nGebruikers en bewerkingen van een IP-adres van een client kunnen achterhaald worden via XFF-headers door \"/xff\" achter het IP-adres toe te voegen. IPv4 (CIDR $1-32) en IPv6 (CIDR $2-128) worden ondersteund.\nOm prestatieredenen worden niet meer dan 5.000 bewerkingen weergegeven.\nGebruik dit hulpmiddel volgens het vastgestelde beleid.",
@@ -44,6 +48,7 @@
"checkuser-nomatch-edits": "Niets gevonden.\nDe laatste bewerking was op $1 om $2.",
"checkuser-check": "Controleren",
"checkuser-check-this-user": "Deze gebruiker controleren",
+ "checkuser-recent-checks": "Recente controles voor deze gebruiker",
"checkuser-log-fail": "Logboekregel toevoegen niet mogelijk",
"checkuser-nolog": "Geen logboek gevonden.",
"checkuser-blocked": "Geblokkeerd",
@@ -64,8 +69,7 @@
"checkuser-block-noreason": "U moet een reden opgeven voor de blokkades.",
"checkuser-centralauth-multilock": "Lock alle geselecteerde gebruikers",
"checkuser-noreason": "U moet een reden opgeven voor deze zoekopdracht.",
- "checkuser-accounts": "$1 nieuwe {{PLURAL:$1|gebruiker|gebruikers}}",
- "checkuser-too-many": "Te veel resultaten (volgens de schatting). Maak de CIDR kleiner:\nHieronder worden de gebruikte IP-adressen weergegeven (maximaal 5000, op IP-adres gesorteerd):",
+ "checkuser-too-many": "Te veel resultaten (volgens de schatting). Maak de CIDR kleiner:\nHieronder worden de gebruikte IP-adressen weergegeven (maximaal $1, op IP-adres gesorteerd):",
"checkuser-user-nonexistent": "De opgegeven gebruiker bestaat niet.",
"checkuser-search": "Checkuserlogboekregels doorzoeken",
"checkuser-search-submit": "Zoeken",
@@ -77,33 +81,53 @@
"checkuser-showmain": "Naar het hoofdformulier van GebruikerControleren gaan",
"checkuser-limited": "'''Deze resultaten zijn niet volledig om prestatieredenen.'''",
"checkuser-log-entry-userips": "$3, $1 heeft IP-adressen opgevraagd voor $2",
- "checkuser-log-entry-ipedits": "$3, $1 heeft bewerkingen opgevraagd voor $2",
- "checkuser-log-entry-ipusers": "$3, $1 heeft gebruikers opgevraagd voor $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 heeft bewerkingen opgevraagd voor XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 heeft gebruikers opgevraagd voor XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 heeft bewerkingen opgevraagd voor <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 heeft gebruikers opgevraagd voor <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 heeft bewerkingen opgevraagd voor XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 heeft gebruikers opgevraagd voor XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 heeft bewerkingen opgevraagd voor $2",
"checkuser-autocreate-action": "is automatisch aangemaakt",
"checkuser-create-action": "is aangemaakt",
"checkuser-email-action": "heeft een e-mail gestuurd aan \"$1\"",
"checkuser-reset-action": "heeft het wachtwoord voor gebruiker \"$1\" opnieuw ingesteld",
"checkuser-token-fail": "Sessie is mislukt. Probeer het opnieuw.",
- "apihelp-query+checkuser-description": "Controleer welke IP-adressen gebruikt worden door een opgegeven gebruikersnaam of welke gebruikersnamen worden gebruikt door een opgegeven IP-adres.",
- "apihelp-query+checkuser-summary": "Controleer welke IP-adressen gebruikt worden door een opgegeven gebruikersnaam of welke gebruikersnamen worden gebruikt door een opgegeven IP-adres.",
- "apihelp-query+checkuser-param-request": "Type van het CheckUserverzoek:\n;userips:IP-adres van de doelgebruiker ophalen.\n;edits:Wijzigingen van IP-adres of IP-adresreeks ophalen.\n;ipusers:Gebruikers van IP-adres of IP-adresreeks ophalen.",
- "apihelp-query+checkuser-param-target": "Gebruikersnaam, IP-adres, of te controleren CIDR-range.",
- "apihelp-query+checkuser-param-reason": "Reden voor controleren.",
- "apihelp-query+checkuser-param-limit": "Limiet voor rijen.",
- "apihelp-query+checkuser-param-timecond": "Tijdslimiet voor gebruikersgegevens, bijvoorbeeld \"-2 weeks\" of \"2 weeks ago\".",
- "apihelp-query+checkuser-param-xff": "XFF-gegevens gebruiken in plaats van IP-adres.",
- "apihelp-query+checkuser-example-1": "IP-adressen controleren voor [[User:Example]].",
- "apihelp-query+checkuser-example-2": "Bewerkingen controleren voor 192.0.2.0/24.",
- "apihelp-query+checkuserlog-description": "Regels uit het CheckUserlogboek ophalen.",
- "apihelp-query+checkuserlog-param-user": "Naam van de gebruiker met CheckUserrechten.",
- "apihelp-query+checkuserlog-param-target": "Gebruiker, IP-adres of CIDR-range gecontroleerd.",
- "apihelp-query+checkuserlog-param-limit": "Limiet voor rijen.",
- "apihelp-query+checkuserlog-param-from": "Het tijdstip waar de opsomming begint.",
- "apihelp-query+checkuserlog-param-to": "Het tijdstip waar de opsomming eindigt.",
- "apihelp-query+checkuserlog-example-1": "Controles van [[User:Example]] weergeven.",
- "apihelp-query+checkuserlog-example-2": "Controles van 192.0.2.0/24 na 2011-10-15T23:00:00Z weergeven.",
- "apierror-checkuser-missingsummary": "U moet een reden opgeven voor deze controle."
+ "checkuser-login-failure": "Kon niet als $1 inloggen op {{SITENAME}}",
+ "checkuser-login-success": "Succesvol als $1 op {{SITENAME}} ingelogd",
+ "checkuser-investigateblock-target": "Gebruikersnaam en IP-adressen",
+ "checkuser-investigateblock-options": "Verdere opties",
+ "checkuser-investigateblock-notice-position-label": "Positie",
+ "checkuser-investigateblock-notice-text-label": "Wikitext",
+ "checkuser-investigateblock-notice-replace": "Vervang pagina",
+ "checkuser-investigate": "Onderzoeken",
+ "checkuser-investigate-subtitle-block-button-label": "Blokkeren",
+ "checkuser-investigate-indicator-logs": "Logboeken",
+ "checkuser-investigate-legend": "Zoeken naar gebruikersnamen, IP-adressen of IP bereiken",
+ "checkuser-investigate-notice-no-results": "Er zijn geen resultaten.",
+ "checkuser-investigate-tab-compare": "Vergelijken",
+ "checkuser-investigate-tab-timeline": "Tijdlijn",
+ "checkuser-investigate-targets-label": "Gebruikersnaam of IP-adres",
+ "checkuser-investigate-targets-placeholder": "Gebruikersnaam of 1.1.1.1",
+ "checkuser-investigate-duration-label": "Duur",
+ "checkuser-investigate-duration-option-all": "Alle",
+ "checkuser-investigate-duration-option-1w": "Afgelopen week",
+ "checkuser-investigate-duration-option-2w": "Afgelopen twee weken",
+ "checkuser-investigate-duration-option-30d": "Laatste 30 dagen",
+ "checkuser-investigate-reason-label": "Reden",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Geblokkeerd",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|bewerking|bewerkingen}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Niet geblokkeerd",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Bewerkingen",
+ "checkuser-investigate-preliminary-table-header-groups": "Groepen",
+ "checkuser-investigate-preliminary-table-header-name": "Gebruikersnaam",
+ "checkuser-investigate-preliminary-table-header-registration": "Koppelingsdatum",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki niet gevonden",
+ "checkuser-investigate-compare-notice-no-results": "Er zijn geen resultaten: deze users of IP-adressen hebben de voorbije 90 dagen geen veranderingen doorgevoerd",
+ "checkuser-investigate-compare-notice-no-results-filters": "Er zijn geen resultaten die aan deze filtervoorwaarden voldoen. Probeer een aantal filters te verwijderen om breder te zoeken.",
+ "checkuser-investigate-compare-table-cell-unregistered": "Niet-geregistreerd",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|bewerking|bewerkingen}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 van alle gebruikers)</i>",
+ "checkuser-investigate-compare-table-header-username": "Gebruikersnaam",
+ "checkuser-investigate-compare-table-header-ip": "IP-adres"
}
diff --git a/CheckUser/i18n/nn.json b/CheckUser/i18n/nn.json
index d8689347..e579c409 100644
--- a/CheckUser/i18n/nn.json
+++ b/CheckUser/i18n/nn.json
@@ -57,7 +57,6 @@
"checkuser-block-limit": "For mange brukarar er valte.",
"checkuser-block-noreason": "Du må oppgje ei blokkeringsårsak.",
"checkuser-noreason": "Du må gje opp ei grunngjeving for denne spørjinga.",
- "checkuser-accounts": "{{PLURAL:$1|Éin ny konto|$1 nye kontoar}}",
"checkuser-too-many": "For mange resultat, (i høve til overslag for spørjinga) ver venleg og reduser CIDR.\nHer er IP-ane nytta (høgst 5000, sorterte etter adressa):",
"checkuser-user-nonexistent": "Brukarnamnet du oppgav finst ikkje.",
"checkuser-search": "Søk",
diff --git a/CheckUser/i18n/oc.json b/CheckUser/i18n/oc.json
index 1243a80b..7e51baf3 100644
--- a/CheckUser/i18n/oc.json
+++ b/CheckUser/i18n/oc.json
@@ -2,7 +2,8 @@
"@metadata": {
"authors": [
"Boulaur",
- "Cedric31"
+ "Cedric31",
+ "Quentí"
]
},
"checkuser-summary": "Aquesta aisina passa en revista los cambiaments recents per recercar l'IPS emplegada per un utilizaire, mostrar totas las edicions faitas per una IP, o per enumerar los utilizaires qu'an emplegat las IPs. Los utilizaires e las modificacions pòdon èsser trobats amb una IP XFF se s'acaba amb « /xff ». IPv4 (CIDR $1-32) e IPv6(CIDR $2-128) son suportats. Emplegatz aquò segon las cadenas de caractèrs.",
@@ -52,7 +53,6 @@
"checkuser-block-limit": "Tròp d'utilizaires seleccionats.",
"checkuser-block-noreason": "Vos cal especificar un motiu pels blocatges.",
"checkuser-noreason": "Vos cal balhar una rason per aquesta requèsta.",
- "checkuser-accounts": "$1 {{PLURAL:$1|compte novèl|comptes novèls}}",
"checkuser-too-many": "Tròp de resultats (segon l'estimacion de la requèsta), afinatz l’espandida CIDR.\nVaquí un extrait de las adreças IP utilizadas ({{formatnum:5000}} maximum, triadas per adreça) :",
"checkuser-user-nonexistent": "L’utilizaire indicat existís pas",
"checkuser-search": "Recercar las entradas de jornal de verificacion utilizaire",
@@ -65,5 +65,8 @@
"checkuser-autocreate-action": "es estat creat automaticament",
"checkuser-create-action": "es estat creat",
"checkuser-email-action": "a mandat un corrièr electronic a « $1 »",
- "checkuser-reset-action": "torna inicializar lo senhal per « $1 »"
+ "checkuser-reset-action": "torna inicializar lo senhal per « $1 »",
+ "checkuser-investigate-subtitle-block-button-label": "Blocar",
+ "checkuser-investigate-subtitle-cancel-button-label": "Anullar",
+ "checkuser-investigate-subtitle-continue-button-label": "Contunhar"
}
diff --git a/CheckUser/i18n/or.json b/CheckUser/i18n/or.json
index 20e3c8fb..f10f6eb8 100644
--- a/CheckUser/i18n/or.json
+++ b/CheckUser/i18n/or.json
@@ -34,7 +34,7 @@
"checkuser-all": "ସବୁ",
"checkuser-cidr-label": "ଏକ IP ଠିକଣାର ତାଲିକା ନିମନ୍ତେ ଏକ ସାଧାରଣ ସୀମା ଓ ପ୍ରଭାବିତ IP ଠିକଣାମାନ ଦିଅନ୍ତୁ",
"checkuser-cidr-res": "ସାଧାରଣ CIDR:",
- "checkuser-empty": "ଇତିହାସରେ କିଛି ବି ବିଷୟ ନାହିଁ ।",
+ "checkuser-empty": "ଇତିହାସରେ କୌଣସି ବିଷୟ ନାହିଁ ।",
"checkuser-nomatch": "କିଛି ମେଳହେଲା ନାହିଁ ।",
"checkuser-nomatch-edits": "କିଛି ବି ମେଳ ଖାଇଲା ନାହିଁ ।\nଶେଷ ବଦଳଟି $1 ଦିନ $2 ବେଳେ ହୋଇଥିଲା ।",
"checkuser-check": "ଯାଞ୍ଚ କରିବା",
@@ -54,7 +54,6 @@
"checkuser-block-limit": "ବହୁ ଅଧିକ ବ୍ୟବହାରକାରୀଙ୍କୁ ବଛାଗଲା ।",
"checkuser-block-noreason": "ଆପଣଙ୍କୁ ଅଟକ ପାଇଁ ଏକ କାରଣ ଦେବାକୁ ପଡ଼ିବ ।",
"checkuser-noreason": "ଆପଣଙ୍କୁ ଏହି ପ୍ରଶ୍ନ ପାଇଁ ଏକ କାରଣ ଦେବାକୁ ପଡ଼ିବ ।",
- "checkuser-accounts": "$1 ଗୋଟି ନୂଆ {{PLURAL:$1|ଖାତା|ଖାତା}}",
"checkuser-user-nonexistent": "ଆପଣ ଖୋଜୁଥିବା ବ୍ୟବହାରକାରୀ ମିଳୁନାହାନ୍ତି ।",
"checkuser-search": "ଖୋଜନ୍ତୁ",
"checkuser-search-submit": "ଖୋଜନ୍ତୁ",
diff --git a/CheckUser/i18n/pag.json b/CheckUser/i18n/pag.json
index b7ab7d4c..4353670d 100644
--- a/CheckUser/i18n/pag.json
+++ b/CheckUser/i18n/pag.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser-reason": "Katonongan",
"checkuser-target": "Manag-usar odino IP",
"checkuser-users": "Alaen so manag-usar",
diff --git a/CheckUser/i18n/pam.json b/CheckUser/i18n/pam.json
index 5278894f..319990dc 100644
--- a/CheckUser/i18n/pam.json
+++ b/CheckUser/i18n/pam.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser": "Surian ya ing gagamit",
"checkuser-reason": "Sangkan:",
"checkuser-showlog": "Pakit ya ing log",
diff --git a/CheckUser/i18n/pl.json b/CheckUser/i18n/pl.json
index aa72d6e2..4dcd4c19 100644
--- a/CheckUser/i18n/pl.json
+++ b/CheckUser/i18n/pl.json
@@ -5,16 +5,18 @@
"Beau",
"BeginaFelicysym",
"Chaduvari",
+ "Chrumps",
"Derbeth",
+ "Krottyianock",
"Leinad",
+ "Matma Rex",
+ "Rail",
+ "Railfail536",
"Saper",
"Sovq",
"Sp5uhe",
"Woytecr",
"Wpedzich",
- "Chrumps",
- "Krottyianock",
- "Railfail536",
"Zero"
]
},
@@ -66,6 +68,7 @@
"checkuser-blocktalk": "Zablokuj możliwość edytowania przez tego użytkownika własnej strony dyskusji w czasie trwania blokady",
"checkuser-blocktag": "Podmień strony blokowanych użytkowników na",
"checkuser-blocktag-talk": "Podmień strony dyskusji blokowanych użytkowników na",
+ "checkuser-reblock": "Nadpisz istniejące blokady",
"checkuser-massblock-commit": "Zablokuj wybranych użytkowników",
"checkuser-block-success": "'''{{PLURAL:$2|Użytkownik|Użytkownicy}} $1 {{PLURAL:$2|jest|są}} obecnie {{PLURAL:$2|zablokowany|zablokowani}}.'''",
"checkuser-block-failure": "'''Nie udało się zablokować użytkowników.'''",
@@ -73,8 +76,7 @@
"checkuser-block-noreason": "Należy podać powód blokad.",
"checkuser-centralauth-multilock": "Zablokuj wybrane konta",
"checkuser-noreason": "Musisz podać powód wykonania zapytania.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nowe konto|nowe konta|nowych kont}}",
- "checkuser-too-many": "System oszacował, że zapytanie zwróci zbyt wiele wyników; spróbuj zawęzić zakres CIDR.\n\nPoniżej wyświetlono pierwszych 5000 adresów IP (posortowane według adresu):",
+ "checkuser-too-many": "System oszacował, że zapytanie zwróci zbyt wiele wyników; spróbuj zawęzić zakres CIDR.\n\nPoniżej wyświetlono używane adresy IP (maksymalnie $1, posortowane według adresu):",
"checkuser-user-nonexistent": "Taki użytkownik nie istnieje.",
"checkuser-search": "Szukaj w rejestrze checkuserów",
"checkuser-search-submit": "Szukaj",
@@ -84,40 +86,108 @@
"checkuser-log-search-type": "Szukaj według:",
"checkuser-ipeditcount": "~$1 od wszystkich użytkowników",
"checkuser-showmain": "Przejdź do głównego formularza CheckUser",
- "checkuser-limited": "'''Długość listy wyników została ograniczona ze względu na wydajność.'''",
+ "checkuser-limited": "'''Ze względów wydajnościowych lista wyników została skrócona.'''",
"checkuser-log-entry-userips": "$3, $1 otrzymał adresy IP używane przez $2",
- "checkuser-log-entry-ipedits": "$3, $1 otrzymał historię edycji dla $2",
- "checkuser-log-entry-ipusers": "$3, $1 otrzymał listę użytkowników korzystających z adresu IP $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 otrzymał listę edycji dla XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 otrzymał listę użytkowników dla XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 otrzymał historię edycji dla <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 otrzymał listę użytkowników korzystających z adresu IP <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 otrzymał listę edycji dla XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 otrzymał listę użytkowników dla XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 otrzymał historię edycji wykonanych przez $2",
"checkuser-autocreate-action": "został automatycznie utworzony",
"checkuser-create-action": "utworzono",
"checkuser-email-action": "wysłał e‐mail do użytkownika „$1”",
"checkuser-reset-action": "reset hasła dla użytkownika „$1”",
"checkuser-token-fail": "Awaria sesji. Spróbuj jeszcze raz.",
- "checkuser-login-failure": "Logowanie do {{SITENAME}} jako $1 nie powiodło się",
- "checkuser-login-success": "Pomyślnie zalogowano do {{SITENAME}} jako $1",
- "apihelp-query+checkuser-description": "Umożliwia sprawdzenie, z których adresów IP edytował zadany użytkownik lub odnalezienie nazw użytkowników korzystających z zadanego adresu IP.",
- "apihelp-query+checkuser-summary": "Umożliwia sprawdzenie, z których adresów IP edytował zadany użytkownik lub odnalezienie nazw użytkowników korzystających z zadanego adresu IP.",
- "apihelp-query+checkuser-param-request": "Rodzaj zapytania checkuser:\n;userips: Pobierz adresy IP zadanego użytkownika\n;edits: Pobierz edycje z zadanego adresu IP lub ich zakresu\n;ipusers: Pobierz nazwy użytkowników dla zadanego adresu IP lub ich zakresu",
- "apihelp-query+checkuser-param-target": "Nazwa użytkownika, adres IP lub zakres CIDR do sprawdzenia.",
- "apihelp-query+checkuser-param-reason": "Powód dla sprawdzenia",
- "apihelp-query+checkuser-param-limit": "Limit liczby zwróconych wierszy",
- "apihelp-query+checkuser-param-timecond": "Przedział czasowy dla pobieranych danych (np. \"-2 weeks\" lub \"2 weeks ago\" dla ostatnich dwóch tygodni)",
- "apihelp-query+checkuser-param-xff": "Sprawdź nagłówki XFF zamiast rzeczywistego adresu IP",
- "apihelp-query+checkuser-example-1": "Sprawdź adresy IP dla [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Pobierz edycje dla zakresu 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Pobierz wypisy w rejestrze zapytań checkuser.",
- "apihelp-query+checkuserlog-summary": "Pobierz wypisy w rejestrze zapytań checkuser.",
- "apihelp-query+checkuserlog-param-user": "Nazwa użytkownika sprawdzającego (checkusera)",
- "apihelp-query+checkuserlog-param-target": "Nazwa użytkownika sprawdzanego, adres IP lub ich zakres.",
- "apihelp-query+checkuserlog-param-limit": "Limit liczby zwracanych wierszy.",
- "apihelp-query+checkuserlog-param-from": "Znacznik czasu dla najstarszych zwracanych wpisów",
- "apihelp-query+checkuserlog-param-to": "Znacznik czasu, na którym zakończyć wpisywanie danych z rejestru",
- "apihelp-query+checkuserlog-example-1": "Pokaż, co sprawdzał [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Pokaż, kto sprawdzał zakres adresów 192.0.2.0/24 po 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Musisz podać powód sprawdzenia",
- "apierror-checkuser-timelimit": "Musisz użyć poprawnego limitu czasu (np. „-2 tygodnie” lub „2 tygodnie temu”).",
- "apierror-checkuser-invalidmode": "Nieprawidłowy tryb żądania"
+ "checkuser-login-failure": "Logowanie do {{GRAMMAR:D.lp|{{SITENAME}}}} jako $1 nie powiodło się",
+ "checkuser-login-success": "Pomyślnie zalogowano do {{GRAMMAR:D.lp|{{SITENAME}}}} jako $1",
+ "checkuser-link-investigate-label": "Wypróbuj nowe narzędzie CheckUser",
+ "checkuser-investigateblock": "Zablokuj użytkowników",
+ "checkuser-investigateblock-target": "Nazwy użytkownika i adresy IP",
+ "checkuser-investigateblock-actions": "Czynności, które zablokować",
+ "checkuser-investigateblock-reason": "Powód",
+ "checkuser-investigateblock-options": "Dodatkowe opcje",
+ "checkuser-investigateblock-email-label": "Zablokuj możliwość wysyłania e‐maili",
+ "checkuser-investigateblock-usertalk-label": "Zablokuj możliwość edytowania przez tego użytkownika własnej strony dyskusji w czasie trwania blokady",
+ "checkuser-investigateblock-reblock-label": "Nadpisz istniejące blokady",
+ "checkuser-investigateblock-notice-user-page-label": "Zostaw notkę na stronie użytkownika",
+ "checkuser-investigateblock-notice-talk-page-label": "Zostaw notkę na stronie dyskusji użytkownika",
+ "checkuser-investigateblock-notice-position-label": "Położenie",
+ "checkuser-investigateblock-notice-text-label": "Wikitekst",
+ "checkuser-investigateblock-notice-append": "Dodaj do strony",
+ "checkuser-investigateblock-notice-prepend": "Dołącz na początku strony",
+ "checkuser-investigateblock-notice-replace": "Zastąp stronę",
+ "checkuser-investigateblock-failure": "Nie zablokowano żadnego użytkownika. Aby nadpisać istniejące blokady zaznacz pole: „{{int:checkuser-investigateblock-reblock-label}}”. Blokada nie zostanie nadpisana, jeśli jej nowe parametry pokrywają się z istniejącymi.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|Użytkownik|Użytkownicy}} $1 {{PLURAL:$2|jest|są}} obecnie {{PLURAL:$2|zablokowany|zablokowani}}.",
+ "checkuser-investigateblock-notices-failed": "Niektóre notki nie mogły zostać dodane do stron lub dyskusji użytkowników.",
+ "checkuser-investigate-log": "Rejestr sprawdzeń",
+ "checkuser-investigate-log-entry": "$3, $1 sparwdził informacje <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Nie znaleziono wpisów w rejestrze badania.",
+ "checkuser-investigate-log-subtitle": "Przejdź do formularza sprawdzania",
+ "checkuser-investigate": "Sprawdź",
+ "checkuser-investigate-page-subtitle": "Obecnie sprawdzenie dla $1",
+ "checkuser-investigate-subtitle-block-button-label": "Blokuj",
+ "checkuser-investigate-subtitle-cancel-button-label": "Anuluj",
+ "checkuser-investigate-subtitle-continue-button-label": "Kontynuuj",
+ "checkuser-investigate-indicator-new-investigation": "Nowe sprawdzenie",
+ "checkuser-investigate-indicator-logs": "Rejestry",
+ "checkuser-investigate-legend": "Szukaj nazw użytkownika, adresów IP bądź ich zakresów",
+ "checkuser-investigate-notice-no-results": "Nie odnaleziono żadnych wyników.",
+ "checkuser-investigate-tab-preliminary-check": "Informacje o koncie",
+ "checkuser-investigate-tab-compare": "IP i aplikacje klientów",
+ "checkuser-investigate-tab-timeline": "Oś czasu",
+ "checkuser-investigate-targets-label": "Nazwy użytkownika i adresy IP",
+ "checkuser-investigate-targets-placeholder": "NazwaUżytkownika lub 1.1.1.1",
+ "checkuser-investigate-duration-label": "Czas trwania",
+ "checkuser-investigate-duration-option-all": "Wszystko",
+ "checkuser-investigate-duration-option-1w": "Ostatni tydzień",
+ "checkuser-investigate-duration-option-2w": "Ostatnie dwa tygodnie",
+ "checkuser-investigate-duration-option-30d": "Ostatnie 30 dni",
+ "checkuser-investigate-reason-label": "Powód",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Zakładka informacji o koncie nie zawiera żadnych informacji na temat adresów IP. Sprawdź <span class=\"plainlinks\">[$1 zakładkę „IP i aplikacje klientów”]</span> w celu uzyskania tych szczegółów.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Zablokowany",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|edycja|edycje|edycji}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Niezablokowany",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Edycje",
+ "checkuser-investigate-preliminary-table-header-groups": "Grupy",
+ "checkuser-investigate-preliminary-table-header-name": "Nazwa użytkownika",
+ "checkuser-investigate-preliminary-table-header-registration": "Data dołączenia",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Nie odnaleziono wiki",
+ "checkuser-investigate-filters-legend": "Filtry",
+ "checkuser-investigate-filters-exclude-targets-label": "Ukryj poniższych użytkowników lub IP",
+ "checkuser-investigate-timeline-notice-no-results": "Brak wyników: użytkownicy lub IP nie wykazali żadnej zarejestrowanej aktywności w ciągu ostatnich 90 dni",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Brak wyników spełniających podane kryteria filtrowania. Spróbuj usunąć niektóre filtry aby zwiększyć zakres wyszukiwania.",
+ "checkuser-investigate-compare-copy-button-label": "Pokaż wikitekst",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Sprawdź Proxy",
+ "checkuser-investigate-compare-copy-message-label": "Chcesz skopiować te informacje jako tabelę w wikitekście?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "W wyniku ograniczeń technicznych, osiągnięto maksymalną liczbę wpisów, jakie można było wyświetlić. Dane dla następujących podmiotów są niekompletne: $1. Prosimy podać mniejszą liczbę podmiotów, węższe okno czasowe lub zakresy IP.",
+ "checkuser-investigate-compare-notice-no-results": "Brak wyników: użytkownicy lub IP nie wykonywali żadnych edycji w ciągu ostatnich 90 dni",
+ "checkuser-investigate-compare-notice-no-results-filters": "Brak wyników spełniających podane kryteria filtrowania. Spróbuj usunąć niektóre filtry aby zwiększyć zakres wyszukiwania.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Pokaż wszystkie IP tego użytkownika",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Pokaż wszystkich użytkowników z tego IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Dodaj to IP do sprawdzenia",
+ "checkuser-investigate-compare-table-button-checks-label": "Sprawdzenia",
+ "checkuser-investigate-compare-table-button-contribs-label": "Wkład",
+ "checkuser-investigate-compare-table-button-filter-label": "Filtruj z wyników",
+ "checkuser-investigate-compare-table-cell-unregistered": "Niezarejestrowany",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|edycja|edycje|edycji}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 od wszystkich użytkowników)</i>",
+ "checkuser-investigate-compare-table-header-username": "Nazwa użytkownika",
+ "checkuser-investigate-compare-table-header-activity": "Zakres dat",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Aplikacja klienta",
+ "checkuser-investigate-subtitle-link-restart-tour": "Ponów wycieczkę po narzędziu",
+ "checkuser-investigate-tour-targets-title": "Sprawdzasz wielu użytkowników i IP?",
+ "checkuser-investigate-tour-targets-desc": "Dodaj do $1 {{PLURAL:$1|nazwy użytkownika|nazw użytkowników}} lub IP i pozyskaj informacje na ich temat w jednym miejscu. Nie martw się, w rejestrze sprawdzeń powstaną oddzielne wpisy dla każdego z nich.",
+ "checkuser-investigate-tour-useragents-title": "Dopasowujesz aplikacje klientów?",
+ "checkuser-investigate-tour-useragents-desc": "Najedź na komórkę aby podświetlić wszystkie inne wiersze zawierające te same dane. Kliknij ikonę przypinania aby dane dalej były podświetlone podczas przeglądania.",
+ "checkuser-investigate-tour-addusertargets-title": "Potrzebujesz więcej kontekstu?",
+ "checkuser-investigate-tour-addusertargets-desc": "Kliknij, aby zobaczyć wszystkich innych użytkowników korzystających z tego IP. Możesz także wykonać analogiczną operację dla użytkowników i zobaczyć wszystkie IP z których korzystali. Automatycznie utworzymy dla Ciebie wpis w rejestrze sprawdzeń.",
+ "checkuser-investigate-tour-filterip-title": "Zawęzić sprawdzenie?",
+ "checkuser-investigate-tour-filterip-desc": "Usuń bałagan w danych poprzez filtrowanie nazw użytkowników, IP lub aplikacji klientów. Chcesz dane z powrotem? Użyj panelu filtrów na górze aby je usunąć.",
+ "checkuser-investigate-tour-block-title": "Nałożyć blokadę?",
+ "checkuser-investigate-tour-block-desc": "Umożliwia ci wybranie użytkowników, których chcesz zablokować a następnie zabiera cię do formularza blokowania, aby wybrać odpowiednią blokadę.",
+ "checkuser-investigate-tour-copywikitext-title": "Chcesz skopiować dane?",
+ "checkuser-investigate-tour-copywikitext-desc": "Skopiuj tabelę porównywania jednym kliknięciem i zamierz ją na CUWiki. Zauważ tylko, że kopiowane są tylko widoczne dane, nie wszystkie strony sprawdzania."
}
diff --git a/CheckUser/i18n/pms.json b/CheckUser/i18n/pms.json
index ec7cd249..f47b1a75 100644
--- a/CheckUser/i18n/pms.json
+++ b/CheckUser/i18n/pms.json
@@ -56,7 +56,6 @@
"checkuser-block-limit": "Tròpi utent selessionà.",
"checkuser-block-noreason": "It deve dé na rason për ij blocagi.",
"checkuser-noreason": "It deve dé na rason për costa arcesta.",
- "checkuser-accounts": "$1 neuv {{PLURAL:$1|cont|cont}}",
"checkuser-too-many": "Tròpi arzultà (scond la stima dl'arcesta), për piasì strenz ël CIDR.\nSì a-i son j'IP dovrà (5000 al pi, ordinà për adrëssa):",
"checkuser-user-nonexistent": "L'utent specificà a esist pa.",
"checkuser-search": "Sërca",
diff --git a/CheckUser/i18n/ps.json b/CheckUser/i18n/ps.json
index f394a800..6c98ffa0 100644
--- a/CheckUser/i18n/ps.json
+++ b/CheckUser/i18n/ps.json
@@ -2,6 +2,7 @@
"@metadata": {
"authors": [
"Ahmed-Najib-Biabani-Ibrahimkhel",
+ "Amjad Khan",
"Baloch Khan"
]
},
@@ -31,7 +32,6 @@
"checkuser-block-failure": "'''په هېڅ کارن بنديز پلي نشو.'''",
"checkuser-block-limit": "له حد نه ډېر زيات کارنان ټاکل شوي.",
"checkuser-block-noreason": "تاسې بايد د بنديز لگولو يو سبب څرگند کړئ.",
- "checkuser-accounts": "$1 {{PLURAL:$1|نوی گڼون|نوي گڼونونه}}",
"checkuser-search": "پلټل",
"checkuser-search-submit": "پلټل",
"checkuser-search-initiator": "پېلوونکی",
diff --git a/CheckUser/i18n/pt-br.json b/CheckUser/i18n/pt-br.json
index 440732f2..decc58b4 100644
--- a/CheckUser/i18n/pt-br.json
+++ b/CheckUser/i18n/pt-br.json
@@ -3,25 +3,27 @@
"authors": [
"Amgauna",
"Ankry",
+ "Araceletorres",
"Cainamarques",
"Chaduvari",
"Dicionarista",
+ "Eduardo Addad de Oliveira",
"Eduardo.mps",
+ "Felipe L. Ewald",
"Giro720",
+ "He7d3r",
"Helder.wiki",
"Heldergeovane",
"Jesielt",
"Luckas",
"Luckas Blade",
- "Pedroca cerebral",
- "555",
- "He7d3r",
- "Araceletorres",
+ "Luk3",
"Macofe",
- "Felipe L. Ewald",
+ "Opraco",
+ "Pedroca cerebral",
"RadiX",
- "Eduardo Addad de Oliveira",
- "Opraco"
+ "Rodrigo codignoli",
+ 555
]
},
"checkuser-summary": "Esta ferramenta varre as mudanças recentes para obter os endereços de IP de um usuário ou para exibir os dados de edições/usuários para um IP.\nUsuários e edições podem ser obtidos por um IP XFF colocando-se \"/xff\" no final do endereço. São suportados endereços IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128).\nNão serão retornadas mais de 5000 edições por motivos de desempenho. O uso desta ferramenta deverá estar de acordo com as políticas.",
@@ -63,7 +65,7 @@
"checkuser-nolog": "Não foi encontrado um arquivo de registros.",
"checkuser-blocked": "Bloqueado",
"checkuser-gblocked": "Bloqueado globalmente",
- "checkuser-locked": "Bloqueado",
+ "checkuser-locked": "bloqueada",
"checkuser-wasblocked": "Previamente bloqueado",
"checkuser-localonly": "Não unificada",
"checkuser-massblock": "Bloquear usuários selecionados",
@@ -72,6 +74,7 @@
"checkuser-blocktalk": "Evite editar sua própria página de discussão enquanto estiver bloqueada",
"checkuser-blocktag": "Substituir páginas de usuário com:",
"checkuser-blocktag-talk": "Substituir páginas de discussão por:",
+ "checkuser-reblock": "Substituir bloqueios existentes",
"checkuser-massblock-commit": "Bloquear usuários selecionados",
"checkuser-block-success": "'''{{PLURAL:$2|O usuário|Os usuários}} $1 {{PLURAL:$2|está|estão}} agora {{PLURAL:$2|bloqueado|bloqueados}}.'''",
"checkuser-block-failure": "'''Nenhum usuário bloqueado.'''",
@@ -79,8 +82,7 @@
"checkuser-block-noreason": "Você deve especificar um motivo para os bloqueios.",
"checkuser-centralauth-multilock": "Multi-bloqueio de contas selecionadas",
"checkuser-noreason": "Você deve fornecer um motivo para esta pesquisa.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nova conta|novas contas}}",
- "checkuser-too-many": "Há muitos resultados (de acordo com a estimativa de consulta), por favor, restrinja o CIDR. \nAqui estão os IPs usados (5000 no máx., ordenados por endereço):",
+ "checkuser-too-many": "Há muitos resultados (de acordo com a estimativa de consulta), por favor, restrinja o CIDR. \nAqui estão os IPs usados ($1 no máx., ordenados por endereço):",
"checkuser-user-nonexistent": "O usuário especificado não existe.",
"checkuser-search": "Pesquisar entradas do registro do CheckUser",
"checkuser-search-submit": "Pesquisar",
@@ -92,10 +94,10 @@
"checkuser-showmain": "Retornar ao formulário principal de CheckUser",
"checkuser-limited": "'''Estes resultados foram removidos por motivos de performance.'''",
"checkuser-log-entry-userips": "$3, $1 obteve endereços IP para $2",
- "checkuser-log-entry-ipedits": "$3, $1 obteve edições de $2",
- "checkuser-log-entry-ipusers": "$3, $1 obteve usuários para $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 obteve edições para XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 obteve usuários para XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 obteve edições de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 obteve usuários para <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 obteve edições para XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 obteve usuários para XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 obteve edições por $2",
"checkuser-autocreate-action": "foi automaticamente criada",
"checkuser-create-action": "foi criada",
@@ -106,26 +108,94 @@
"checkuser-login-success": "Entrou em {{SITENAME}} como $1",
"group-checkuser.css": "/* CSS colocado aqui afetará apenas checkuser */",
"group-checkuser.js": "/* JS colocado aqui afetará o usuário do checkeruser */",
- "apihelp-query+checkuser-description": "Verifique quais endereços IP são utilizados por um determinado nome de usuário ou quais nomes de usuários são utilizados por um determinado endereço IP.",
- "apihelp-query+checkuser-summary": "Verifique quais endereços IP são utilizados por um determinado nome de usuário ou quais nomes de usuários são utilizados por um determinado endereço IP.",
- "apihelp-query+checkuser-param-request": "Tipo de pedido CheckUser:\n;userips:Obter endereço IP do usuário-alvo.\n;edits:Obter alterações de endereço IP de destino ou intervalo.\n;ipusers:Obter usuários de endereço IP de destino ou intervalo.",
- "apihelp-query+checkuser-param-target": "Nome de usuário, endereço IP ou intervalo CIDR para verificar.",
- "apihelp-query+checkuser-param-reason": "Motivo para verificar.",
- "apihelp-query+checkuser-param-limit": "Limite de linhas.",
- "apihelp-query+checkuser-param-timecond": "Limite de tempo dos dados do usuário (como \"-2 weeks\" ou \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Usar dados XFF no lugar do endereço IP.",
- "apihelp-query+checkuser-example-1": "Verificar endereço IP para [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Verificar edições de 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Obter entradas do registro do CheckUser.",
- "apihelp-query+checkuserlog-summary": "Obter entradas do registro do CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Nome de usuário do CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Usuário verificado, endereço IP ou intervalo CIDR.",
- "apihelp-query+checkuserlog-param-limit": "Limite de linhas.",
- "apihelp-query+checkuserlog-param-from": "O timestamp para começar a enumeração.",
- "apihelp-query+checkuserlog-param-to": "O selo do tempo para finalizar a enumeração.",
- "apihelp-query+checkuserlog-example-1": "Mostrar verificações de [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Mostrar verificações de 192.0.2.0/24 após 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Você deve definir o motivo da verificação.",
- "apierror-checkuser-timelimit": "Você precisa usar o limite de tempo correto (como \"-2 semanas\" ou \"2 semanas atrás\").",
- "apierror-checkuser-invalidmode": "Modo de solicitação inválido"
+ "checkuser-link-investigate-label": "Experimente a nova ferramenta CheckUser",
+ "checkuser-investigateblock": "Bloquear usuários",
+ "checkuser-investigateblock-target": "Nomes de usuário e endereços IP",
+ "checkuser-investigateblock-actions": "Ações a serem bloqueadas",
+ "checkuser-investigateblock-reason": "Motivo",
+ "checkuser-investigateblock-options": "Opções adicionais",
+ "checkuser-investigateblock-email-label": "Previne de enviar e-mail",
+ "checkuser-investigateblock-usertalk-label": "Evite editar sua própria página de discussão enquanto estiver bloqueada",
+ "checkuser-investigateblock-reblock-label": "Substituir bloqueios existentes",
+ "checkuser-investigateblock-notice-user-page-label": "Deixar um aviso na página do usuário",
+ "checkuser-investigateblock-notice-talk-page-label": "Deixar um aviso na página de discussão do usuário",
+ "checkuser-investigateblock-notice-position-label": "Posição",
+ "checkuser-investigateblock-notice-text-label": "Wikitexto",
+ "checkuser-investigateblock-notice-append": "Anexar à página",
+ "checkuser-investigateblock-notice-prepend": "Anexar à página",
+ "checkuser-investigateblock-notice-replace": "Substituir página",
+ "checkuser-investigateblock-failure": "Nenhum usuário foi bloqueado. Para substituir os blocos existentes, verifique: \"{{int:checkuser-inquiryblock-reblock-label}}\". Um bloco não será substituído se o novo bloco for idêntico ao bloco existente.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|O usuário|Os usuários}} $1 {{PLURAL:$2|está|estão}} agora bloqueado.",
+ "checkuser-investigateblock-notices-failed": "Alguns avisos não puderam ser adicionados às páginas do usuário ou às páginas de discussão do usuário.",
+ "checkuser-investigate-log": "Logs de investigação",
+ "checkuser-investigate-log-entry": "$3, o usuario $1 procurou informações de <bdi>$2</bdi> por $4",
+ "checkuser-investigate-log-empty": "Não há logs disponíveis",
+ "checkuser-investigate-log-subtitle": "Mudar para o formulário de investigar",
+ "checkuser-investigate": "Investigar",
+ "checkuser-investigate-page-subtitle": "Investigação atual para $1",
+ "checkuser-investigate-subtitle-block-button-label": "Bloquear",
+ "checkuser-investigate-subtitle-cancel-button-label": "Cancelar",
+ "checkuser-investigate-subtitle-continue-button-label": "Continuar",
+ "checkuser-investigate-indicator-new-investigation": "Nova investigação",
+ "checkuser-investigate-indicator-logs": "Registros",
+ "checkuser-investigate-legend": "Pesquise nomes de usuário, endereços IP ou intervalos de IP",
+ "checkuser-investigate-notice-no-results": "Não há resultados.",
+ "checkuser-investigate-tab-preliminary-check": "Informações da Conta",
+ "checkuser-investigate-tab-compare": "IPs e agentes do usuário",
+ "checkuser-investigate-tab-timeline": "Linha do tempo",
+ "checkuser-investigate-targets-label": "Nomes de usuário e endereços IP",
+ "checkuser-investigate-targets-placeholder": "Mome de usuário ou 1.1.1.1",
+ "checkuser-investigate-duration-label": "Duração",
+ "checkuser-investigate-duration-option-all": "Todos",
+ "checkuser-investigate-duration-option-1w": "Última semana",
+ "checkuser-investigate-duration-option-2w": "Última 2 semanas",
+ "checkuser-investigate-duration-option-30d": "últimos 30 dias",
+ "checkuser-investigate-reason-label": "Razão",
+ "checkuser-investigate-preliminary-notice-ip-targets": "A guia Informações da conta não inclui nenhuma informação sobre IPs. Veja os <span class=\"plainlinks\">[$1 IPs & User agents tab]</span> para esses detalhes.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Bloqueado",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|edição|edições}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Não bloqueado",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Edições",
+ "checkuser-investigate-preliminary-table-header-groups": "Grupos",
+ "checkuser-investigate-preliminary-table-header-name": "Nome de usuário",
+ "checkuser-investigate-preliminary-table-header-registration": "Data anexada",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wiki não encontrada",
+ "checkuser-investigate-filters-legend": "Filtros",
+ "checkuser-investigate-filters-exclude-targets-label": "Ocultar os seguintes usuários ou IPs",
+ "checkuser-investigate-timeline-notice-no-results": "Não há resultados: não houve atividade registrada desses usuários ou IPs nos últimos 90 dias",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Não há resultados correspondentes a esses critérios de filtragem. Tente remover alguns filtros para ampliar a pesquisa.",
+ "checkuser-investigate-compare-copy-button-label": "Mostrar wikitexto",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Verificação de proxy",
+ "checkuser-investigate-compare-copy-message-label": "Would you like to copy this information as a Wikitext table?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Devido a limitações técnicas, alcançamos o número de registros que podem ser apresentados. Os dados retornados para os seguintes destinos estão incompletos: $1. Tente usar menos destinos, janela de tempo menor ou intervalos de IP mais estreitos.",
+ "checkuser-investigate-compare-notice-no-results": "Não há resultados: não houve edições desses usuários ou IPs nos últimos 90 dias",
+ "checkuser-investigate-compare-notice-no-results-filters": "Não há resultados correspondentes a esses critérios de filtragem. Tente remover alguns filtros para ampliar a pesquisa.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Mostrar todos os IPs deste usuário",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Mostrar todos os usuários neste IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Adicionar este IP à investigação",
+ "checkuser-investigate-compare-table-button-checks-label": "Verificações",
+ "checkuser-investigate-compare-table-button-contribs-label": "Contribuições",
+ "checkuser-investigate-compare-table-button-filter-label": "Filtrar a partir dos resultados",
+ "checkuser-investigate-compare-table-cell-unregistered": "Não registrados",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|edição|edições}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 de todos os usuários)</i>",
+ "checkuser-investigate-compare-table-header-username": "Nome de usuário",
+ "checkuser-investigate-compare-table-header-activity": "Intervalo de data",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Agente de usuário",
+ "checkuser-investigate-subtitle-link-restart-tour": "Reiniciar tour",
+ "checkuser-investigate-tour-targets-title": "Verificando vários usuários e IPs?",
+ "checkuser-investigate-tour-targets-desc": "Adicionar até $1 {{PLURAL:$1|Nome de usuário ou IP|Nomes de usuário ou IPs}} e obtenha todas as informações em um só lugar. Não se preocupe, criaremos um registro de Verificar usuário separado para cada um deles.",
+ "checkuser-investigate-tour-useragents-title": "Correspondente a agentes do usuário?",
+ "checkuser-investigate-tour-useragents-desc": "Passe o mouse sobre uma célula para destacar todas as outras linhas que possuem os mesmos dados. Clique no ícone de alfinete para manter o destaque à medida que avança nos dados.",
+ "checkuser-investigate-tour-addusertargets-title": "Precisa de mais contexto?",
+ "checkuser-investigate-tour-addusertargets-desc": "Clique para ver todos os outros usuários no IP. Você também pode fazer isso para os usuários e ver todos os IPs que eles estão usando. Criaremos automaticamente um item de registro de verificação de usuário para você.",
+ "checkuser-investigate-tour-filterip-title": "Restringindo sua investigação?",
+ "checkuser-investigate-tour-filterip-desc": "Remova a confusão filtrando nomes de usuários, IPs ou agentes de usuários. Deseja os dados de volta? Use o painel de filtros na parte superior para remover os filtros.",
+ "checkuser-investigate-tour-block-title": "Deseja bloquear?",
+ "checkuser-investigate-tour-block-desc": "Permite selecionar os usuários que você deseja bloquear e, em seguida, leva você ao formulário do bloco para escolher o bloco apropriado.",
+ "checkuser-investigate-tour-copywikitext-title": "Deseja copiar os dados?",
+ "checkuser-investigate-tour-copywikitext-desc": "Copie a tabela de comparação com um clique e leve-a para o CUWiki. Observe que você está apenas copiando o que é visível e não todas as páginas da investigação."
}
diff --git a/CheckUser/i18n/pt.json b/CheckUser/i18n/pt.json
index 3fa72c02..ea231ff5 100644
--- a/CheckUser/i18n/pt.json
+++ b/CheckUser/i18n/pt.json
@@ -1,21 +1,26 @@
{
"@metadata": {
"authors": [
+ "Athena in Wonderland",
"Dicionarista",
+ "Eduardo Addad de Oliveira",
+ "Fúlvio",
"Hamilton Abreu",
"Luckas",
"Malafaya",
+ "Mansil",
+ "Mansil alfalb",
+ "RadiX",
"Sir Lestaty de Lioncourt",
- "Waldir",
- "555",
+ "Tks4Fish",
"Vitorvicentevalente",
- "Fúlvio",
- "RadiX",
- "Athena in Wonderland"
+ "Waldir",
+ "Waldyrious",
+ 555
]
},
"checkuser-summary": "Esta ferramenta varre as mudanças recentes para obter os endereços IP de um utilizador ou para apresentar os dados de edições/utilizadores para um determinado IP.\nOs utilizadores e edições de um determinado IP, podem ser obtidos através de cabeçalhos XFF, acrescentando \"/xff\" no final do endereço.\nSão suportados endereços IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128).\nPor motivos de desempenho não serão fornecidas mais do que 5000 edições.\nO uso desta ferramenta deverá respeitar as normas e recomendações.",
- "checkuser-desc": "Concede a utilizadores com a permissão apropriada a possibilidade de verificar os endereços IP e outra informação de um utilizador",
+ "checkuser-desc": "Concede a utilizadores devidamente autorizados a possibilidade de verificar os endereços IP e outra informação dos utilizadores",
"checkuser-logcase": "As buscas nos registos distinguem maiúsculas de minúsculas.",
"checkuser": "Verificação de utilizadores",
"checkuserlog": "Registo das verificações de utilizadores",
@@ -69,7 +74,6 @@
"checkuser-block-noreason": "Tem de especificar um motivo para os bloqueios.",
"checkuser-centralauth-multilock": "Bloquear contas globais selecionadas",
"checkuser-noreason": "Tem de fornecer um motivo para esta pesquisa.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nova conta|novas contas}}",
"checkuser-too-many": "Há demasiados resultados (segundo estimativa da pesquisa); por favor, restrinja o CIDR.\nAqui estão os endereços IP utilizados (5000 no máx., ordenados por endereço):",
"checkuser-user-nonexistent": "O utilizador especificado não existe.",
"checkuser-search": "Pesquisar entradas do registo de verificações de utilizadores",
@@ -82,10 +86,10 @@
"checkuser-showmain": "Mudar para o formulário principal da verificação de utilizadores",
"checkuser-limited": "'''Estes resultados foram truncados por motivos de desempenho.'''",
"checkuser-log-entry-userips": "$3, $1 obteve endereços IP de $2",
- "checkuser-log-entry-ipedits": "$3, $1 obteve edições de $2",
- "checkuser-log-entry-ipusers": "$3, $1 obteve utilizadores de $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 obteve edições do XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 obteve utilizadores do XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 obteve edições de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 obteve utilizadores de <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 obteve edições do XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 obteve utilizadores do XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 obteve edições de $2",
"checkuser-autocreate-action": "foi criada automaticamente",
"checkuser-create-action": "foi criada",
@@ -94,26 +98,29 @@
"checkuser-token-fail": "Falha na sessão. Por favor, tente novamente.",
"checkuser-login-failure": "Não foi possível entrar na wiki {{SITENAME}} como $1",
"checkuser-login-success": "Entrou na wiki {{SITENAME}} como $1",
- "apihelp-query+checkuser-description": "Verificar que endereços IP são usados por determinado nome de utilizador ou que nomes de utilizador são usados por um determinado endereço IP.",
- "apihelp-query+checkuser-summary": "Verificar que endereços IP são usados por determinado nome de utilizador ou que nomes de utilizador são usados por um determinado endereço IP.",
- "apihelp-query+checkuser-param-request": "Tipo do pedido de verificação de utilizadores:\n;userips:Obter endereço IP do utilizador alvo.\n;edits:Obter alterações do endereço IP ou gama IP alvo.\n;ipusers:Obter utilizadores do endereço IP ou gama IP alvo.",
- "apihelp-query+checkuser-param-target": "Nome de utilizador, endereço IP, ou gama CIDR a verificar",
- "apihelp-query+checkuser-param-reason": "Motivo da verificação.",
- "apihelp-query+checkuser-param-limit": "Limite de linhas.",
- "apihelp-query+checkuser-param-timecond": "Limite temporal dos dados de utilizador (como \"-2 weeks\" ou \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Usar dados XFF em vez do endereço IP.",
- "apihelp-query+checkuser-example-1": "Verificar o endereço IP de [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Verificar edições de 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Obter entradas do registo de verificação de utilizadores.",
- "apihelp-query+checkuserlog-summary": "Obter entradas do registo de verificação de utilizadores.",
- "apihelp-query+checkuserlog-param-user": "Nome de utilizador do pedido de verificação de utilizadores.",
- "apihelp-query+checkuserlog-param-target": "Utilizador verificado, endereço IP ou gama CIDR.",
- "apihelp-query+checkuserlog-param-limit": "Limite de linhas.",
- "apihelp-query+checkuserlog-param-from": "A data e hora a partir da qual será começada a enumeração.",
- "apihelp-query+checkuserlog-param-to": "A data e hora na qual será parada a enumeração.",
- "apihelp-query+checkuserlog-example-1": "Mostrar verificações de [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Mostrar verificações de 192.0.2.0/24 após 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Tem de definir um motivo para a verificação.",
- "apierror-checkuser-timelimit": "Tem de usar um limite temporal correto (como \"-2 weeks\" ou \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "Modo de pedido inválido"
+ "checkuser-investigate": "Investigar",
+ "checkuser-investigate-indicator-logs": "Registos",
+ "checkuser-investigate-legend": "Pesquisar nomes de utilizador, endereços IP ou gamas IP",
+ "checkuser-investigate-tab-timeline": "Linha cronológica",
+ "checkuser-investigate-targets-label": "Nomes de utilizador e endereços IP",
+ "checkuser-investigate-targets-placeholder": "Nome de utilizador ou 1.1.1.1",
+ "checkuser-investigate-reason-label": "Motivo",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Bloqueado",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|edição|edições}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Não bloqueado",
+ "checkuser-investigate-preliminary-table-header-blocked": "Estado",
+ "checkuser-investigate-preliminary-table-header-editcount": "Edições",
+ "checkuser-investigate-preliminary-table-header-groups": "Grupos",
+ "checkuser-investigate-preliminary-table-header-name": "Nome de utilizador",
+ "checkuser-investigate-preliminary-table-header-registration": "Data de anexação",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-filters-legend": "Filtros",
+ "checkuser-investigate-filters-exclude-targets-label": "Ocultar os seguintes utilizadores ou IPs",
+ "checkuser-investigate-compare-copy-button-label": "Mostrar texto wiki",
+ "checkuser-investigate-compare-table-cell-unregistered": "Não registado",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|edição|edições}}</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 de todos os utilizadores)</i>",
+ "checkuser-investigate-compare-table-header-username": "Nome de utilizador",
+ "checkuser-investigate-compare-table-header-activity": "Intervalo de datas",
+ "checkuser-investigate-compare-table-header-ip": "IP"
}
diff --git a/CheckUser/i18n/qqq.json b/CheckUser/i18n/qqq.json
index 830ec9b8..0ea07fc8 100644
--- a/CheckUser/i18n/qqq.json
+++ b/CheckUser/i18n/qqq.json
@@ -1,31 +1,36 @@
{
"@metadata": {
"authors": [
+ "Amire80",
+ "Beta16",
+ "Catrope",
"Darth Kule",
"Dferg",
+ "FF11",
"Fryed-peach",
"Jon Harald Søby",
"Kwj2772",
"Lejonel",
+ "Liuxinyu970226",
"Lloffiwr",
"MarcoAurelio",
+ "Matma Rex",
+ "McDutchie",
"Meno25",
"Mormegil",
+ "Nemo bis",
"Purodha",
+ "Purodha Blissenbach",
"Raymond",
+ "Revi",
+ "Robby",
"Shirayuki",
"Siddhartha Ghai",
"Siebrand",
"Slomox",
"Tgr",
"The Evil IP address",
- "Umherirrender",
- "Liuxinyu970226",
- "Nemo bis",
- "Revi",
- "Beta16",
- "McDutchie",
- "Purodha Blissenbach"
+ "Umherirrender"
]
},
"checkuser-summary": "Explanation of CheckUser tool. See [[mw:Extension:CheckUser#Basic_interface|screenshot titled 'Basic CheckUser interface']].\n\nParameters:\n* $1 - an integer. default value: 16\n* $2 - an integer. default value: 32",
@@ -72,10 +77,11 @@
"checkuser-localonly": "Used as a flag in [[Special:CheckUser]].",
"checkuser-massblock": "Used as fieldset label.\n\nThis message is followed by the following message:\n* {{msg-mw|Checkuser-massblock-text}}\n{{Identical|Block selected users}}",
"checkuser-massblock-text": "Used as intro text for the form {{msg-mw|checkuser-massblock}}.",
- "checkuser-blockemail": "Used as a label for a checkbox asking to block email access.",
- "checkuser-blocktalk": "Used as a label for a checkbox asking to block talk page access.",
- "checkuser-blocktag": "[[File:Special-checkuser-get-users en.png|thumb|Checkuser interface]]Used as checkbox label in [[Special:CheckUser]].\n\nThis message is followed by \"tag\" input box. The input box is for text which replaces the entire wikitext of the concerned page.\n\nSee also:\n* {{msg-mw|Checkuser-blocktag-talk}}",
- "checkuser-blocktag-talk": "[[File:Special-checkuser-get-users en.png|thumb|Checkuser interface]]Used as checkbox label in [[Special:CheckUser]].\n\nThis message is followed by \"talktag\" input box. The input box is for text which replaces the entire wikitext of the concerned page.\n\nSee also:\n* {{msg-mw|Checkuser-blocktag}}",
+ "checkuser-blockemail": "[[File:Checkuser - get users - 2020-05-29.png|thumb|Checkuser interface]]\nUsed as a label for a checkbox asking to block email access.\n\nAppears as part of a list with these messages:\n* {{msg-mw|Checkuser-blocktag}}\n* {{msg-mw|Checkuser-blocktag-talk}}\n* {{msg-mw|Checkuser-blocktalk}}\n* {{msg-mw|Checkuser-blockemail}}\n* {{msg-mw|Checkuser-reblock}}",
+ "checkuser-blocktalk": "Used as a label for a checkbox asking to block talk page access.\n[[File:Checkuser - get users - 2020-05-29.png|thumb|Checkuser interface]]\nAppears as part of a list with these messages:\n* {{msg-mw|Checkuser-blocktag}}\n* {{msg-mw|Checkuser-blocktag-talk}}\n* {{msg-mw|Checkuser-blocktalk}}\n* {{msg-mw|Checkuser-blockemail}}\n* {{msg-mw|Checkuser-reblock}}",
+ "checkuser-blocktag": "[[File:Checkuser - get users - 2020-05-29.png|thumb|Checkuser interface]]\nUsed as checkbox label in [[Special:CheckUser]].\n\nThis message is followed by \"tag\" input box. The input box is for text which replaces the entire wikitext of the concerned page.\n\nAppears as part of a list with these messages:\n* {{msg-mw|Checkuser-blocktag}}\n* {{msg-mw|Checkuser-blocktag-talk}}\n* {{msg-mw|Checkuser-blocktalk}}\n* {{msg-mw|Checkuser-blockemail}}\n* {{msg-mw|Checkuser-reblock}}",
+ "checkuser-blocktag-talk": "[[File:Checkuser - get users - 2020-05-29.png|thumb|Checkuser interface]]\nUsed as checkbox label in [[Special:CheckUser]].\n\nThis message is followed by \"talktag\" input box. The input box is for text which replaces the entire wikitext of the concerned page.\n\nAppears as part of a list with these messages:\n* {{msg-mw|Checkuser-blocktag}}\n* {{msg-mw|Checkuser-blocktag-talk}}\n* {{msg-mw|Checkuser-blocktalk}}\n* {{msg-mw|Checkuser-blockemail}}\n* {{msg-mw|Checkuser-reblock}}",
+ "checkuser-reblock": "[[File:Checkuser - get users - 2020-05-29.png|thumb|Checkuser interface]]\nUsed as checkbox label in [[Special:CheckUser]].\n\nThis message is followed by \"talktag\" input box. The input box is for text which replaces the entire wikitext of the concerned page.\n\nAppears as part of a list with these messages:\n* {{msg-mw|Checkuser-blocktag}}\n* {{msg-mw|Checkuser-blocktag-talk}}\n* {{msg-mw|Checkuser-blocktalk}}\n* {{msg-mw|Checkuser-blockemail}}\n* {{msg-mw|Checkuser-reblock}}",
"checkuser-massblock-commit": "Used as Submit button text in [[Special:CheckUser]].\n{{Identical|Block selected users}}",
"checkuser-block-success": "Used as success message in [[Special:CheckUser]].\n\nParameters:\n* $1 - a list of one or more usernames\n* $2 - the number of usernames in <code>$1</code>\n\nSee also:\n* {{msg-mw|Checkuser-block-failure}}\n* {{msg-mw|Checkuser-block-limit}}\n* {{msg-mw|Checkuser-block-noreason}}",
"checkuser-block-failure": "Used as failure message in [[Special:CheckUser]].\n\nSee also:\n* {{msg-mw|Checkuser-block-success}}\n* {{msg-mw|Checkuser-block-limit}}\n* {{msg-mw|Checkuser-block-noreason}}",
@@ -83,8 +89,7 @@
"checkuser-block-noreason": "Used as failure message in [[Special:CheckUser]].\n\nSee also:\n* {{msg-mw|Checkuser-block-success}}\n* {{msg-mw|Checkuser-block-failure}}\n* {{msg-mw|Checkuser-block-limit}}",
"checkuser-centralauth-multilock": "Label of link to Special:MultiLock shown on Special:CheckUser's block form.\n\nCf. {{msg-mw|multilock}}.",
"checkuser-noreason": "Used as error message in [[Special:CheckUser]].",
- "checkuser-accounts": "Used in Special:CheckUser. Parameters:\n* $1 - number of accounts",
- "checkuser-too-many": "Used in [[Special:CheckUser]].\n\nThis message is followed by a list of IPs that have edits.\n\nIf the number of IPs is 5000 or more, the following message is shown:\n* {{msg-mw|checkuser-limited}}",
+ "checkuser-too-many": "Used in [[Special:CheckUser]].\n\nThis message is followed by a list of IPs that have edits.\n\nIf the number of IPs also exceeds the limit, the following message is shown:\n* {{msg-mw|checkuser-limited}}\n\nParameters:\n* $1 - the maximum number of results",
"checkuser-user-nonexistent": "Used as error message in [[Special:CheckUserLog]].",
"checkuser-search": "Heading of fieldset on log of CheckUser searches. See screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]",
"checkuser-search-submit": "Button label on log of CheckUser searches. See screenshot \"[[mw:Extension:CheckUser#Basic_interface|Example log]]\".\n{{Identical|Search}}",
@@ -105,33 +110,103 @@
"checkuser-create-action": "Text of the event displayed in the CheckUser results. Indicates creation of the user.",
"checkuser-email-action": "Logged text when a user sends an e-mail. Probably preceded by the name of the checkuser.\n\nParameters:\n* $1 - a salted MD5 hash for the user an email was sent to",
"checkuser-reset-action": "Logged text when a user resets a password. Parameters:\n* $1 - the username for which the password was reset. Can be used for GENDER.",
- "checkuser-userlinks-ip": "Links shown next to an IP address in a CheckUser result entry. $1 - IP address\n\nSee also:\n*{{msg-mw|Signature}}\n*{{msg-mw|Checkuser-userlinks}}",
+ "checkuser-userlinks-ip": "{{notranslate}}\nLinks shown next to an IP address in a CheckUser result entry. $1 - IP address\n\nSee also:\n*{{msg-mw|Signature}}\n*{{msg-mw|Checkuser-userlinks}}",
"checkuser-toollinks": "{{notranslate}}\nParameters:\n* $1 - IP address",
"checkuser-token-fail": "Error message shown when the CSRF token does not match the current session.",
"checkuser-login-failure": "Log entry shown in CheckUser logs for failed login attemps",
"checkuser-login-success": "Log entry shown in CheckUser logs for successful login attempts",
"group-checkuser.css": "{{doc-group|checkuser|css}}",
"group-checkuser.js": "{{doc-group|checkuser|js}}",
- "apihelp-query+checkuser-description": "{{doc-apihelp-description|query+checkuser}}",
- "apihelp-query+checkuser-summary": "{{doc-apihelp-summary|query+checkuser}}",
- "apihelp-query+checkuser-param-request": "{{doc-apihelp-param|query+checkuser|request}}",
- "apihelp-query+checkuser-param-target": "{{doc-apihelp-param|query+checkuser|target}}",
- "apihelp-query+checkuser-param-reason": "{{doc-apihelp-param|query+checkuser|reason}}",
- "apihelp-query+checkuser-param-limit": "{{doc-apihelp-param|query+checkuser|limit}}",
- "apihelp-query+checkuser-param-timecond": "{{doc-important|Do not translate \"-2 weeks\" or \"2 weeks ago\". It must be in [http://www.php.net/strtotime original format].}}\n----\n{{doc-apihelp-param|query+checkuser|timecond}}",
- "apihelp-query+checkuser-param-xff": "{{doc-apihelp-param|query+checkuser|xff}}",
- "apihelp-query+checkuser-example-1": "{{doc-apihelp-example|query+checkuser}}",
- "apihelp-query+checkuser-example-2": "{{doc-apihelp-example|query+checkuser}}",
- "apihelp-query+checkuserlog-description": "{{doc-apihelp-description|query+checkuserlog}}",
- "apihelp-query+checkuserlog-summary": "{{doc-apihelp-summary|query+checkuserlog}}",
- "apihelp-query+checkuserlog-param-user": "{{doc-apihelp-param|query+checkuserlog|user}}",
- "apihelp-query+checkuserlog-param-target": "{{doc-apihelp-param|query+checkuserlog|target}}",
- "apihelp-query+checkuserlog-param-limit": "{{doc-apihelp-param|query+checkuserlog|limit}}",
- "apihelp-query+checkuserlog-param-from": "{{doc-apihelp-param|query+checkuserlog|from}}",
- "apihelp-query+checkuserlog-param-to": "{{doc-apihelp-param|query+checkuserlog|to}}",
- "apihelp-query+checkuserlog-example-1": "{{doc-important|Do not translate \"User:Example\".}}\n{{doc-apihelp-example|query+checkuserlog}}",
- "apihelp-query+checkuserlog-example-2": "{{doc-apihelp-example|query+checkuserlog}}",
- "apierror-checkuser-missingsummary": "{{doc-apierror}}",
- "apierror-checkuser-timelimit": "{{doc-apierror}}\n{{doc-important|Do not translate \"-2 weeks\" or \"2 weeks ago\". It must be in [http://www.php.net/strtotime original format].}}",
- "apierror-checkuser-invalidmode": "{{doc-apierror}}"
+ "checkuser-link-investigate-label": "Label for a link to [[Special:Investigate]] from [[Special:CheckUser]].",
+ "checkuser-investigateblock": "{{doc-special|InvestigateBlock}}",
+ "checkuser-investigateblock-target": "Label for a section of the form on [[Special:InvestigateBlock]]",
+ "checkuser-investigateblock-actions": "Label for a section of the form on [[Special:InvestigateBlock]]",
+ "checkuser-investigateblock-reason": "Label for a text input in the [[Special:InvestigateBlock]] form\n{{identical|Reason}}",
+ "checkuser-investigateblock-options": "Label for a section of the form on [[Special:InvestigateBlock]]",
+ "checkuser-investigateblock-email-label": "Label for a checkbox in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-usertalk-label": "Label for a checkbox in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-reblock-label": "Label for a checkbox in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-notice-user-page-label": "Label for a checkbox in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-notice-talk-page-label": "Label for a checkbox in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-notice-position-label": "Label for a select widget in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-notice-text-label": "Label for a select widget in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-notice-append": "Label for an option in a select widget in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-notice-prepend": "Label for an option in a select widget in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-notice-replace": "Label for an option in a select widget in the [[Special:InvestigateBlock]] form",
+ "checkuser-investigateblock-failure": "Message shown after submitting the [[Special:InvestigateBlock]] form if no blocks were made",
+ "checkuser-investigateblock-success": "Message shown after submitting the [[Special:InvestigateBlock]] form if blocks were made",
+ "checkuser-investigateblock-notices-failed": "Message shown after submitting the [[Special:InvestigateBlock]] form if blocks were made but notices were not added",
+ "checkuser-investigate-log": "{{doc-special|InvestigateLog}}\nThe special page is a new version of [[Special:CheckUserLog]].",
+ "checkuser-investigate-log-entry": "This is an entry in the checkuser log when a checkuser starts an investigation.\n\nParameters:\n* $1 - name of checkuser\n* $2 - name of the user or ip who is the target of the investigation\n* $3 - a formatted timestamp of the event\n* $4 - the reason why the investigation was initiated",
+ "checkuser-investigate-log-empty": "Used in [[Special:InvestigateLog]] if there are no log entries to display.",
+ "checkuser-investigate-log-subtitle": "Page subtitle used in [[Special:InvestigateLog]] linking to [[Special:Investigate]].",
+ "checkuser-investigate": "{{doc-special|Investigate}}\nThe special page is a new version of [[Special:CheckUser]].",
+ "checkuser-investigate-page-subtitle": "Used as the page subtitle displaying the users under investigation.\n\nParameters:\n* $1 - a list of usernames selected for the investigation",
+ "checkuser-investigate-subtitle-block-button-label": "Label for a button in [[Special:Investigate]].\n{{identical|Block}}",
+ "checkuser-investigate-subtitle-cancel-button-label": "Label for a button in [[Special:Investigate]].\n{{identical|Cancel}}",
+ "checkuser-investigate-subtitle-continue-button-label": "Label for a button linking to [[Special:InvestigateBlock]].\n{{identical|Continue}}",
+ "checkuser-investigate-indicator-new-investigation": "Label for a button linking to [[Special:Investigate]].",
+ "checkuser-investigate-indicator-logs": "Label for a button linking to [[Special:InvestigateLog]].",
+ "checkuser-investigate-legend": "Heading for the [[Special:Investigate]] search form.",
+ "checkuser-investigate-notice-no-results": "Message shown in [[Special:Investigate]] when there are no results for an Account information investigation.",
+ "checkuser-investigate-tab-preliminary-check": "Label for the Account information tab.",
+ "checkuser-investigate-tab-compare": "Label for the IPs & User agents tab.",
+ "checkuser-investigate-tab-timeline": "Label for the Timeline tab.\n{{Identical|Timeline}}",
+ "checkuser-investigate-targets-label": "Label for a field in the [[Special:Investigate]] search form.",
+ "checkuser-investigate-targets-placeholder": "Placeholder text for a field in the [[Special:Investigate]] search form.",
+ "checkuser-investigate-duration-label": "Label for a field in the [[Special:Investigate]] form.",
+ "checkuser-investigate-duration-option-all": "Option in the duration field on [[Special:Investigate]]",
+ "checkuser-investigate-duration-option-1w": "Option in the duration field on [[Special:Investigate]]",
+ "checkuser-investigate-duration-option-2w": "Option in the duration field on [[Special:Investigate]]",
+ "checkuser-investigate-duration-option-30d": "Option in the duration field on [[Special:Investigate]]",
+ "checkuser-investigate-reason-label": "Label for a field in the [[Special:Investigate]] search form.",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Message shown if an investigation involves an IP address.\n\n\"Account information\" is {{msg-mw|Checkuser-investigate-tab-preliminary-check}}\n\n\"IPs & User agents\" is {{msg-mw|Checkuser-investigate-tab-compare}}",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Entry for a table cell in [[Special:Investigate]].",
+ "checkuser-investigate-preliminary-table-cell-edits": "Entry for a table cell in [[Special:Investigate]].\n\nParameters:\n* $1 - total number of edits by the user on the respective wiki",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Entry for a table cell in [[Special:Investigate]].",
+ "checkuser-investigate-preliminary-table-header-blocked": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-preliminary-table-header-editcount": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-preliminary-table-header-groups": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-preliminary-table-header-name": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-preliminary-table-header-registration": "Label for a table header in [[Special:Investigate]]. Means \"the day on which (the account) was attached\".",
+ "checkuser-investigate-preliminary-table-header-wiki": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Entry for a table cell in [[Special:Investigate]].",
+ "checkuser-investigate-filters-legend": "Heading for the filters form on [[Special:Investigate]].",
+ "checkuser-investigate-filters-exclude-targets-label": "Label for the hide targets filter on [[Special:Investigate]].",
+ "checkuser-investigate-timeline-notice-no-results": "Message shown in [[Special:Investigate]] when there are no results for a Timeline investigation.",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Message shown in [[Special:Investigate]] when there are no results for a Timeline investigation that has filters.",
+ "checkuser-investigate-compare-copy-button-label": "Label for a button in [[Special:Investigate]]",
+ "checkuser-investigate-compare-toollinks": "{{notranslate}}\nParameters:\n* $1 - IP address",
+ "checkuser-investigate-compare-toollinks-whois": "{{optional}}\nWHOIS/RDNS tool link. Label for an option in a dropdown list.\n\nSee also {{msg-mw|checkuser-investigate-compare-toollinks}}",
+ "checkuser-investigate-compare-toollinks-ipcheck": "IP Check tool link. Label for an option in a dropdown list.\n\nSee also {{msg-mw|checkuser-investigate-compare-toollinks}}",
+ "checkuser-investigate-compare-copy-message-label": "Label for a banner in [[Special:Investigate]]",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Warning shown in [[Special:Investigate]].\n\nParameters:\n* $1 - invalid user names",
+ "checkuser-investigate-compare-notice-no-results": "Message shown in [[Special:Investigate]] when there are no results for an IPs & User agents investigation.",
+ "checkuser-investigate-compare-notice-no-results-filters": "Message shown in [[Special:Investigate]] when there are no results for an IPs & User agents investigation that has filters.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Label for a button inside a table cell in [[Special:Investigate]]",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Label for a button inside a table cell in [[Special:Investigate]]",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Label for a button inside a table cell in [[Special:Investigate]]",
+ "checkuser-investigate-compare-table-button-checks-label": "Label for a button inside a table cell in [[Special:Investigate]]",
+ "checkuser-investigate-compare-table-button-contribs-label": "Label for a button inside a table cell in [[Special:Investigate]].\n\n{{Identical|Contributions}}",
+ "checkuser-investigate-compare-table-button-filter-label": "Label for a button inside a table cell in [[Special:Investigate]]",
+ "checkuser-investigate-compare-table-cell-unregistered": "Entry for a table cell in [[Special:Investigate]]. Refers to an unregistered user. Shown in a table like this:\n\n{| class=\"wikitable\"\n|-\n! Username !! IP\n|-\n| UserA || 1.2.3.4\n|-\n| UserB || 1.2.3.5\n|-\n| Unregistered || 1.2.3.6\n|-\n| UserC || 1.2.3.7\n|}",
+ "checkuser-investigate-compare-table-cell-edits": "Entry for a table cell in [[Special:Investigate]].\n\nParameters:\n* $1 - total number of edits by a registered user from the respective IP and User Agent",
+ "checkuser-investigate-compare-table-cell-other-edits": "Entry for a table cell in [[Special:Investigate]].\n\nParameters:\n* $1 - total number of edits from the respective IP",
+ "checkuser-investigate-compare-table-header-username": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-compare-table-header-activity": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-compare-table-header-ip": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-compare-table-header-useragent": "Label for a table header in [[Special:Investigate]].",
+ "checkuser-investigate-subtitle-link-restart-tour": "Text for the link in the subtitle of [[Special:Investigate]] that will restart the guided tour.",
+ "checkuser-investigate-tour-targets-title": "Title of targets step in the investigate form guided tour.",
+ "checkuser-investigate-tour-targets-desc": "Description of targets step in the investigate form guided tour.\n\nParameters:\n* $1 - number of targets allowed on the [[Special:Investigate]] form.",
+ "checkuser-investigate-tour-useragents-title": "Title of useragents step in investigate guided tour.",
+ "checkuser-investigate-tour-useragents-desc": "Description of useragents step in investigate guided tour.",
+ "checkuser-investigate-tour-addusertargets-title": "Title of addusertargets step in investigate guided tour.",
+ "checkuser-investigate-tour-addusertargets-desc": "Description of addusertargets step in investigate guided tour.",
+ "checkuser-investigate-tour-filterip-title": "[[File:Screenshot of Special-Investigate Guided Tour - Filter.png|thumb|Form where string is used in English.]] Title of filterip step in investigate guided tour.",
+ "checkuser-investigate-tour-filterip-desc": "[[File:Screenshot of Special-Investigate Guided Tour - Filter.png|thumb|Form where string is used in English.]]\nDescription of filterip step in investigate guided tour. The title of \"Filters panel\" is {{msg-mw|Checkuser-investigate-filters-legend}}.",
+ "checkuser-investigate-tour-block-title": "Title of block step in investigate guided tour.",
+ "checkuser-investigate-tour-block-desc": "Description of block step in investigate guided tour.",
+ "checkuser-investigate-tour-copywikitext-title": "Title of copywikitext step in investigate guided tour.",
+ "checkuser-investigate-tour-copywikitext-desc": "Description of copywikitext step in investigate guided tour."
}
diff --git a/CheckUser/i18n/rif.json b/CheckUser/i18n/rif.json
index f3427ded..c74834af 100644
--- a/CheckUser/i18n/rif.json
+++ b/CheckUser/i18n/rif.json
@@ -1,8 +1,8 @@
{
"@metadata": {
"authors": [
- "Jose77",
- "Amara-Amaziɣ"
+ "Amara-Amaziɣ",
+ "Jose77"
]
},
"checkuser-search": "Tarzzut",
diff --git a/CheckUser/i18n/ro.json b/CheckUser/i18n/ro.json
index 3e14ce74..23306845 100644
--- a/CheckUser/i18n/ro.json
+++ b/CheckUser/i18n/ro.json
@@ -2,6 +2,7 @@
"@metadata": {
"authors": [
"AdiJapan",
+ "Andrei Stroe",
"Emily",
"Firilacroco",
"KlaudiuMihaila",
@@ -26,7 +27,7 @@
"grouppage-checkuser": "{{ns:project}}:Checkuser",
"checkuser-reason": "Motiv:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Arată jurnal",
+ "checkuser-showlog": "Comută la jurnalul CheckUser",
"checkuser-query": "Interoghează schimbările recente",
"checkuser-target": "Adresă IP sau nume de utilizator:",
"checkuser-users": "Arată utilizatorii",
@@ -60,10 +61,9 @@
"checkuser-block-limit": "Prea mulți utilizatori selectați.",
"checkuser-block-noreason": "Trebuie să specificați un motiv pentru blocări.",
"checkuser-noreason": "Trebuie să specifici un motiv pentru această interogare.",
- "checkuser-accounts": "$1 {{PLURAL:$1|cont nou|conturi noi}}",
- "checkuser-too-many": "Prea multe rezultate (după estimarea interogării), vă rugăm să limitați CIDR.\nIată IP-urile folosite (maxim 5000, sortate după adresă):",
+ "checkuser-too-many": "Prea multe rezultate (conform estimării interogării), vă rugăm să limitați CIDR.\nIată IP-urile folosite (maxim 5000, sortate după adresă):",
"checkuser-user-nonexistent": "Utilizatorul specificat nu există.",
- "checkuser-search": "Caută",
+ "checkuser-search": "Caută înregistrări din jurnalul check user",
"checkuser-search-submit": "Caută",
"checkuser-search-initiator": "inițiator",
"checkuser-search-target": "destinație",
diff --git a/CheckUser/i18n/roa-tara.json b/CheckUser/i18n/roa-tara.json
index 4f4b1c54..ac428695 100644
--- a/CheckUser/i18n/roa-tara.json
+++ b/CheckUser/i18n/roa-tara.json
@@ -60,8 +60,7 @@
"checkuser-block-noreason": "Tu à dà 'nu mutive pe le blocche.",
"checkuser-centralauth-multilock": "Blocche le cunde scacchiate",
"checkuser-noreason": "Tu à dà 'nu mutive pe st'inderrogazione.",
- "checkuser-accounts": "$1 {{PLURAL:$1|cunde utende|cunde utinde}} nuève",
- "checkuser-too-many": "Stonne assaje resultate (seconne 'a stime fatte de l'inderrogazzione), pe' piacere restringe 'u CIDR.\nAqquà stonne le IP ausate (5000 masseme, ordenate pe' inderizze):",
+ "checkuser-too-many": "Stonne assaje resultate (seconne 'a stime fatte de l'inderrogazzione), pe' piacere restringe 'u CIDR.\nAqquà stonne le IP ausate ($1 masseme, ordenate pe' inderizze):",
"checkuser-user-nonexistent": "L'utende specificate non g'esiste.",
"checkuser-search": "Cirche le vôsce jndr'à l'archivije ''check user''",
"checkuser-search-submit": "Cirche",
@@ -73,10 +72,10 @@
"checkuser-showmain": "Veje sus a 'u module prengepàle de CheckUser",
"checkuser-limited": "'''Chiste resultate onne state tagghiate pe mutive de performance.'''",
"checkuser-log-entry-userips": "$3, $1 ha pigghiate le indirizze IP pe $2",
- "checkuser-log-entry-ipedits": "$3, $1 ha pigghiate le cangiaminde pe $2",
- "checkuser-log-entry-ipusers": "$3, $1 ha pigghiate le utinde pe $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 ha pigghiate le cangiaminde pe XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 ha pigghiate le utinde pe XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 ha pigghiate le cangiaminde pe <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 ha pigghiate le utinde pe <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 ha pigghiate le cangiaminde pe XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 ha pigghiate le utinde pe XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 ha pigghiate le cangiaminde pe $2",
"checkuser-autocreate-action": "ha state ccrejete automaticamende",
"checkuser-create-action": "ha state ccrejate",
@@ -85,26 +84,12 @@
"checkuser-token-fail": "Sessione fallite. Pruève arrete.",
"checkuser-login-failure": "Non g'è trasute jndr'à {{SITENAME}} cumme $1",
"checkuser-login-success": "E' trasute jndr'à {{SITENAME}} cumme $1",
- "apihelp-query+checkuser-description": "Verifiche quale IP so ausate da 'nu certe nome utende o quale nome de utinde so ausate da 'nu certe IP.",
- "apihelp-query+checkuser-summary": "Verifiche quale IP so ausate da 'nu certe nome utende o quale nome de utinde so ausate da 'nu certe IP.",
- "apihelp-query+checkuser-param-request": "Tipe de richieste de CheckUser:\n;userips:Pigghie l'indirizze IP de l'utende de destinazione.\n;edits:Pigghie le cangiaminde da l'indirizze IP de destinazione o de l'indervalle.\n;ipusers:Pigghie le utinde da l'indirizze IP de destinazione o de l'indervalle..",
- "apihelp-query+checkuser-param-target": "Nome de l'utende, indirizze IP o indervalle CIDR da verificà.",
- "apihelp-query+checkuser-param-reason": "Mutive d'u condrolle.",
- "apihelp-query+checkuser-param-limit": "Limite de righe.",
- "apihelp-query+checkuser-param-timecond": "Tiembe limite de le date utende (cumme \"2 sumàne\" o \"2 sumàne fa\").",
- "apihelp-query+checkuser-param-xff": "Ause date XFF invece de l'indirizze IP.",
- "apihelp-query+checkuser-example-1": "Verifiche l'indirizze IP pe [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Verifiche le cangiaminde da 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Pigghie le vôsce da l'archivije CheckUser.",
- "apihelp-query+checkuserlog-summary": "Pigghie le v147sce de l'archivije d'u CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Nome de l'utende de CheckUser.",
- "apihelp-query+checkuserlog-param-target": "Utende condrollate, indirizze IP o indervalle CIDR.",
- "apihelp-query+checkuserlog-param-limit": "Limite de righe.",
- "apihelp-query+checkuserlog-param-from": "Orarie da addò accumenze l'enumerazione.",
- "apihelp-query+checkuserlog-param-to": "Orarie da addò spicce l'enumerazione.",
- "apihelp-query+checkuserlog-example-1": "Fà vedè le verifiche sus a [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Fà vedè le verifiche de 192.0.2.0/24 apprisse 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Tu ha dicere 'nu mutive de verifiche.",
- "apierror-checkuser-timelimit": "Tu è abbesogne de ausà 'u limite de tiembe corrette (cumme \"-2 sumàne\" o \"2 sumàne rrete\").",
- "apierror-checkuser-invalidmode": "Mode de richieste invalide"
+ "checkuser-investigateblock": "Bluècche l'utinde",
+ "checkuser-investigateblock-target": "Nome de le utinde e indirizze IP",
+ "checkuser-investigate": "Investighe",
+ "checkuser-investigate-legend": "Cirche nome utinde, indirizze IP o 'ndervalle IP",
+ "checkuser-investigate-targets-label": "Nome de le utinde e indirizze IP",
+ "checkuser-investigate-targets-placeholder": "Nome utende o 1.1.1.1",
+ "checkuser-investigate-reason-label": "Mutive",
+ "checkuser-investigate-preliminary-table-header-blocked": "State"
}
diff --git a/CheckUser/i18n/ru.json b/CheckUser/i18n/ru.json
index daeb2c8c..24e1d70c 100644
--- a/CheckUser/i18n/ru.json
+++ b/CheckUser/i18n/ru.json
@@ -1,29 +1,35 @@
{
"@metadata": {
"authors": [
+ "Alexander Yukal",
+ "Cat1987",
"Cryptocoryne",
"DCamer",
+ "Diman Russkov",
+ "Diralik",
"EugeneZelenko",
"Express2000",
+ "Facenapalm",
"Ferrer",
"Ilya Voyager",
"Kaganer",
+ "Kent73",
"Kv75",
"Lockal",
+ "Mailman",
+ "MaksimPinigin",
+ "Mariya",
+ "Mouse21",
"NBS",
+ "Okras",
"Ole Yves",
+ "Pacha Tchernof",
"Prima klasy4na",
"Putnik",
"Silence",
+ "Teretalexev",
"Александр Сигачёв",
- "Okras",
- "Mariya",
- "Ядерный Трамвай",
- "Cat1987",
- "Mailman",
- "Facenapalm",
- "MaksimPinigin",
- "Mouse21"
+ "Ядерный Трамвай"
]
},
"checkuser-summary": "Данный инструмент может быть использован, чтобы получить IP-адреса, использовавшиеся участником, либо чтобы показать правки/участников, работавших с IP-адреса.\nПравки и пользователи, которые правили с определённого IP-адреса, указанного в X-Forwarded-For, можно получить, добавив постфикс <code>/xff</code> к IP-адресу. Поддерживаемые версии IP: 4 (CIDR $1—32) и 6 (CIDR $2—128).\nИз соображений производительности будут показаны только первые 5000 правок.\nИспользуйте эту страницу '''только в соответствии с правилами'''.",
@@ -35,8 +41,8 @@
"checkuser-contribs-log": "недавние проверки пользователя",
"group-checkuser": "Проверяющие участников",
"group-checkuser-member": "{{GENDER:$1|проверяющий участников|проверяющая участников}}",
- "right-checkuser": "проверка IP-адресов и другой информации участников",
- "right-checkuser-log": "просмотр журнала проверок участников",
+ "right-checkuser": "Проверка IP-адресов и другой информации участников",
+ "right-checkuser-log": "Просмотр журнала проверок участников",
"action-checkuser": "проверка IP-адресов и другой информации участников",
"action-checkuser-log": "просмотр журнала проверок участников",
"grouppage-checkuser": "{{ns:project}}:Проверка участников",
@@ -81,7 +87,6 @@
"checkuser-block-noreason": "Вы должны указать причину блокировок.",
"checkuser-centralauth-multilock": "Глобально заблокировать выбранные учётные записи",
"checkuser-noreason": "Вы должны указать причину для этого запроса.",
- "checkuser-accounts": "$1 {{PLURAL:$1|новая учётная запись|новых учётных записи|новых учётных записей}}",
"checkuser-too-many": "Слишком много результатов (согласно оценке запроса), пожалуйста, сузьте CIDR.\nИспользованные IP (максимум 5000, отсортировано по адресу):",
"checkuser-user-nonexistent": "Указанного участника не существует",
"checkuser-search": "Поиск по записям журнала проверки пользователя",
@@ -94,38 +99,55 @@
"checkuser-showmain": "Перейти к странице проверки участников",
"checkuser-limited": "'''Результаты были усечены чтобы не создавать дополнительной нагрузки на сервер.'''",
"checkuser-log-entry-userips": "$3 $1 получил IP-адреса для $2",
- "checkuser-log-entry-ipedits": "$3 $1 получил правки для $2",
- "checkuser-log-entry-ipusers": "$3 $1 получил учётные записи для $2",
- "checkuser-log-entry-ipedits-xff": "$3 $1 получил правки для XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3 $1 получил учётные записи для XFF $2",
+ "checkuser-log-entry-ipedits": "$3 $1 получил правки для <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3 $1 получил учётные записи для <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3 $1 получил правки для XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3 $1 получил учётные записи для XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3 $1 получил правки для $2",
"checkuser-autocreate-action": "был создан автоматически",
"checkuser-create-action": "создан",
"checkuser-email-action": "отправил письмо участнику «$1»",
"checkuser-reset-action": "сбросил пароль для участника $1",
- "checkuser-token-fail": "Сеанс прерван. Пожалуйста, попробуйте еще раз.",
+ "checkuser-token-fail": "Сеанс прерван. Пожалуйста, попробуйте ещё раз.",
"checkuser-login-failure": "Не удалось войти в {{SITENAME}} в качестве $1",
"checkuser-login-success": "Успешно вошел в систему {{SITENAME}} как $1",
- "apihelp-query+checkuser-description": "Проверить, какие IP-адреса используются данным именем участника или какие имена участников используются заданным IP-адресом.",
- "apihelp-query+checkuser-summary": "Проверить, какие IP-адреса используются данным именем участника или какие имена участников используются заданным IP-адресом.",
- "apihelp-query+checkuser-param-request": "Тип запроса чекюзера:\n;userips:Получить IP-адрес целевого пользователя.\n; edits:Получить изменения, сделанные с целевого IP-адреса или диапазона адресов.\n;ipusers:Получить пользователей по целевому IP-адресу или диапазону.",
- "apihelp-query+checkuser-param-target": "Имя участника, IP-адрес или CIDR-диапазон для проверки.",
- "apihelp-query+checkuser-param-reason": "Причина проверки.",
- "apihelp-query+checkuser-param-limit": "Ограничение количества строк.",
- "apihelp-query+checkuser-param-timecond": "Ограничение по времени для данных об участнике (например, «-2 weeks» или «2 weeks ago»).",
- "apihelp-query+checkuser-param-xff": "Использовать XFF-данные вместо IP-адреса.",
- "apihelp-query+checkuser-example-1": "Проверить IP-адреса [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Проверить правки с 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Получить записи из журнала проверки участников (CheckUser).",
- "apihelp-query+checkuserlog-summary": "Получить записи из журнала проверки участников.",
- "apihelp-query+checkuserlog-param-user": "Имя пользователя чекюзера.",
- "apihelp-query+checkuserlog-param-target": "Проверенный участник, IP-адрес или CIDR-диапазон.",
- "apihelp-query+checkuserlog-param-limit": "Ограничение количества строк.",
- "apihelp-query+checkuserlog-param-from": "Метка времени, с которого нужно начинать перечисление.",
- "apihelp-query+checkuserlog-param-to": "Метка времени, до которого делать перечисление.",
- "apihelp-query+checkuserlog-example-1": "Показать проверки [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Показать проверки 192.0.2.0/24 начиная с 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Вы должны указать причину для проверки.",
- "apierror-checkuser-timelimit": "Вам необходимо использовать правильное ограничение по времени (например, «-2 weeks» или «2 weeks ago»).",
- "apierror-checkuser-invalidmode": "Недопустимый режим запроса"
+ "checkuser-investigateblock": "Заблокированные участники",
+ "checkuser-investigateblock-reblock-label": "Переписать существующие блокировки",
+ "checkuser-investigateblock-success": "Сейчас {{PLURAL:$2|заблокирован $1 участник|заблокированы $1 участника|заблокированы $1 участников}}.",
+ "checkuser-investigate-log": "Журнал исследований",
+ "checkuser-investigate-log-entry": "$3, $1 посмотрел информацию для <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Записи журнала исследований не найдены.",
+ "checkuser-investigate-log-subtitle": "Переключиться на форму исследования",
+ "checkuser-investigate-page-subtitle": "Текущее исследование за $1",
+ "checkuser-investigate-indicator-new-investigation": "Новое исследование",
+ "checkuser-investigate-indicator-logs": "Журналы",
+ "checkuser-investigate-legend": "Поиск по именам участников, IP-адресам или диапазонам IP-адресов",
+ "checkuser-investigate-notice-no-results": "Нет результатов.",
+ "checkuser-investigate-tab-preliminary-check": "Информация об аккаунте",
+ "checkuser-investigate-tab-compare": "IP-адреса и агенты пользователя",
+ "checkuser-investigate-reason-label": "Причина",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Заблокирован",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|правка|правки}}",
+ "checkuser-investigate-preliminary-table-header-blocked": "Статус",
+ "checkuser-investigate-preliminary-table-header-editcount": "Правки",
+ "checkuser-investigate-preliminary-table-header-groups": "Группы",
+ "checkuser-investigate-preliminary-table-header-name": "Имя участника",
+ "checkuser-investigate-preliminary-table-header-wiki": "Вики",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Вики не найдена",
+ "checkuser-investigate-filters-legend": "Фильтры",
+ "checkuser-investigate-filters-exclude-targets-label": "Скрыть следующих пользователей или IP-адреса",
+ "checkuser-investigate-timeline-notice-no-results": "Нет результатов: за последние 90 дней не было зарегистрировано активности этих участников или IP-адресов.",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Нет результатов, соответствующих этим критериям фильтрации. Попробуйте удалить некоторые фильтры, чтобы расширить поиск.",
+ "checkuser-investigate-compare-copy-button-label": "Показать вики-текст",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Из-за технических ограничений мы достигли количества записей, которые могут быть представлены. Данные, возвращаемые для следующих целей, являются неполными: $1. Пожалуйста, попробуйте использовать меньшее количество целей, меньшее временное окно или более узкие диапазоны IP-адресов.",
+ "checkuser-investigate-compare-notice-no-results": "Нет результатов: за последние 90 дней не было правок от этих участников или IP-адресов.",
+ "checkuser-investigate-compare-notice-no-results-filters": "Нет результатов, соответствующих этим критериям фильтрации. Попробуйте удалить некоторые фильтры, чтобы расширить поиск.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Показать все IP этого пользователя",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Показать всех участников, использующих этот IP",
+ "checkuser-investigate-compare-table-cell-unregistered": "Незарегистрированные",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|правка|правки}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 от всех пользователей)</i>",
+ "checkuser-investigate-compare-table-header-username": "Имя участника",
+ "checkuser-investigate-compare-table-header-activity": "Диапазон дат",
+ "checkuser-investigate-compare-table-header-ip": "IP-адрес"
}
diff --git a/CheckUser/i18n/rue.json b/CheckUser/i18n/rue.json
index fdea66cb..c4b2473b 100644
--- a/CheckUser/i18n/rue.json
+++ b/CheckUser/i18n/rue.json
@@ -51,7 +51,6 @@
"checkuser-block-limit": "Выбрано дуже много хоснователїв.",
"checkuser-block-noreason": "Мусите задати причіну блокованя.",
"checkuser-noreason": "Ку тому запыту мусите увести причіну.",
- "checkuser-accounts": "$1 {{PLURAL:$1|нове конто|новы конта|новых конт}}",
"checkuser-too-many": "Дуже много резултатів (подля оцінкы пожадавкы), спробуйте обмеджіти CIDR.\nНиже суть хоснованы IP адресы (найвеце 5000, сортованы подля адресы):",
"checkuser-user-nonexistent": "Зазначеный хоснователь не єствує.",
"checkuser-search": "Найти",
diff --git a/CheckUser/i18n/rup.json b/CheckUser/i18n/rup.json
index 417f1df7..c18d96b5 100644
--- a/CheckUser/i18n/rup.json
+++ b/CheckUser/i18n/rup.json
@@ -1,8 +1,8 @@
{
"@metadata": {
"authors": [
- "Hakka",
- "D'AroemenenZullenNiVergaan"
+ "D'AroemenenZullenNiVergaan",
+ "Hakka"
]
},
"checkuser-reason": "Furńie:",
diff --git a/CheckUser/i18n/ryu.json b/CheckUser/i18n/ryu.json
new file mode 100644
index 00000000..efea48dd
--- /dev/null
+++ b/CheckUser/i18n/ryu.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tmv"
+ ]
+ },
+ "checkuser-investigate-subtitle-block-button-label": "ブロック",
+ "checkuser-investigate-subtitle-cancel-button-label": "ヰーヰー"
+}
diff --git a/CheckUser/i18n/sah.json b/CheckUser/i18n/sah.json
index 7cdc8eed..4a811af2 100644
--- a/CheckUser/i18n/sah.json
+++ b/CheckUser/i18n/sah.json
@@ -50,7 +50,6 @@
"checkuser-block-limit": "Наһаа элбэх киһини талбыккын",
"checkuser-block-noreason": "Бобуу төрүөтүн этиэхтээххин.",
"checkuser-noreason": "Бу ыйытык төрүөтүн ааттыахтааххын.",
- "checkuser-accounts": "$1 саҥа {{PLURAL:$1|аат|ааттар}}",
"checkuser-too-many": "Наһаа элбэх булулунна (көрдөбүл түмүгүнэн), бука диэн CIDR кыччатан биэр. \nТуһаныллыбыт IP (саамай элбэҕэ 5000, бу аадырыһынан наардаммыт):",
"checkuser-user-nonexistent": "Маннык ааттаах кыттааччы суох",
"checkuser-search": "Көрдөө",
diff --git a/CheckUser/i18n/sat.json b/CheckUser/i18n/sat.json
new file mode 100644
index 00000000..59a23eed
--- /dev/null
+++ b/CheckUser/i18n/sat.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Durga Soren"
+ ]
+ },
+ "checkuser-investigate-compare-table-button-contribs-label": "ᱮᱱᱮᱢᱠᱚ"
+}
diff --git a/CheckUser/i18n/scn.json b/CheckUser/i18n/scn.json
index 153fe771..b170ce35 100644
--- a/CheckUser/i18n/scn.json
+++ b/CheckUser/i18n/scn.json
@@ -2,8 +2,8 @@
"@metadata": {
"authors": [
"Melos",
- "Santu",
"Pippinu",
+ "Santu",
"Sarvaturi"
]
},
@@ -57,7 +57,6 @@
"checkuser-block-limit": "Troppu assai utenti scigghiuti.",
"checkuser-block-noreason": "S'havi a dari nu mutivu pi li blocchi.",
"checkuser-noreason": "S'havi a dari nu mutivu pi sta ntirrugazzioni.",
- "checkuser-accounts": "$1 {{PLURAL:$1|cuntu novu|cunti novi}}",
"checkuser-too-many": "Ci sunnu troppu assai risurtati (secunnu la stima dâ ntirrugazzioni), pi favuri strinci lu CIDR.\nDi sècutu sunnu nnicati li nnirizzi IP adupirati (màssimu 5000, misi n òrdini pi nnirizzu):",
"checkuser-user-nonexistent": "L’utenti spicificatu nun esisti.",
"checkuser-search": "Cerca",
@@ -71,22 +70,5 @@
"checkuser-create-action": "fu criatu",
"checkuser-email-action": "mannau nu missaggiu di posta elittrònica a «$1»",
"checkuser-reset-action": "azzera la password di l'utenti «$1»",
- "checkuser-token-fail": "Erruri di sissioni. Pi favuri prova n'àutra vota.",
- "apihelp-query+checkuser-description": "Cuntrolla quali nnirizzi IP sunnu adupirati dûn nomu utenti datu, o quali nomi utenti sunnu adupirati di nu nnirizzu IP datu.",
- "apihelp-query+checkuser-param-request": "Sorta d'addumannata dû CheckUser:\n;userips:Pigghia lu nnirizzu IP di l'utenti.\n;edits:Pigghia li canciamenti dû nnirizzu IP o dû ntirvallu di nnirizzi IP.\n;ipusers:Pigghia l'utenti dû nnirizzu IP o dû ntirvallu di nnirizzi IP.",
- "apihelp-query+checkuser-param-target": "Nomu utenti, nnirizzu IP, o ntirvallu CIDR di cuntrullari.",
- "apihelp-query+checkuser-param-reason": "Mutivu dû cuntrollu.",
- "apihelp-query+checkuser-param-limit": "Lìmiti di ringhi.",
- "apihelp-query+checkuser-param-timecond": "Lìmiti di tempu pî dati di l’utenti (comu \"2 weeks\").",
- "apihelp-query+checkuser-param-xff": "Adòpira lu datu XFF mmeci dû nnirizzu IP.",
- "apihelp-query+checkuser-example-1": "Cuntrolla li nnirizzi IP di [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Cuntrolla li canciamenti ca vèninu di 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Pigghia li vuci dû riggistru dû CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Nomu utenti dû cuntrulluri.",
- "apihelp-query+checkuserlog-param-target": "Utenti, nnirizzu IP, o ntirvallu CIDR cuntrullatu.",
- "apihelp-query+checkuserlog-param-limit": "Lìmiti di ringhi.",
- "apihelp-query+checkuserlog-param-from": "La data e l'ura di quannu si voli accuminzari l'enumirazzioni.",
- "apihelp-query+checkuserlog-param-to": "La data e l'ura di quannu si voli cunchiùdiri l'enumirazzioni.",
- "apihelp-query+checkuserlog-example-1": "Ammustra li cuntrolli fatti di [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Ammustra li cuntrolli fatti di 192.0.2.0/24 appressu dû 2011-10-15T23:00:00Z"
+ "checkuser-token-fail": "Erruri di sissioni. Pi favuri prova n'àutra vota."
}
diff --git a/CheckUser/i18n/sd.json b/CheckUser/i18n/sd.json
index 47423f9a..cc907bfb 100644
--- a/CheckUser/i18n/sd.json
+++ b/CheckUser/i18n/sd.json
@@ -1,16 +1,16 @@
{
"@metadata": {
"authors": [
- "Mehtab ahmed",
"Indus Asia",
+ "Mehtab ahmed",
"Tweety"
]
},
"group-checkuser": "واپرائيندڙ چڪاسڪار",
"checkuser-target": "آئي پي پتو يا واپرائيندڙ نانءُ",
- "checkuser-edits": "ترميمون وٺو",
+ "checkuser-edits": "سنوارون وٺو",
+ "checkuser-month": "گذريل 30 ڏينھن",
"checkuser-all": "سڀ",
"checkuser-check-this-user": "هن واپرائيندڙ جي جانچ ڪيو (Check this user)",
- "checkuser-blocktag-talk": "بحث صفحن کي سان مٽايو:",
- "apihelp-query+checkuser-example-2": "192.0.2.0/24 پاران ترميمون چڪاسيو"
+ "checkuser-blocktag-talk": "بحث صفحن کي سان مٽايو:"
}
diff --git a/CheckUser/i18n/sh.json b/CheckUser/i18n/sh.json
index 53ebe89a..2e5e1ccb 100644
--- a/CheckUser/i18n/sh.json
+++ b/CheckUser/i18n/sh.json
@@ -1,11 +1,12 @@
{
"@metadata": {
"authors": [
- "Kolega2357"
+ "Kolega2357",
+ "Vlad5250"
]
},
"checkuser-summary": "Ova alatka pregleda skorašnje izmene i vraća IP adrese koje je korisnik koristio ili pokazuje podatke o korisniku/izmenama za dati IP. Korisnici i izmene klijentskog IP se mogu dobaviti preko XFF zaglavlja dodavanjem <code>/xff</code> iza IP adrese. Podržani su formati IPv4 (CIDR $1-32) i IPv6 (CIDR $2-128).\nZbog performansi neće biti vraćeno više od 5000 izmena.\nAlatku koristite u skladu sa politikom.",
- "checkuser-desc": "Daje korisnicima sa odgovarajućim pravima mogućnost da provere IP adrese korisnika i druge informacije.",
+ "checkuser-desc": "Daje korisnicima sa odgovarajućim pravima mogućnost da provere IP adrese korisnika i druge informacije",
"checkuser-logcase": "Pretraga evidencije razlikuje mala i velika slova.",
"checkuser": "Provjera korisnika / Провера корисника",
"checkuserlog": "Evidencija čekjuzera",
@@ -20,24 +21,26 @@
"grouppage-checkuser": "{{ns:project}}:Čekjuzeri",
"checkuser-reason": "Razlog:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Prikaži evidenciju",
+ "checkuser-showlog": "Prebaci na dnevnik čekjuzera",
"checkuser-query": "Upit u skorašnjim izmenama",
"checkuser-target": "IP adresa ili korisničko ime:",
- "checkuser-users": "Dobavi korisnike",
- "checkuser-edits": "Dobavi izmene za IP",
- "checkuser-ips": "Dobavi IP brojeve",
+ "checkuser-users": "Vidi korisnike",
+ "checkuser-edits": "Vidi izmene",
+ "checkuser-ips": "Prikaži IP adrese",
"checkuser-period": "Trajanje:",
"checkuser-week-1": "poslednja nedelja",
"checkuser-week-2": "poslednje dve nedelje",
"checkuser-month": "poslednjih 30 dana",
"checkuser-all": "sve",
- "checkuser-cidr-label": "Pronađi uobičajeni opseg i zahvaćene adrese za spisak IP adresa.",
- "checkuser-cidr-res": "Uobičajeni CIDR:",
- "checkuser-empty": "U evidenciji nema zabeleženih izmena.",
+ "checkuser-cidr-label": "Nađi zajedničku nizu i zahvaćene adrese za spisak IP adresa",
+ "checkuser-cidr-res": "Zajednički CIDR:",
+ "checkuser-empty": "Evidencija je prazna.",
"checkuser-nomatch": "Nema pogodaka.",
- "checkuser-nomatch-edits": "Nema pogodaka. Poslednja izmena je urađena $1 u $2.",
+ "checkuser-nomatch-edits": "Nema pogodaka.\nPoslednja izmena je urađena $1 u $2.",
"checkuser-check": "Proveri",
- "checkuser-log-fail": "Ne mogu da dodam belešku u evidenciju",
+ "checkuser-check-this-user": "Proveri ovog korisnika",
+ "checkuser-recent-checks": "Skorašnje provjere korisnika",
+ "checkuser-log-fail": "Ne mogu da dodam stavku u evidenciju",
"checkuser-nolog": "Nije pronađena datoteka evidencije.",
"checkuser-blocked": "Blokiran",
"checkuser-gblocked": "Blokiran globalno",
@@ -45,27 +48,40 @@
"checkuser-wasblocked": "Prethodno blokiran",
"checkuser-localonly": "Nije unificirano",
"checkuser-massblock": "Blokiraj izabranog korisnika",
- "checkuser-massblock-text": "Izabrani nalozi će biti blokirani na neodređeno, uz obeležene opcije autoblokiranja i zabrane pravljenja naloga.\nIP adrese će biti blokirane na nedelju dana za IP korisnike, uz zabranu pravljenja naloga.",
+ "checkuser-massblock-text": "Izabrani računi će biti neograničeno blokirani, s omogućenom autoblokiranjem i onemogućenim pravljenjem računa.\nIP adrese će biti blokirane na nedelju samo za IP korisnike, i s onemogućenim pravljenjem računa.",
+ "checkuser-blockemail": "Onemogući slanje e-pošte",
+ "checkuser-blocktalk": "Spriječi uređivanje vlastite stranice za razgovor za vrijeme blokiranja",
"checkuser-blocktag": "Zameni korisničke stranice sa:",
- "checkuser-blocktag-talk": "Zameni sтrane za razgovor sa:",
- "checkuser-massblock-commit": "Blokiraj izabranog korisnika",
+ "checkuser-blocktag-talk": "Zameni stranice za razgovor sa:",
+ "checkuser-massblock-commit": "Blokiraj izabrane korisnike",
"checkuser-block-success": "'''{{PLURAL:$2|Korisnik|Korisnici}} $1 {{PLURAL:$2|je sada blokiran|su sada blokirani}}.'''",
"checkuser-block-failure": "'''Nema blokiranih korisnika.'''",
- "checkuser-block-limit": "Izabrano je previše korisnika.",
- "checkuser-block-noreason": "Morate dati razlog za blok.",
+ "checkuser-block-limit": "Izabrali ste previše korisnika.",
+ "checkuser-block-noreason": "Morate navesti razlog za blokiranje.",
+ "checkuser-centralauth-multilock": "Višekratno zaključavanje računa",
"checkuser-noreason": "Morate da navedete razlog za ovaj upit.",
- "checkuser-accounts": "$1 {{PLURAL:$1|novi nalog|nova naloga|nova naloga|nova naloga|novih naloga}}",
- "checkuser-too-many": "Nađeno je previše rezultata (prema proceni zahteva). Molimo Vas da suzite CIDR.\nOvde su korišćene IP adrese (najviše 5.000, sortiranih po adresi):",
+ "checkuser-too-many": "Previše stavki (prema proceni zahteva). Molimo Vas da suzite CIDR.\nOvde su korišćene IP adrese (najviše 5.000, sortiranih po adresi):",
"checkuser-user-nonexistent": "Navedeni korisnik ne postoji.",
- "checkuser-search": "Traži / Тражи",
+ "checkuser-search": "Pretraži stavke u zapisniku provjeravača",
"checkuser-search-submit": "Pretraži",
"checkuser-search-initiator": "pokretač",
"checkuser-search-target": "cilj",
+ "checkuser-log-search-target": "Cilj:",
+ "checkuser-log-search-type": "Pretraži prema:",
"checkuser-ipeditcount": "~$1 od svih korisnika",
- "checkuser-showmain": "Nazad na glavni obrazac za proveravanje korisnika",
- "checkuser-limited": "'''Ovi rezultati su skraćeni zbog performansi.'''",
+ "checkuser-showmain": "Prebaci me na glavni obrazac za proveravanje korisnika",
+ "checkuser-limited": "'''Ovaj ishod je skraćen zbog performansi.'''",
+ "checkuser-log-entry-userips": "$3, $1 je dohvatio IP adrese za $2",
+ "checkuser-log-entry-ipedits": "$3, $1 je dohvatio izmjene za <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 je dohvatio korisnike za <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 je dohvatio izmjene za XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 je dohvatio korisnike za XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-useredits": "$3, $1 je dohvatio izmjene za $2",
"checkuser-autocreate-action": "je automatski napravljen",
"checkuser-create-action": "je napravljen",
"checkuser-email-action": "e-mail je poslat korisniku „$1“",
- "checkuser-reset-action": "poništi lozinku korisnika „$1“"
+ "checkuser-reset-action": "poništi lozinku korisnika „$1“",
+ "checkuser-token-fail": "Sesija nije uspjela. Pokušajte ponovno.",
+ "checkuser-login-failure": "Nije uspio vas prijaviti na {{SITENAME}} kao $1",
+ "checkuser-login-success": "Uspješno sam prijavio na {{SITENAME}} kao $1"
}
diff --git a/CheckUser/i18n/si.json b/CheckUser/i18n/si.json
index 5460d74a..3d8dedf9 100644
--- a/CheckUser/i18n/si.json
+++ b/CheckUser/i18n/si.json
@@ -51,7 +51,6 @@
"checkuser-block-limit": "තෝරාගත් පරිශීලකයන් ගණන වැඩියි.",
"checkuser-block-noreason": "වාරණ සඳහා ඔබ විසින් හේතුවක් ලබා දිය යුතුය.",
"checkuser-noreason": "මෙම ප්‍රශ්නය සඳහා ඔබ විසින් හේතුවක් ලබා දිය යුතුය.",
- "checkuser-accounts": "නව {{PLURAL:$1|ගිණුම්|ගිණුම්}} $1 ක්",
"checkuser-user-nonexistent": "විශේෂණය කෙරූ පරිශීලකයා නොපවතියි.",
"checkuser-search": "ගවේෂණය",
"checkuser-search-submit": "ගවේෂණය",
diff --git a/CheckUser/i18n/sk.json b/CheckUser/i18n/sk.json
index a6eccba6..74063ff9 100644
--- a/CheckUser/i18n/sk.json
+++ b/CheckUser/i18n/sk.json
@@ -2,9 +2,11 @@
"@metadata": {
"authors": [
"Helix84",
+ "Luky001",
"Martin Kozák",
"Sudo77(new)",
- "Teslaton"
+ "Teslaton",
+ "Vlad5250"
]
},
"checkuser-summary": "Tento nástroj kontroluje Posledné úpravy, aby získal IP adresy, ktoré používateľ použil alebo zobrazil úpravy/používateľské dáta IP adresy.\nPoužívateľov a úpravy je možné získať prostredníctvom hlavičiek XFF pridaním „/xff“ k IP adrese. Sú podporované IPv4 (CIDR $1-32) a IPv6 (CIDR $2-128).\nZ dôvodov výkonnosti nebude vrátených viac ako 5 000 úprav. Túto funkciu využívajte len v súlade s platnou politikou.",
@@ -23,7 +25,7 @@
"grouppage-checkuser": "{{ns:project}}:Revízia používateľa",
"checkuser-reason": "Dôvod:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Zobraziť záznam",
+ "checkuser-showlog": "Prepnúť na protokol kontroly používateľov",
"checkuser-query": "Získať z posledných úprav",
"checkuser-target": "IP adresa alebo meno používateľa:",
"checkuser-users": "Získať používateľov",
@@ -40,6 +42,7 @@
"checkuser-nomatch": "Žiadny vyhovujúci záznam.",
"checkuser-nomatch-edits": "Neboli nájdené zhody.\nPosledná úprava bola $1 o $2.",
"checkuser-check": "Skontrolovať",
+ "checkuser-check-this-user": "Skontrolovať tohto používateľa",
"checkuser-log-fail": "Nebolo možné pridať položku záznamu",
"checkuser-nolog": "Nebol nájdený súbor záznamu.",
"checkuser-blocked": "Zablokovaný",
@@ -60,10 +63,9 @@
"checkuser-block-noreason": "Musíte zadať dôvod blokovaní.",
"checkuser-centralauth-multilock": "Hromadne zamknúť zvolené účty",
"checkuser-noreason": "Musíte uviesť dôvod tejto požiadavky.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nový účet|nové účty|nových účtov}}",
- "checkuser-too-many": "Príliš veľa výsledkov (podľa odhadu požiadavky), prosím zúžte CIDR.\nTu sú použité IP (max. 5 000, zoradené podľa adresy):",
+ "checkuser-too-many": "Príliš veľa výsledkov (podľa odhadu požiadavky), prosím, zúžte CIDR.\nTu sú použité IP adresy (max. 5 000, zoradené podľa adresy):",
"checkuser-user-nonexistent": "Uvedený používateľ neexistuje.",
- "checkuser-search": "Hľadať",
+ "checkuser-search": "Hľadanie v záznamoch kontroly používateľov",
"checkuser-search-submit": "Hľadať",
"checkuser-search-initiator": "začínajúci",
"checkuser-search-target": "cieľ",
@@ -73,10 +75,10 @@
"checkuser-showmain": "Návrat na hlavný formulár kontroly používateľa",
"checkuser-limited": "'''Tieto výsledky boli z výkonnostných dôvodov skrátené.'''",
"checkuser-log-entry-userips": "$3, $1 zisťuje IP adresy používateľa $2",
- "checkuser-log-entry-ipedits": "$3, $1 zisťuje úpravy z $2",
- "checkuser-log-entry-ipusers": "$3, $1 zisťuje používateľa z $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 zisťuje úpravy s XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 zisťuje používateľa s XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 zisťuje úpravy z <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 zisťuje používateľa z <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 zisťuje úpravy s XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 zisťuje používateľa s XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 zisťuje úpravy používateľa $2",
"checkuser-autocreate-action": "bol automaticky vytvorený",
"checkuser-create-action": "bol vytvorený",
diff --git a/CheckUser/i18n/skr-arab.json b/CheckUser/i18n/skr-arab.json
new file mode 100644
index 00000000..0f661989
--- /dev/null
+++ b/CheckUser/i18n/skr-arab.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Saraiki"
+ ]
+ },
+ "checkuser-investigate-indicator-logs": "لاگ",
+ "checkuser-investigate-duration-option-all": "یکے",
+ "checkuser-investigate-duration-option-1w": "پچھلا ہفتہ",
+ "checkuser-investigate-filters-legend": "چھاݨے"
+}
diff --git a/CheckUser/i18n/sl.json b/CheckUser/i18n/sl.json
index 778fd47a..17bbc930 100644
--- a/CheckUser/i18n/sl.json
+++ b/CheckUser/i18n/sl.json
@@ -60,8 +60,7 @@
"checkuser-block-noreason": "Potrebno je navesti razlog blokiranj.",
"checkuser-centralauth-multilock": "Zakleni izbrane račune",
"checkuser-noreason": "Potrebno je navesti razlog za to poizvedbo.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nov račun|nova računa|novi računi|novih računov}}",
- "checkuser-too-many": "Preveč rezultatov (glede na oceno poizvedbe), prosimo zožite CIDR.\nTukaj so uporabljeni IP-naslovi (največ 5000, razvrščeni po naslovu):",
+ "checkuser-too-many": "Preveč rezultatov (glede na oceno poizvedbe), prosimo zožite CIDR.\nTukaj so uporabljeni IP-naslovi (največ $1, razvrščeni po naslovu):",
"checkuser-user-nonexistent": "Navedeni uporabnik ne obstaja.",
"checkuser-search": "Iskanje vnosov v dnevniku preverjanj uporabnikov",
"checkuser-search-submit": "Išči",
@@ -73,10 +72,10 @@
"checkuser-showmain": "Preklopi na glavni obrazec za preverjanje uporabnikov",
"checkuser-limited": "'''Rezultati so bili okrnjeni iz zmogljivostnih razlogov.'''",
"checkuser-log-entry-userips": "$3, $1 je {{GENDER:|prejel|prejela}} izpis IP naslovov za $2",
- "checkuser-log-entry-ipedits": "$3, $1 je {{GENDER:|prejel|prejela}} izpis urejanj za $2",
- "checkuser-log-entry-ipusers": "$3, $1 je {{GENDER:$1|prejel|prejela}} izpis uporabnikov za $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 je {{GENDER:|prejel|prejela}} izpis urejanj za XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 je {{GENDER:|prejel|prejela}} izpis uporabnikov XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 je {{GENDER:|prejel|prejela}} izpis urejanj za <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 je {{GENDER:$1|prejel|prejela}} izpis uporabnikov za <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 je {{GENDER:|prejel|prejela}} izpis urejanj za XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 je {{GENDER:|prejel|prejela}} izpis uporabnikov XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 je {{GENDER:|prejel|prejela}} izpis uporabnikov za $2",
"checkuser-autocreate-action": "je bil samodejno ustvarjen",
"checkuser-create-action": "je bil ustvarjen",
@@ -84,27 +83,5 @@
"checkuser-reset-action": "ponastavi geslo uporabnika »$1«",
"checkuser-token-fail": "Seja je spodletela. Poskusi ponovno.",
"checkuser-login-failure": "Prijava na {{SITENAME}} kot $1 je spodletela",
- "checkuser-login-success": "Uspešna prijava na {{SITENAME}} kot $1",
- "apihelp-query+checkuser-description": "Preveri, katere IP naslove uporablja navedeni uporabnik ali katera uporabniška imena uporablja navedeni IP naslov.",
- "apihelp-query+checkuser-summary": "Preveri, katere IP naslove uporablja navedeni uporabnik ali katera uporabniška imena uporablja navedeni IP naslov.",
- "apihelp-query+checkuser-param-request": "Vrsta prošnje za preverjanje uporabnika:\n;userips:Prikaži IP naslov ciljnega uporabnika.\n;edits:Prikaži spremembe ciljnega IP naslova ali razpona IP-jev.\n;ipusers:Prikaži uporabnike ciljnega IP naslova ali razpona IP-jev.",
- "apihelp-query+checkuser-param-target": "Uporabniško ime, IP naslov ali razpon CIDR za preverbo.",
- "apihelp-query+checkuser-param-reason": "Razlog preverbe.",
- "apihelp-query+checkuser-param-limit": "Omejitev vrstic.",
- "apihelp-query+checkuser-param-timecond": "Časovna omejitev uporabniških podatkov (na primer \"-2 tedna\" ali \"2 tedna nazaj\").",
- "apihelp-query+checkuser-param-xff": "Uporabi podatke XFF namesto IP naslova.",
- "apihelp-query+checkuser-example-1": "Preveri IP naslove za [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Preveri urejanja od 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Prikaži vpise iz dnevnika preverjanj uporabnikov.",
- "apihelp-query+checkuserlog-summary": "Prikaži vpise iz dnevnika preverjanj uporabnikov.",
- "apihelp-query+checkuserlog-param-user": "Uporabniško ime preverjevalca uporabnikov.",
- "apihelp-query+checkuserlog-param-target": "Uporabniško ime, IP naslov ali razpon CIDR.",
- "apihelp-query+checkuserlog-param-limit": "Omejitev vrstic.",
- "apihelp-query+checkuserlog-param-from": "Datum začetka izpisa.",
- "apihelp-query+checkuserlog-param-to": "Datum konca izpisa.",
- "apihelp-query+checkuserlog-example-1": "Prikaži preverjanja za [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Prikaži preverjanja za 192.0.2.0/24 po 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Potrebno je navesti razlog za preverjanje.",
- "apierror-checkuser-timelimit": "Potrebno je uporabiti pravilno časovno omejitev (na primer \"-2 tedna\" ali \"2 tedna nazaj\").",
- "apierror-checkuser-invalidmode": "Neveljaven način zaprositve"
+ "checkuser-login-success": "Uspešna prijava na {{SITENAME}} kot $1"
}
diff --git a/CheckUser/i18n/sq.json b/CheckUser/i18n/sq.json
index 1d40508e..ca878b15 100644
--- a/CheckUser/i18n/sq.json
+++ b/CheckUser/i18n/sq.json
@@ -1,8 +1,8 @@
{
"@metadata": {
"authors": [
- "Dori",
"Ammartivari",
+ "Dori",
"Toplove12"
]
},
diff --git a/CheckUser/i18n/sr-ec.json b/CheckUser/i18n/sr-ec.json
index 4bef2b08..94cdba8d 100644
--- a/CheckUser/i18n/sr-ec.json
+++ b/CheckUser/i18n/sr-ec.json
@@ -1,86 +1,126 @@
{
"@metadata": {
"authors": [
+ "Acamicamacaraca",
+ "BadDog",
+ "FriedrickMILBarbarossa",
+ "Kizule",
"Milicevic01",
"Millosh",
"Rancher",
"Sasa Stefanovic",
"Verlor",
+ "Zoranzoki21",
"Јованвб",
+ "Вукан Ц",
"Жељко Тодоровић",
"Михајло Анђелковић",
"Обрадовић Горан",
- "Сербијана",
- "Acamicamacaraca",
- "Zoranzoki21",
- "BadDog"
+ "Сербијана"
]
},
- "checkuser-summary": "Ова алатка скенира скорашње измене и враћа IP адресе које је корисник користио или приказује податке о кориснику/изменама за дати IP.\nКорисници и измене IP адресе клијента се могу добавити преко XFF заглавља додавањем <code>/xff</code> иза IP адресе. Формати IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128) су подржани.\nНеће бити враћено више од 5.000 измена због перформанси.\nКористите ово у складу с правилима.",
- "checkuser-desc": "Даје корисницима с одговарајућим правима могућност да провере IP адресе корисника и друге информације.",
- "checkuser-logcase": "Претрага дневника је осетљива на мала и велика слова.",
- "checkuser": "Провери корисника",
- "checkuserlog": "Дневник чекјузера",
+ "checkuser-summary": "Ова алатка врши преглед скорашњих измена и проналази корисничке IP адресе или приказује податке о кориснику/изменама поједине IP адресе.\nКорисници и измене IP адресе клијента могу се добавити преко XFF заглавља додавањем ознаке <code>/xff</code> иза IP адресе. Формати IPv4 (CIDR $1-32) и IPv6 (CIDR $2-128) су подржани.\nЗбог перформанси, неће бити враћено више од 5.000 измена.\nКористите алатку у складу с правилима.",
+ "checkuser-desc": "Даје корисницима са одговарајућим правима могућност провере IP адреса и других информација",
+ "checkuser-logcase": "Претрага дневника разликује мала и велика слова.",
+ "checkuser": "Провера корисника",
+ "checkuserlog": "Дневник провере корисника",
"checkuser-contribs": "провери корисничке IP адресе",
- "checkuser-contribs-log": "скорашње провере",
+ "checkuser-contribs-log": "недавне провере",
"group-checkuser": "Чекјузери",
"group-checkuser-member": "{{GENDER:$1|чекјузер}}",
"right-checkuser": "проверавање корисничких IP адреса и других информација",
- "right-checkuser-log": "преглед дневника чекјузера",
+ "right-checkuser-log": "преглед дневника провере корисника",
"action-checkuser": "проверавате корисничке IP адресе и друге информације",
- "action-checkuser-log": "прегледате дневнике чекјузера",
+ "action-checkuser-log": "прегледате дневнике провере корисника",
"grouppage-checkuser": "{{ns:project}}:Чекјузер",
"checkuser-reason": "Разлог:",
- "checkuser-reason-api": "АПИ: $1",
- "checkuser-showlog": "Пребаци на дневник чекјузера",
- "checkuser-query": "Упит на скорашње измене.",
+ "checkuser-reason-api": "API: $1",
+ "checkuser-showlog": "Пребаци на дневник проверавача",
+ "checkuser-query": "Претражи скорашње измене",
"checkuser-target": "IP адреса или корисничко име:",
- "checkuser-users": "Добави кориснике",
- "checkuser-edits": "Добави измене",
- "checkuser-ips": "Добави IP адресе",
+ "checkuser-users": "Пронађи кориснике",
+ "checkuser-edits": "Пронађи измене",
+ "checkuser-ips": "Пронађи IP адресе",
"checkuser-period": "Трајање:",
- "checkuser-week-1": "последња недеља",
- "checkuser-week-2": "последње две недеље",
+ "checkuser-week-1": "последња седмица",
+ "checkuser-week-2": "последње две седмице",
"checkuser-month": "последњих 30 дана",
"checkuser-all": "све",
"checkuser-cidr-label": "Проналажење заједничког опсега и погођених адресе за списак IP адреса",
- "checkuser-cidr-res": "Уобичајени CIDR",
- "checkuser-empty": "Дневник не садржи ставке.",
+ "checkuser-cidr-res": "Заједнички CIDR:",
+ "checkuser-empty": "Дневник је празан.",
"checkuser-nomatch": "Нема погодака.",
- "checkuser-nomatch-edits": "Нису нађена поклапања.\nПоследња измена је била на $1 у $2.",
- "checkuser-check": "Провера",
- "checkuser-log-fail": "Не могу да додам унос у евиденцији",
+ "checkuser-nomatch-edits": "Нема погодака.\nПоследња измена је била $1 у $2.",
+ "checkuser-check": "Провери",
+ "checkuser-check-this-user": "Провери корисника",
+ "checkuser-recent-checks": "Недавне провере овог корисника",
+ "checkuser-log-fail": "Није могуће додати унос у дневник",
"checkuser-nolog": "Датотека дневника није пронађена.",
"checkuser-blocked": "Блокиран",
- "checkuser-gblocked": "Блокиран глобално",
- "checkuser-locked": "Закључано",
- "checkuser-wasblocked": "Претходно блокиран",
- "checkuser-localonly": "Није унифицирано",
+ "checkuser-gblocked": "Глобално блокиран",
+ "checkuser-locked": "Закључан",
+ "checkuser-wasblocked": "Раније блокиран",
+ "checkuser-localonly": "Није обједињен",
"checkuser-massblock": "Блокирај изабране кориснике",
- "checkuser-massblock-text": "Изабрани налози ће бити блокирани на неодређено, уз обележене опције аутоблокирања и забране прављења налога.\nIP адресе ће бити блокиране на недељу дана за IP кориснике, уз забрану прављења налога.",
- "checkuser-blockemail": "Онемогући кориснику да шаље имејлове",
- "checkuser-blocktalk": "Онемогући кориснику да уређује своју страницу за разговор",
+ "checkuser-massblock-text": "Изабрани налози биће трајно блокирани уз омогућене опције аутоматског блокирања и забране отварања налога.\nIP адресе биће блокиране на једну седмицз за анонимне кориснике уз забрану отварања налога.",
+ "checkuser-blockemail": "Онемогући слање имејлова",
+ "checkuser-blocktalk": "Онемогући уређивање сопствене странице за разговор за време блокирања",
"checkuser-blocktag": "Замени корисничке странице са:",
- "checkuser-blocktag-talk": "Замени стране за разговор са:",
+ "checkuser-blocktag-talk": "Замени странице за разговор са:",
"checkuser-massblock-commit": "Блокирај изабраног корисника",
"checkuser-block-success": "'''{{PLURAL:$2|Корисник|Корисници}} $1 {{PLURAL:$2|је сада блокиран|су сада блокирани}}.'''",
- "checkuser-block-failure": "'''Нема блокираних корисника.'''",
+ "checkuser-block-failure": "'''Ниједан корисник није блокиран.'''",
"checkuser-block-limit": "Изабрано је превише корисника.",
- "checkuser-block-noreason": "Морате дати разлог за блок.",
+ "checkuser-block-noreason": "Морате да наведете разлог блокирања.",
+ "checkuser-centralauth-multilock": "Закључавање више изабраних налога",
"checkuser-noreason": "Морате да наведете разлог за овај упит.",
- "checkuser-accounts": "$1 {{PLURAL:$1|нови налог|нова налога|нових налога}}",
- "checkuser-too-many": "Пронађено превише резултата (према процени захтева), сузите CIDR.\nОвде су коришћене IP адресе (највише 5.000, поређене по адреси):",
+ "checkuser-too-many": "Пронађено је превише резултата (према процени захтева), сузите CIDR.\nОвде су коришћене IP адресе (највише $1, поређене по адреси):",
"checkuser-user-nonexistent": "Наведени корисник не постоји.",
- "checkuser-search": "Претрага уноса у евиденцији чекјузера",
+ "checkuser-search": "Претрага ставки у дневнику чекјузера",
"checkuser-search-submit": "Претражи",
"checkuser-search-initiator": "покретач",
"checkuser-search-target": "циљ",
"checkuser-log-search-target": "Циљ:",
+ "checkuser-log-search-type": "Претрага по:",
"checkuser-ipeditcount": "~$1 од свих корисника",
- "checkuser-showmain": "Назад на главни образац за проверавање корисника",
+ "checkuser-showmain": "Пребаци ме на главни образац проверавача",
"checkuser-limited": "'''Ови резултати су скраћени због перформанси.'''",
- "checkuser-autocreate-action": "је аутоматски направљен",
- "checkuser-create-action": "је направљен",
- "checkuser-email-action": "имејл је послат кориснику „$1“",
- "checkuser-reset-action": "resetuj lozinku za korisnika „$1“"
+ "checkuser-log-entry-userips": "$3, $1 је преузео IP адресе за $2",
+ "checkuser-log-entry-ipedits": "$3, $1 је преузео измене за <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 је преузео кориснике за <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 је преузео измене за XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 је преузео кориснике за XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-useredits": "$3, $1 је преузео измене за $2",
+ "checkuser-autocreate-action": "је аутоматски отворен",
+ "checkuser-create-action": "је отворен",
+ "checkuser-email-action": "имејл је послат кориснику „$1”",
+ "checkuser-reset-action": "ресетуј лозинку корисника „$1”",
+ "checkuser-token-fail": "Сесија је отказана. Покушајте поново.",
+ "checkuser-login-failure": "Пријављивање на пројекат као $1 није успело",
+ "checkuser-login-success": "Успешто пријављивање на пројекат као $1",
+ "checkuser-investigateblock-target": "Корисничка имена или IP адресе",
+ "checkuser-investigateblock-actions": "Радње за блокирање",
+ "checkuser-investigateblock-options": "Додатне могућности",
+ "checkuser-investigateblock-notice-user-page-label": "Пошаљи обавештење на корисничкој страници",
+ "checkuser-investigateblock-notice-position-label": "Положај",
+ "checkuser-investigateblock-notice-text-label": "Викитекст",
+ "checkuser-investigateblock-notice-append": "Додај на дно странице",
+ "checkuser-investigateblock-notice-prepend": "Додај на врх странице",
+ "checkuser-investigateblock-notice-replace": "Замени страницу",
+ "checkuser-investigate": "Испитивање",
+ "checkuser-investigate-legend": "Тражење корисничких имена, IP адреса или опсега",
+ "checkuser-investigate-notice-no-results": "Нема резултата.",
+ "checkuser-investigate-targets-label": "Корисничко име или IP адреса",
+ "checkuser-investigate-targets-placeholder": "Корисничко име или 1.1.1.1",
+ "checkuser-investigate-reason-label": "Разлог",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Блокиран",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|измена|измене|измена}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Није блокиран",
+ "checkuser-investigate-preliminary-table-header-blocked": "Статус",
+ "checkuser-investigate-preliminary-table-header-editcount": "Измене",
+ "checkuser-investigate-preliminary-table-header-groups": "Групе",
+ "checkuser-investigate-preliminary-table-header-name": "Корисничко име",
+ "checkuser-investigate-preliminary-table-header-registration": "Приложени датум",
+ "checkuser-investigate-preliminary-table-header-wiki": "Вики",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Вики није пронађен"
}
diff --git a/CheckUser/i18n/sr-el.json b/CheckUser/i18n/sr-el.json
index 7be3e0d5..2be28843 100644
--- a/CheckUser/i18n/sr-el.json
+++ b/CheckUser/i18n/sr-el.json
@@ -59,7 +59,6 @@
"checkuser-block-limit": "Izabrano je previše korisnika.",
"checkuser-block-noreason": "Morate dati razlog za blok.",
"checkuser-noreason": "Morate da navedete razlog za ovaj upit.",
- "checkuser-accounts": "$1 {{PLURAL:$1|novi nalog|nova naloga|novih naloga}}",
"checkuser-too-many": "Nađeno je previše rezultata (prema proceni zahteva). Molimo Vas da suzite CIDR.\nOvde su korišćene IP adrese (najviše 5.000, sortiranih po adresi):",
"checkuser-user-nonexistent": "Navedeni korisnik ne postoji.",
"checkuser-search": "Pretraga dnevnika čekjuzera",
diff --git a/CheckUser/i18n/stq.json b/CheckUser/i18n/stq.json
index b9f88f30..4ac953e8 100644
--- a/CheckUser/i18n/stq.json
+++ b/CheckUser/i18n/stq.json
@@ -52,7 +52,6 @@
"checkuser-block-limit": "Der wuuden toufuul Benutsere uutwääld.",
"checkuser-block-noreason": "Du moast n Gruund foar ju Speere anreeke.",
"checkuser-noreason": "Foar disse Oufroage mout ne Begruundenge ounroat wäide.",
- "checkuser-accounts": "{{PLURAL:$1|1 näi Benutserkonto|$1 näie Benutserkonten}}",
"checkuser-too-many": "Ju Lieste fon Resultoate is tou loang (ätter ju Skätsenge), gränsje dän IP-Beräk fääre ien. Hier sunt do benutsede IP-Adressen (maximoal 5000, sortierd ätter Adresse):",
"checkuser-user-nonexistent": "Die anroate Benutser bestoant nit.",
"checkuser-search": "Säike (uk ap Düütsk4)",
diff --git a/CheckUser/i18n/sv.json b/CheckUser/i18n/sv.json
index ccf9451d..7c0fb00a 100644
--- a/CheckUser/i18n/sv.json
+++ b/CheckUser/i18n/sv.json
@@ -2,20 +2,21 @@
"@metadata": {
"authors": [
"Ainali",
+ "Bengtsson96",
"Boivie",
+ "Hangsna",
+ "Jenniesarina",
+ "Jopparn",
"Lejonel",
"Leo Johannes",
+ "Lokal Profil",
"M.M.S.",
"MagnusA",
+ "McDutchie",
"Najami",
"Per",
- "WikiPhoenix",
- "Hangsna",
- "Lokal Profil",
- "Jenniesarina",
- "Jopparn",
- "McDutchie",
- "Bengtsson96"
+ "Sabelöga",
+ "WikiPhoenix"
]
},
"checkuser-summary": "Det här verktyget söker igenom de senaste ändringarna för att hämta IP-adresser för en användare, eller redigeringar och användare för en IP-adress.\nAnvändare och redigeringar kan visas med IP-adress från XFF genom att lägga till \"/xff\" efter IP-adressen. Verktyget stödjer IPv4 (CIDR $1-32) och IPv6 (CIDR $2-128).\nPå grund av prestandaskäl så visas inte mer än 5000 redigeringar. Använd verktyget i enlighet med policy.",
@@ -26,15 +27,15 @@
"checkuser-contribs": "kontrollera användarens IP-adresser",
"checkuser-contribs-log": "senaste användarkontroller",
"group-checkuser": "Användarkontrollanter",
- "group-checkuser-member": "{{GENDER:$1|IP-kontrollant}}",
+ "group-checkuser-member": "{{GENDER:$1|användarkontrollant}}",
"right-checkuser": "Kontrollera användares IP-adresser och annan information",
- "right-checkuser-log": "Se loggen över användarkontroller",
+ "right-checkuser-log": "Visa loggen för användarkontroller",
"action-checkuser": "kontrollera användarens IP-adresser och annan information",
- "action-checkuser-log": "visa loggen för IP-kontroll",
+ "action-checkuser-log": "visa loggen för användarkontroll",
"grouppage-checkuser": "{{ns:project}}:Användarkontrollant",
"checkuser-reason": "Anledning:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Visa logg",
+ "checkuser-showlog": "Byt till CheckUser-logg",
"checkuser-query": "Sök de senaste ändringarna",
"checkuser-target": "IP-adress eller användarnamn:",
"checkuser-users": "Hämta användare",
@@ -63,50 +64,129 @@
"checkuser-massblock": "Blockera valda användare",
"checkuser-massblock-text": "Valda konton kommer blockeras på obestämd tid, med autoblockering aktiverad och kontoskapande avaktiverat.\nIP-adresser kommer blockeras i en vecka för anonyma användare, med kontoskapande avaktiverat.",
"checkuser-blockemail": "Förhindra från att skicka e-post",
+ "checkuser-blocktalk": "Förhindra från att redigera sina egna diskussionssidor under blockeringen",
"checkuser-blocktag": "Ersätt användarsidor med:",
"checkuser-blocktag-talk": "Ersätt diskussionssidor med:",
+ "checkuser-reblock": "Åsidosätt befintliga blockeringar",
"checkuser-massblock-commit": "Blockera valda användare",
"checkuser-block-success": "'''{{PLURAL:$2|Användaren|Användarna}} $1 är nu {{PLURAL:$2|blockerad|blockerade}}.'''",
"checkuser-block-failure": "'''Ingen användare blockerades.'''",
"checkuser-block-limit": "För många användare valda.",
"checkuser-block-noreason": "Du måste ange en anledning för blockeringarna.",
+ "checkuser-centralauth-multilock": "Lås flera markerade konton",
"checkuser-noreason": "Du måste uppge en anledning för den här frågan.",
- "checkuser-accounts": "$1 {{PLURAL:$1|nytt konto|nya konton}}",
- "checkuser-too-many": "För många resultat (enligt uppskattning). Du bör söka i ett mindre CIDR-block. Här är de IP-adresser som använts (högst 5000, sorterade efter adress):",
+ "checkuser-too-many": "För många resultat (enligt uppskattning). Du bör söka i ett mindre CIDR-block. Här är de IP-adresser som använts (högst $1, sorterade efter adress):",
"checkuser-user-nonexistent": "Användarnamnet som angavs finns inte.",
- "checkuser-search": "Sök",
+ "checkuser-search": "Sök loggposter för användarkontroll",
"checkuser-search-submit": "Sök",
"checkuser-search-initiator": "kontrollanten",
"checkuser-search-target": "kontrollmålet",
+ "checkuser-log-search-target": "Mål:",
+ "checkuser-log-search-type": "Sök efter:",
"checkuser-ipeditcount": "~$1 från alla användare",
"checkuser-showmain": "Växla till CheckUser huvudformulär",
"checkuser-limited": "'''Dessa resultat har av prestandaskäl blivit avkortade.'''",
"checkuser-log-entry-userips": "$3, $1 hämtade IP-adresser för $2",
- "checkuser-log-entry-ipedits": "$3, $1 hämtade redigeringar för $2",
- "checkuser-log-entry-ipusers": "$3, $1 hämtade användare för $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 hämtade redigeringar för XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 hämtade användare för XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 hämtade redigeringar för <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 hämtade användare för <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 hämtade redigeringar för XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 hämtade användare för XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 hämtade redigeringar för $2",
"checkuser-autocreate-action": "skapades automatiskt",
"checkuser-create-action": "skapades",
"checkuser-email-action": "skickade ett mejl till användare \"$1\"",
"checkuser-reset-action": "återställ lösenord för användare \"$1\"",
"checkuser-token-fail": "Session misslyckande. Var god försök igen.",
- "apihelp-query+checkuser-description": "Kontrollera vilka IP-adresser som används av ett visst användarnamn eller vilka användarnamn som används av en viss IP-adress.",
- "apihelp-query+checkuser-param-request": "Typ av CheckUser begäran:\n;userips:Få IP-adresser för målanvändaren.\n;edits:Få ändringar från mål-IP-adresser eller -intervall.\n;ipusers:Få användare från mål-IP-adresser eller -intervall.",
- "apihelp-query+checkuser-param-target": "Användarnamn, IP-adress eller CIDR-intervall att kontrollera.",
- "apihelp-query+checkuser-param-reason": "Skäl att kontrollera.",
- "apihelp-query+checkuser-param-limit": "Begränsning av rader.",
- "apihelp-query+checkuser-param-timecond": "Tidsgräns för användardata (som \"-2 weeks\" eller \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Använd XFF data istället för IP-adress.",
- "apihelp-query+checkuser-example-1": "Kontrollera IP-adresser för [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Kontrollera redigeringar från 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Få poster från CheckUser-loggen.",
- "apihelp-query+checkuserlog-param-user": "Användarnamn för CheckUsern.",
- "apihelp-query+checkuserlog-param-target": "Kontrollerad användare, IP-adress, eller CIDR-intervall.",
- "apihelp-query+checkuserlog-param-limit": "Begränsning av rader.",
- "apihelp-query+checkuserlog-param-from": "Tidsstämpel att börja räkna upp från.",
- "apihelp-query+checkuserlog-param-to": "Tidsstämpeln att räkna upp till.",
- "apihelp-query+checkuserlog-example-1": "Visa kontroller av [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Visa kontroller av 192.0.2.0/24 efter 2011-10-15T23:00:00Z"
+ "checkuser-login-failure": "Misslyckades att logga in på {{SITENAME}} som $1",
+ "checkuser-login-success": "Loggades in på {{SITENAME}} som $1",
+ "checkuser-link-investigate-label": "Prova det nya verktyget för användarkontroll",
+ "checkuser-investigateblock": "Blockera användare",
+ "checkuser-investigateblock-target": "Användarnamn och IP-adresser",
+ "checkuser-investigateblock-actions": "Åtgärder att blockera",
+ "checkuser-investigateblock-reason": "Anledning",
+ "checkuser-investigateblock-options": "Ytterligare alternativ",
+ "checkuser-investigateblock-email-label": "Förhindra från att skicka e-post",
+ "checkuser-investigateblock-usertalk-label": "Förhindra från att redigera sin egen diskussionssida under blockering",
+ "checkuser-investigateblock-reblock-label": "Åsidosätt befintliga blockeringar",
+ "checkuser-investigateblock-notice-user-page-label": "Lämna ett meddelande på användarsidan",
+ "checkuser-investigateblock-notice-talk-page-label": "Lämna ett meddelande på användardiskussionssidan",
+ "checkuser-investigateblock-notice-position-label": "Position",
+ "checkuser-investigateblock-notice-text-label": "Wikitext",
+ "checkuser-investigateblock-notice-append": "Lägg till i slutet på sidan",
+ "checkuser-investigateblock-notice-prepend": "Lägg till i början på sidan",
+ "checkuser-investigateblock-notice-replace": "Ersätt sida",
+ "checkuser-investigateblock-failure": "Inga användare blockerades. För att åsidosätta befintliga blockeringar, markera: \"{{int:checkuser-investigateblock-reblock-label}}\". En blockering kommer inte åsidosättas om den nya blockeringen är identisk med den befintliga blockeringen.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|Användaren|Användarna}} $1 är nu {{PLURAL:$2|blockerad|blockerade}}.",
+ "checkuser-investigateblock-notices-failed": "En del meddelanden kunde inte läggas till på användarsidorna eller användardiskussionssidorna.",
+ "checkuser-investigate-log": "Undersökningsloggar",
+ "checkuser-investigate-log-entry": "$3, $1 kollade upp information om <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Inga poster i undersökningsloggen hittades.",
+ "checkuser-investigate-log-subtitle": "Byt till undersökningsformuläret",
+ "checkuser-investigate": "Undersök",
+ "checkuser-investigate-page-subtitle": "Nuvarande undersökning för $1",
+ "checkuser-investigate-subtitle-block-button-label": "Blockera",
+ "checkuser-investigate-subtitle-cancel-button-label": "Avbryt",
+ "checkuser-investigate-subtitle-continue-button-label": "Fortsätt",
+ "checkuser-investigate-indicator-new-investigation": "Ny undersökning",
+ "checkuser-investigate-indicator-logs": "Loggar",
+ "checkuser-investigate-legend": "Sök efter användarnamn, IP-adress eller IP-intervall",
+ "checkuser-investigate-notice-no-results": "Det finns inga resultat.",
+ "checkuser-investigate-tab-preliminary-check": "Kontoinformation",
+ "checkuser-investigate-tab-compare": "IP-adresser och användaragenter",
+ "checkuser-investigate-tab-timeline": "Tidslinje",
+ "checkuser-investigate-targets-label": "Användarnamn och IP-adresser",
+ "checkuser-investigate-targets-placeholder": "Användarnamn eller 1.1.1.1",
+ "checkuser-investigate-duration-label": "Varaktighet",
+ "checkuser-investigate-duration-option-all": "Alla",
+ "checkuser-investigate-duration-option-1w": "Senaste veckan",
+ "checkuser-investigate-duration-option-2w": "Senaste 2 veckorna",
+ "checkuser-investigate-duration-option-30d": "Senaste 30 dagarna",
+ "checkuser-investigate-reason-label": "Anledning",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Fliken \"Kontoinformation\" innehåller inte någon information om IP-adresser. Se <span class=\"plainlinks\">[$1 fliken \"IP-adresser och användaragenter\"]</span> för denna information.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Blockerad",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|redigering|redigeringar}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Inte blockerad",
+ "checkuser-investigate-preliminary-table-header-blocked": "Status",
+ "checkuser-investigate-preliminary-table-header-editcount": "Redigeringar",
+ "checkuser-investigate-preliminary-table-header-groups": "Grupper",
+ "checkuser-investigate-preliminary-table-header-name": "Användarnamn",
+ "checkuser-investigate-preliminary-table-header-registration": "Bifogningsdatum",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Wikin hittades inte",
+ "checkuser-investigate-filters-legend": "Filter",
+ "checkuser-investigate-filters-exclude-targets-label": "Dölj följande användare eller IP-adresser",
+ "checkuser-investigate-timeline-notice-no-results": "Inga resultat: Ingen aktivitet har registrerats från dessa användare eller IP-adresser inom de senaste 90 dagarna",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Inga resultat matchar dessa filteringskriterier. Försök att ta bort några filter för att utvidga sökningen.",
+ "checkuser-investigate-compare-copy-button-label": "Visa wikitext",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Proxy-kontroll",
+ "checkuser-investigate-compare-copy-message-label": "Vill du kopiera denna information som en wikitexttabell?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "På grund av tekniska begränsningar har antalet poster som kan visas uppnåtts. Data som returneras för följande mål är ofullständig: $1. Försök använda färre mål, mindre tidsintervall eller mindre IP-intervall.",
+ "checkuser-investigate-compare-notice-no-results": "Inga resultat: Dessa användare eller IP-adresser har inte redigerat inom de senaste 90 dagarna",
+ "checkuser-investigate-compare-notice-no-results-filters": "Inga resultat matchar dessa filteringskriterier. Försök att ta bort några filter för att utvidga sökningen.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Visa alla IP-adress för denna användare",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Visa alla användare på denna IP-adress",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Lägg till denna IP-adress i undersökningen",
+ "checkuser-investigate-compare-table-button-checks-label": "Kontroller",
+ "checkuser-investigate-compare-table-button-contribs-label": "Bidragsgivare",
+ "checkuser-investigate-compare-table-button-filter-label": "Filtrera från resultat",
+ "checkuser-investigate-compare-table-cell-unregistered": "Oregistrerade",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|redigering|redigeringar}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 från alla användare)</i>",
+ "checkuser-investigate-compare-table-header-username": "Användarnamn",
+ "checkuser-investigate-compare-table-header-activity": "Datumintervall",
+ "checkuser-investigate-compare-table-header-ip": "IP-adress",
+ "checkuser-investigate-compare-table-header-useragent": "Användaragent",
+ "checkuser-investigate-subtitle-link-restart-tour": "Starta om rundtur",
+ "checkuser-investigate-tour-targets-title": "Kontrollera flera användare och IP-adresser?",
+ "checkuser-investigate-tour-targets-desc": "Lägg till högst $1 {{PLURAL:$1|användarnamn eller IP-adress|användarnamn eller IP-adresser}} och hämta all information på ett och samma ställe. Ingen fara, vi skapar separata användarkontrollsloggar.",
+ "checkuser-investigate-tour-useragents-title": "Matchande användaragenter?",
+ "checkuser-investigate-tour-useragents-desc": "Lägg muspekaren över en cell för att markera alla andra rader med samma data. Klicka på knappnålsikonen för att behålla markeringen när du går igenom data.",
+ "checkuser-investigate-tour-addusertargets-title": "Behöver du mer sammanhang?",
+ "checkuser-investigate-tour-addusertargets-desc": "Klicka för att se alla andra användare på IP-adressen. Du kan även göra detta för användare och se alla IP-adresser som de har använt. Vi kommer automatiskt skapa poster i loggen för användarkontroller åt dig.",
+ "checkuser-investigate-tour-filterip-title": "Begränsa din undersökning?",
+ "checkuser-investigate-tour-filterip-desc": "Förfina resultatet genom att filtrera bort användarnamn, IP-adresser eller användaragenter. Vill du få tillbaka data? Använd filterpanelen längst upp för att ta bort filter.",
+ "checkuser-investigate-tour-block-title": "Vill du blockera?",
+ "checkuser-investigate-tour-block-desc": "Låter dig välja de användare du vill blockera och tar dig till blockeringsformuläret.",
+ "checkuser-investigate-tour-copywikitext-title": "Vill du kopiera data?",
+ "checkuser-investigate-tour-copywikitext-desc": "Kopiera hela tabellen med ett klick och ta med den till CUWiki. Observera att du endast kopierar det som är synligt på skärmen och inte alla sidor i undersökningen."
}
diff --git a/CheckUser/i18n/szl.json b/CheckUser/i18n/szl.json
index f333fbe6..479810da 100644
--- a/CheckUser/i18n/szl.json
+++ b/CheckUser/i18n/szl.json
@@ -1,10 +1,11 @@
{
"@metadata": {
"authors": [
- "Herr Kriss"
+ "Herr Kriss",
+ "Uostofchuodnego"
]
},
- "checkuser-reason": "Čymu:",
+ "checkuser-reason": "Powōd:",
"checkuser-search": "Šnupej",
"checkuser-search-submit": "Šnupej"
}
diff --git a/CheckUser/i18n/ta.json b/CheckUser/i18n/ta.json
index b3b94b18..988c461d 100644
--- a/CheckUser/i18n/ta.json
+++ b/CheckUser/i18n/ta.json
@@ -53,7 +53,6 @@
"checkuser-block-limit": "மிக அதிகமான பயனர்கள் தேர்ந்தெடுக்கப்பட்டுள்ளது.",
"checkuser-block-noreason": "தடைக்கான காரணத்தை நீங்கள் கண்டிப்பாகத் தரவேண்டும்.",
"checkuser-noreason": "நீங்கள் இவ்வினவலுக்கு ஒரு காரணத்தைக் கட்டாயம் வழங்க வேண்டும்.",
- "checkuser-accounts": "$1 புதிய {{PLURAL:$1|கணக்கு|கணக்குகள்}}",
"checkuser-user-nonexistent": "குறிப்பிடப்பட்ட பயனர் காணப்படவில்லை.",
"checkuser-search": "தேடுக",
"checkuser-search-submit": "தேடுக",
diff --git a/CheckUser/i18n/te.json b/CheckUser/i18n/te.json
index 45409039..4ff87727 100644
--- a/CheckUser/i18n/te.json
+++ b/CheckUser/i18n/te.json
@@ -2,11 +2,11 @@
"@metadata": {
"authors": [
"Chaduvari",
+ "Kiranmayee",
"Mpradeep",
"Ravichandra",
"Veeven",
- "వైజాసత్య",
- "Kiranmayee"
+ "వైజాసత్య"
]
},
"checkuser-summary": "ఈ పరికరం ఓ వాడుకరి వాడిన ఐపీలను, లేదా ఒక ఐపీకి చెందిన దిద్దుబాట్లు, వాడుకరుల డేటాను చూపిస్తుంది.\nక్లయంటు ఐపీకి చెందిన వాడుకరులు, దిద్దుబాట్లను ఐపీకి /xff అని చేర్చి, XFF హెడర్ల ద్వారా వెలికితీయవచ్చు. IPv4 (CIDR $1-32) and IPv6 (CIDR $2-128) లు పనిచేస్తాయి.\nపనితనపు కారణాల వలన 5000 దిద్దుబాట్లకు మించి చూపించము. విధానాల కనుగుణంగా దీన్ని వాడండి.",
@@ -54,7 +54,6 @@
"checkuser-block-limit": "చాలా మంది వాడుకరులను ఎంచుకున్నారు.",
"checkuser-block-noreason": "ఈ నిరోధాలకి మీరు తప్పనిసరిగా కారణం ఇవ్వాలి.",
"checkuser-noreason": "ఈ విచారణకి మీరు తప్పనిసరిగా ఒక కారణాన్ని ఇవ్వాలి.",
- "checkuser-accounts": "$1 కొత్త {{PLURAL:$1|ఖాతా|ఖాతాలు}}",
"checkuser-too-many": "మరీ ఎక్కువ ఫలితాలొచ్చాయి(క్వేరీ ఎస్టిమేటు ప్రకారము), దయచేసి CIDR ను మరింత కుదించండి. వాడిన ఐపీలివిగో (గరిష్ఠంగా 5000 -అడ్రసు వారీగా పేర్చి)",
"checkuser-user-nonexistent": "ఆ వాడుకరి ఉనికిలో లేరు.",
"checkuser-search": "వెతుకు",
@@ -68,5 +67,16 @@
"checkuser-autocreate-action": "యాంత్రికంగా సృష్టించబడింది",
"checkuser-create-action": "సృష్టించిన తేదీ",
"checkuser-email-action": "వాడుకరి \"$1\"కి ఈమెయిలు పంపించాం",
- "checkuser-reset-action": "\"$1\" వాడుకరి సంకేతపదం రీసెట్ చెయ్యి"
+ "checkuser-reset-action": "\"$1\" వాడుకరి సంకేతపదం రీసెట్ చెయ్యి",
+ "checkuser-investigateblock-actions": "నిరోధించాల్సిన చర్యలు",
+ "checkuser-investigateblock-options": "అదనపు ఎంపికలు",
+ "checkuser-investigateblock-notice-position-label": "స్థానం",
+ "checkuser-investigate-subtitle-block-button-label": "నిరోధించు",
+ "checkuser-investigate-subtitle-cancel-button-label": "రద్దుచేయి",
+ "checkuser-investigate-subtitle-continue-button-label": "కొనసాగించు",
+ "checkuser-investigate-tab-preliminary-check": "ఖాతా సమాచారం",
+ "checkuser-investigate-targets-label": "వాడుకరి పేరు,ఐపీ చిరునామాలు",
+ "checkuser-investigate-reason-label": "కారణం",
+ "checkuser-investigate-tour-block-title": "నిరోధించాలని అనుకుంటున్నారా?",
+ "checkuser-investigate-tour-copywikitext-title": "డేటాను కాపీ చేసుకోవాలనుకుంటున్నారా?"
}
diff --git a/CheckUser/i18n/tg-cyrl.json b/CheckUser/i18n/tg-cyrl.json
index 99fd7f07..15049132 100644
--- a/CheckUser/i18n/tg-cyrl.json
+++ b/CheckUser/i18n/tg-cyrl.json
@@ -1,7 +1,8 @@
{
"@metadata": {
"authors": [
- "Ibrahim"
+ "Ibrahim",
+ "ToJack"
]
},
"checkuser-summary": "Ин абзор тағйироти охирро барои ба даст овардани нишонаҳои интернетӣ IP истифода шуда тавассути як корбар ё таъйини вироишҳои анчом шуда тариқи як нишонаи интернетӣ IP, ҷустуҷӯ мекунад.\nКорбарон ва вироишҳои як нишонаи интернетии IP-ро метавон бо таваҷҷӯҳ ба иттилоот сар оянд тариқи XFF бо афзудан нишонаи интернетӣ IP бо \"/xff\" пайдо кард. Ҳар ду протокол IPv4 (CIDR $1-32) ва IPv6 (CIDR $2-128) тавассути ин абзор пуштибонӣ мешаванд.\nНа беш аз 5000 вироиш бо далелҳои зудкорӣ баргардонида хоҳанд шуд. Бо мувофиқи сиёсат ва қоидаҳо инро истода кунед.",
@@ -47,5 +48,6 @@
"checkuser-search-target": "ҳадаф",
"checkuser-showmain": "Бозгашт ба форми аслии бозрасии корбар",
"checkuser-autocreate-action": "ба таври худкор эҷод шуда буд",
- "checkuser-email-action": "почтаи электронӣ ба корбар \"$1\" фиристода шуд"
+ "checkuser-email-action": "почтаи электронӣ ба корбар \"$1\" фиристода шуд",
+ "checkuser-investigate-reason-label": "Сабаб"
}
diff --git a/CheckUser/i18n/th.json b/CheckUser/i18n/th.json
index 47a6d37d..fa5d43bf 100644
--- a/CheckUser/i18n/th.json
+++ b/CheckUser/i18n/th.json
@@ -1,6 +1,8 @@
{
"@metadata": {
"authors": [
+ "Aefgh39622",
+ "Geonuch",
"Horus",
"Mopza",
"Octahedron80",
@@ -9,20 +11,21 @@
},
"checkuser-summary": "เครื่องมือนี้สแกนการเปลี่ยนแปลงล่าสดเพื่อให้ได้มาซึ่งเลขที่อยู่ไอพีที่ผู้ใช้ใช้หรือแสดงข้อมูลการแก้ไข/ผู้ใช้เพื่อให้ได้มาซึ่งเลขที่อยู่ไอพี\nผู้ใช้และการแก้ไขโดยเลขที่อยู่ไอพีรับบริการสามารถได้มาผ่านตัวนำหน้า XFF โดยการผนวกเลขที่อยู่ไอพีกับ \"/xff\" เครื่องมือนี้รองรับ IPv4 (CIDR $1-32) และ IPv6 (CIDR $2-128)\nจะไม่คืนเกินกว่า 5,000 การแก้ไข ด้วยเหตุผลด้านสมรรถนะ\nใช้เครื่องมือนี้ตามนโยบาย",
"checkuser-desc": "อนุญาตอย่างเหมาะสมให้ผู้ใช้สามารถตรวจสอบเลขที่อยู่ไอพีและสารสนเทศอื่นของผู้ใช้",
- "checkuser-logcase": "การค้นหาปูมไวต่ออักษรใหญ่เล็ก",
+ "checkuser-logcase": "การค้นหารายการบันทึกไวต่ออักษรใหญ่เล็ก",
"checkuser": "ตรวจสอบผู้ใช้",
- "checkuserlog": "ประวัติการตรวจสอบผู้ใช้",
+ "checkuserlog": "ปูมการตรวจสอบผู้ใช้",
"checkuser-contribs": "ตรวจสอบหมายเลขไอพีของผู้ใช้",
"checkuser-contribs-log": "การตรวจสอบผู้ใช้ล่าสุด",
- "group-checkuser": "ตรวจสอบผู้ใช้",
- "group-checkuser-member": "ตรวจสอบผู้ใช้",
+ "group-checkuser": "ผู้ตรวจสอบผู้ใช้",
+ "group-checkuser-member": "{{GENDER:$1|ตรวจสอบผู้ใช้}}",
"right-checkuser": "ตรวจสอบหมายเลขไอพีของผู้ใช้และข้อมูลอื่นๆ",
- "right-checkuser-log": "ดูประวัติการตรวจสอบผู้ใช้",
+ "right-checkuser-log": "ดูรายการบันทึกการตรวจสอบผู้ใช้",
"action-checkuser": "ตรวจสอบเลขที่อยู่ไอพีและสารสนเทศอื่นของผู้ใช้",
- "action-checkuser-log": "ดูปูมการตรวจสอบผู้ใช้",
- "grouppage-checkuser": "{{ns:project}}:ตรวจสอบผู้ใช้",
+ "action-checkuser-log": "ดูรายการบันทึกการตรวจสอบผู้ใช้",
+ "grouppage-checkuser": "{{ns:project}}:ผู้ตรวจสอบผู้ใช้",
"checkuser-reason": "เหตุผล:",
- "checkuser-showlog": "แสดงประวัติ",
+ "checkuser-reason-api": "API: $1",
+ "checkuser-showlog": "สลับไปยังรายการบันทึกการตรวจสอบผู้ใช้",
"checkuser-query": "แบบสอบถามการเปลี่ยนแปลงล่าสุด",
"checkuser-target": "หมายเลขไอพีหรือชื่อผู้ใช้:",
"checkuser-users": "รับชื่อผู้ใช้",
@@ -33,17 +36,51 @@
"checkuser-week-2": "2 สัปดาห์ที่แล้ว",
"checkuser-month": "30 วันที่แล้ว",
"checkuser-all": "ทั้งหมด",
+ "checkuser-cidr-label": "ค้นหาช่วงทั่วไปและหมายเลขไอพีที่ได้รับผลกระทบจากรายการหมายเลขไอพี",
+ "checkuser-cidr-res": "CIDR ธรรมดา:",
"checkuser-empty": "ปูมนี้ไม่มีรายการ",
- "checkuser-nomatch": "ไม่พบสิ่งที่ค้นหา",
+ "checkuser-nomatch": "ไม่พบรายการที่ตรงกัน",
+ "checkuser-nomatch-edits": "ไม่พบรายการที่ตรงกัน\nแก้ไขล่าสุดเมื่อ $1 ณ เวลา $2",
+ "checkuser-check": "ตรวจสอบ",
+ "checkuser-check-this-user": "ตรวจสอบผู้ใช้นี้",
+ "checkuser-recent-checks": "การตรวจสอบล่าสุดสำหรับผู้ใช้นี้",
+ "checkuser-log-fail": "ไม่สามารถเพิ่มหน่วยรายการบันทึกได้",
+ "checkuser-nolog": "ไม่พบไฟล์รายการบันทึก",
+ "checkuser-blocked": "ถูกบล็อก",
+ "checkuser-gblocked": "ถูกบล็อกทั่วโลก",
+ "checkuser-locked": "ถูกล็อก",
+ "checkuser-wasblocked": "ถูกบล็อกก่อนหน้านี้",
+ "checkuser-localonly": "ไม่ได้ถูกรวม",
+ "checkuser-massblock": "บล็อกผู้ใช้ที่เลือก",
+ "checkuser-massblock-text": "บัญชีที่เลือกจะถูกบล็อกโดยไม่มีกำหนด และจะบล็อกที่อยู่ไอพีอัตโนมัติและปิดใช้งานการสร้างบัญชีด้วย\nที่อยู่ไอพีจะถูกบล็อกเป็นเวลาหนึ่งสัปดาห์สำหรับผู้ใช้ไม่ระบุตัวตนเท่านั้นและการสร้างบัญชีจะถูกปิดใช้งาน",
+ "checkuser-blockemail": "ป้องกันไม่ให้ส่งอีเมล",
+ "checkuser-blocktalk": "ป้องกันไม่ให้แก้ไขหน้าพูดคุยของตนเองขณะถูกบล็อก",
"checkuser-blocktag": "แทนที่หน้าผู้ใช้ด้วย:",
"checkuser-blocktag-talk": "แทนที่หน้าคุยด้วย:",
- "checkuser-massblock-commit": "ระงับผู้ใช้ที่เลือก",
- "checkuser-block-success": "'''{{PLURAL:$2|ผู้ใช้|ผู้ใช้}}ชื่อ $1 {{PLURAL:$2|ได้ถูก|ได้ถูก}}ระงับการใช้แล้ว'''",
- "checkuser-block-failure": "'''ไม่มีผู้ใช้ถูกระงับ'''",
+ "checkuser-massblock-commit": "บล็อกผู้ใช้ที่เลือก",
+ "checkuser-block-success": "'''{{PLURAL:$2|ผู้ใช้|ผู้ใช้}} $1 {{PLURAL:$2|ได้ถูก|ได้ถูก}}บล็อกแล้ว'''",
+ "checkuser-block-failure": "'''ไม่มีผู้ใช้ที่ถูกบล็อก'''",
"checkuser-block-limit": "เลือกผู้ใช้มากเกินไป",
- "checkuser-block-noreason": "คุณต้องให้เหตุผลในการระงับด้วย",
+ "checkuser-block-noreason": "คุณต้องให้เหตุผลในการบล็อก",
+ "checkuser-noreason": "คุณต้องให้เหตุผลสำหรับการสอบถามนี้",
"checkuser-too-many": "มีผลลัพธ์มากเกินไป (จากการคาดคะเนของแบบสอบถาม) กรุณาทำให้ CIDR เฉพาะเจาะจงมากขึ้น\nนี่คือหมายเลขไอพีที่ถูกใช้ (สูงสุด 5000 เรียงตามหมายเลขไอพี)",
"checkuser-user-nonexistent": "ไม่พบผู้ใช้ที่กำหนด",
- "checkuser-search": "สืบค้น",
- "checkuser-search-submit": "สืบค้น"
+ "checkuser-search": "ค้นหาหน่วยรายการบันทึกการตรวจสอบผู้ใช้",
+ "checkuser-search-submit": "สืบค้น",
+ "checkuser-search-initiator": "ผู้ตรวจสอบข้อมูล",
+ "checkuser-search-target": "เป้าหมาย",
+ "checkuser-log-search-type": "ค้นหาตาม:",
+ "checkuser-ipeditcount": "~$1 จากผู้ใช้ทั้งหมด",
+ "checkuser-showmain": "สลับไปยังแบบฟอร์มหลักการตรวจสอบผู้ใช้",
+ "checkuser-limited": "'''ผลลัพธ์เหล่านี้ได้ถูกตัดทอนเนื่องด้วยเหตุผลเกี่ยวกับประสิทธิภาพ'''",
+ "checkuser-log-entry-userips": "$3, $1 ได้รับหมายเลขไอพีจาก $2",
+ "checkuser-log-entry-ipedits": "$3, $1 ได้รับรายการแก้ไขจาก <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 ได้รับชื่อผู้ใช้จาก <bdi>$2</bdi>",
+ "checkuser-autocreate-action": "ถูกสร้างขึ้นโดยอัตโนมัติ",
+ "checkuser-create-action": "ถูกสร้างขึ้น",
+ "checkuser-email-action": "ส่งอีเมลหาผู้ใช้ \"$1\"",
+ "checkuser-reset-action": "ตั้งค่ารหัสผ่านสำหรับผู้ใช้ \"$1\" ใหม่",
+ "checkuser-token-fail": "เซสชันล้มเหลว โปรดลองอีกครั้ง",
+ "checkuser-login-failure": "ไม่สามารถเข้าสู่ระบบ {{SITENAME}} ในชื่อ $1 ได้",
+ "checkuser-login-success": "เข้าสู่ระบบ {{SITENAME}} ในชื่อ $1 สำเร็จแล้ว"
}
diff --git a/CheckUser/i18n/ti.json b/CheckUser/i18n/ti.json
new file mode 100644
index 00000000..8bf88263
--- /dev/null
+++ b/CheckUser/i18n/ti.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joanmp17"
+ ]
+ },
+ "checkuser-investigate-preliminary-table-header-editcount": "ምምዕርራያት"
+}
diff --git a/CheckUser/i18n/tk.json b/CheckUser/i18n/tk.json
index 7a5ade70..87aae8bf 100644
--- a/CheckUser/i18n/tk.json
+++ b/CheckUser/i18n/tk.json
@@ -47,7 +47,6 @@
"checkuser-block-limit": "Aşa köp ulanyjy saýlanyldy.",
"checkuser-block-noreason": "Blokirlemeler üçin sebäp görkezmeli.",
"checkuser-noreason": "Bu talap üçin sebäp görkezmeli.",
- "checkuser-accounts": "$1 täze {{PLURAL:$1|hasap|hasap}}",
"checkuser-user-nonexistent": "Görkezilen ulanyjy ýok.",
"checkuser-search": "Gözle",
"checkuser-search-submit": "Gözle",
diff --git a/CheckUser/i18n/tl.json b/CheckUser/i18n/tl.json
index 95213d47..50fd2296 100644
--- a/CheckUser/i18n/tl.json
+++ b/CheckUser/i18n/tl.json
@@ -56,7 +56,6 @@
"checkuser-block-limit": "Napakaraming napiling mga tagagamit.",
"checkuser-block-noreason": "Dapat kang magbigay ng isang dahilan para sa mga paghahadlang.",
"checkuser-noreason": "Dapat kang magbigay ng dahilan para sa tanong na ito.",
- "checkuser-accounts": "$1 {{PLURAL:$1|bagong account|mga bagong account}}",
"checkuser-too-many": "Napakaraming mga resulta (ayon sa taya ng pagtatanong), pakikiputan pababa ang CIDR.\nNarito ang ginamit na mga IP (5000 pinakamarami, inayos ayon sa adres):",
"checkuser-user-nonexistent": "Hindi umiiral ang tinukoy na tagagamit.",
"checkuser-search": "Maghanap",
diff --git a/CheckUser/i18n/tly.json b/CheckUser/i18n/tly.json
new file mode 100644
index 00000000..fa241f98
--- /dev/null
+++ b/CheckUser/i18n/tly.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Patriot Kur"
+ ]
+ },
+ "checkuser-all": "həmə",
+ "checkuser-investigate-duration-option-all": "Həmə"
+}
diff --git a/CheckUser/i18n/to.json b/CheckUser/i18n/to.json
index 6e9ca0aa..00ed28bf 100644
--- a/CheckUser/i18n/to.json
+++ b/CheckUser/i18n/to.json
@@ -1,5 +1,7 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser": "Siviʻi ʻa e ʻetita",
"group-checkuser": "Siviʻi kau ʻetita",
"group-checkuser-member": "Siviʻi ʻa e ʻetita"
diff --git a/CheckUser/i18n/tr.json b/CheckUser/i18n/tr.json
index e8a23736..74a54e89 100644
--- a/CheckUser/i18n/tr.json
+++ b/CheckUser/i18n/tr.json
@@ -1,56 +1,58 @@
{
"@metadata": {
"authors": [
+ "BaRaN6161 TURK",
"Dbl2010",
"Erkan Yilmaz",
+ "HakanIST",
+ "Hedda",
"Joseph",
"Karduelis",
"Mach",
- "Suelnur",
- "Vito Genovese",
+ "McDutchie",
+ "MuratTheTurkish",
"Sadrettin",
- "Ömer Berkay",
"Sayginer",
- "McDutchie",
- "HakanIST",
- "Hedda"
+ "Suelnur",
+ "Vito Genovese",
+ "Ömer Berkay"
]
},
"checkuser-summary": "Bu araç bir kullanıcı tarafından kullanılan IP'leri almak için son değişiklikleri tarar ya da bir IP için değişiklik/kullanıcı verisini gösterir.\nAlıcı IP'deki kullanıcı ve değişiklikler, IP'ye \"/xff\" eklenmesiyle XFF başlıklarıyla alınabilir. IPv4 (CIDR $1-32) ve IPv6 (CIDR $2-128) desteklenmektedir.\nPerformans nedeniyle 5000'den fazla değişiklik dönmeyecektir.\nBunu ilkelere uygun olarak kullanın.",
"checkuser-desc": "Kullanıcıların IP adreslerini ve diğer bilgilerini denetleme yeteneği için, uygun izinleri kullanıcılara tahsis eder",
"checkuser-logcase": "Günlük araması büyük-küçük harfe duyarlıdır.",
"checkuser": "Denetçi",
- "checkuserlog": "Denetçi kaydı",
- "checkuser-contribs": "kullanıcı IPlerini kontrol et",
+ "checkuserlog": "Denetçi günlüğü",
+ "checkuser-contribs": "kullanıcı IP'lerini kontrol et",
"checkuser-contribs-log": "son kullanıcı kontrolleri",
"group-checkuser": "Denetçiler",
"group-checkuser-member": "{{GENDER:$1|denetçi}}",
"right-checkuser": "Kullanıcıların IP adreslerini ve diğer bilgilerini denetle",
- "right-checkuser-log": "Kullanıcıdenetle günlüğünü gör",
- "action-checkuser": "kullanıcının IP adreslerini ve diğer bilgilerini denetle",
- "action-checkuser-log": "Kullanıcıdenetle günlüğünü gör",
+ "right-checkuser-log": "Denetçi günlüğünü gör",
+ "action-checkuser": "denetçilerin IP adresleri ve diğer bilgileri",
+ "action-checkuser-log": "denetçi günlüğünü gör",
"grouppage-checkuser": "{{ns:project}}:Denetçi",
"checkuser-reason": "Gerekçe:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Logu göster",
+ "checkuser-showlog": "Denetçi günlüğüne değiştir",
"checkuser-query": "Son değişiklikleri sorgula",
"checkuser-target": "IP adresi veya kullanıcı adı:",
"checkuser-users": "Kullanıcıları bulup getir",
"checkuser-edits": "Değişiklikleri al",
- "checkuser-ips": "IPleri bulup getir",
+ "checkuser-ips": "IP'leri bulup getir",
"checkuser-period": "Süre:",
- "checkuser-week-1": "son hafta",
+ "checkuser-week-1": "geçen hafta",
"checkuser-week-2": "son iki hafta",
"checkuser-month": "son 30 gün",
"checkuser-all": "hepsi",
- "checkuser-cidr-label": "Bir IP adresi listesi için ortak aralığı ve etkilenen adresleri bul",
- "checkuser-cidr-res": "Ortak CIDR:",
+ "checkuser-cidr-label": "Bir IP adresi listesi için genel aralığı ve etkilenen adresleri bul",
+ "checkuser-cidr-res": "Genel CIDR:",
"checkuser-empty": "Günlükte başka öğe yok.",
- "checkuser-nomatch": "Eşleşen bulunamadı.",
- "checkuser-nomatch-edits": "Eşleşen bulunamadı.\nSon değişiklik $1 tarihinde $2 saatinde.",
+ "checkuser-nomatch": "Eşleşme bulunamadı.",
+ "checkuser-nomatch-edits": "Eşleşme bulunamadı.\nSon değişiklik $1 tarihinde $2 saatinde.",
"checkuser-check": "Kontrol et",
"checkuser-check-this-user": "Bu kullanıcıyı kontrol et",
- "checkuser-recent-checks": "Bu kullanıcı için son kontroller",
+ "checkuser-recent-checks": "Bu kullanıcının son kontrolleri",
"checkuser-log-fail": "Günlük girdisi eklenemiyor",
"checkuser-nolog": "Günlük dosyası bulunamadı.",
"checkuser-blocked": "Engellendi",
@@ -61,9 +63,10 @@
"checkuser-massblock": "Seçili kullanıcıları engelle",
"checkuser-massblock-text": "Seçili hesaplar süresiz olarak engellenecektir, IP adresinden otomatik engelleme devrede ve hesap oluşturma devre dışı olarak.\nIP adresleri sadece anonim kullanıcılar için 1 hafta boyunca engellenecektir ve hesap oluşturma devre dışı olacaktır.",
"checkuser-blockemail": "E-posta göndermesini önle",
- "checkuser-blocktalk": "Engelliyken kendi mesaj sayfasında değişiklik yapmasını önle",
+ "checkuser-blocktalk": "Engellenirken kendi tartışma sayfalarını düzenlemeyi önle",
"checkuser-blocktag": "Kullanıcı sayfalarını şununla yer değiştir:",
"checkuser-blocktag-talk": "Tartışma sayfalarını şununla yer değiştir:",
+ "checkuser-reblock": "Mevcut engelleri geçersiz kıl",
"checkuser-massblock-commit": "Seçili kullanıcıları engelle",
"checkuser-block-success": "'''$1 {{PLURAL:$2|kullanıcısı|kullanıcıları}} artık engellendi.'''",
"checkuser-block-failure": "'''Hiçbir kullanıcı engellenmedi.'''",
@@ -71,51 +74,118 @@
"checkuser-block-noreason": "Engellemeler için bir neden belirtmelisiniz.",
"checkuser-centralauth-multilock": "Seçili hesapları toplu kilitle",
"checkuser-noreason": "Bu sorgu için bir gerekçe göstermelisiniz.",
- "checkuser-accounts": "$1 yeni {{PLURAL:$1|hesap|hesap}}",
- "checkuser-too-many": "Çok fazla sonuç var (sorgu tahminine göre), lütfen CIDR'ı daraltın.\nKullanılan IP'ler (maks 5000, adrese göre sıralı):",
+ "checkuser-too-many": "Çok fazla sonuç var (sorgu tahminine göre), lütfen CIDR'ı daraltın.\nKullanılan IP' adresleri (maksimum $1, adrese göre sıralı):",
"checkuser-user-nonexistent": "Belirtilen kullanıcı mevcut değil.",
"checkuser-search": "Denetçi günlüğünde ara",
"checkuser-search-submit": "Ara",
- "checkuser-search-initiator": "Başlatan",
- "checkuser-search-target": "Hedef",
+ "checkuser-search-initiator": "başlatan",
+ "checkuser-search-target": "hedef",
"checkuser-log-search-target": "Hedef:",
"checkuser-log-search-type": "Arama ölçütü:",
"checkuser-ipeditcount": "tüm kullanıcılardan ~$1",
- "checkuser-showmain": "KullancıDenetle ana formuna geri dön",
+ "checkuser-showmain": "Denetçi ana formuna değiştir",
"checkuser-limited": "'''Performans nedeniyle sonuçlar kırpıldı.'''",
- "checkuser-log-entry-userips": "$3, $1 IP adreslerini aldı: $2",
- "checkuser-log-entry-ipedits": "$3, $1 değişiklikleri aldı: $2",
- "checkuser-log-entry-ipusers": "$3, $1 kullanıcı isimlerini aldı: $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 değişiklikleri aldı: XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 kullanıcı isimlerini aldı: XFF $2",
+ "checkuser-log-entry-userips": "$3, $1 IP adreslerini aldı: $2",
+ "checkuser-log-entry-ipedits": "$3, $1 değişiklikleri aldı: <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 kullanıcı isimlerini aldı: <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 değişiklikleri aldı: XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 kullanıcı isimlerini aldı: XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 değişiklikleri aldı: $2",
"checkuser-autocreate-action": "otomatik olarak oluşturuldu",
"checkuser-create-action": "oluşturuldu",
"checkuser-email-action": "\"$1\" kullanıcısına e-posta gönder",
- "checkuser-reset-action": "\"$1\" kullanıcısı için parolayı sıfırla",
+ "checkuser-reset-action": "\"$1\" kullanıcıya parolayı sıfırla",
"checkuser-token-fail": "Oturum hatası. Lütfen tekrar deneyin.",
"checkuser-login-failure": "$1 olarak {{SITENAME}} sitesinde oturum açma işlemi başarısız oldu",
"checkuser-login-success": "$1 olarak {{SITENAME}} sitesinde oturum başarıyla açıldı",
- "apihelp-query+checkuser-description": "Belirli bir kullanıcı adı tarafından hangi IP adreslerinin kullanıldığını veya kullanıcı adlarının belirli bir IP adresi tarafından kullanıldığını kontrol edin.",
- "apihelp-query+checkuser-summary": "Belirli bir kullanıcı adı tarafından hangi IP adreslerinin kullanıldığını veya kullanıcı adlarının belirli bir IP adresi tarafından kullanıldığını kontrol edin.",
- "apihelp-query+checkuser-param-request": "Kullanıcıdenetle isteğinin türü:\n;userips:Hedef kullanıcının IP adreslerini al.\n;edits:Hedef IP adresleri veya IP aralığındaki değişiklikleri al.\nipusers:Hedef IP adresleri veya IP aralığındaki kullanıcıları al.",
- "apihelp-query+checkuser-param-target": "Kullanıcı adı, IP adresi veya CIDR aralığını kontrol et.",
- "apihelp-query+checkuser-param-reason": "Kontrol nedeni.",
- "apihelp-query+checkuser-param-limit": "Satır sınırı",
- "apihelp-query+checkuser-param-timecond": "Kullanıcı verilerinin zaman sınırı (\"-2 weeks\" veya \"2 weeks ago\" gibi).",
- "apihelp-query+checkuser-param-xff": "IP adresi yerine XFF veri kullanın.",
- "apihelp-query+checkuser-example-1": "[[User:Example]] için IP adreslerini kontrol et",
- "apihelp-query+checkuser-example-2": "192.0.2.0/24 tarafından yapılan değişiklikleri kontrol et",
- "apihelp-query+checkuserlog-description": "Denetçi günlüğünden girdiler alın.",
- "apihelp-query+checkuserlog-summary": "Denetçi günlüğünden girdiler alın.",
- "apihelp-query+checkuserlog-param-user": "Denetçi olan kullanıcı adları.",
- "apihelp-query+checkuserlog-param-target": "Kontrol edilen IP adresleri veya CIDR aralığı.",
- "apihelp-query+checkuserlog-param-limit": "Satır sınırı.",
- "apihelp-query+checkuserlog-param-from": "Numaralandırmaya başlamak için zaman bilgisi.",
- "apihelp-query+checkuserlog-param-to": "Numaralandırmayı sonlandırmak için zaman bilgisi.",
- "apihelp-query+checkuserlog-example-1": "[[User:Example]] için yapılan kontrolleri göster",
- "apihelp-query+checkuserlog-example-2": "2011-10-15T23:00:00Z tarihinden sonraki 192.0.2.0/24 kontrollerini göster",
- "apierror-checkuser-missingsummary": "Kontrol için neden tanımlamanız gerekir.",
- "apierror-checkuser-timelimit": "Doğru zaman sınırını kullanmanız gerekiyor (''-2 hafta'' veya ''2 hafta önce'' gibi)",
- "apierror-checkuser-invalidmode": "Geçersiz istek modu"
+ "checkuser-link-investigate-label": "Yeni Denetçi aracını deneyin",
+ "checkuser-investigateblock": "Kullanıcıları engelle",
+ "checkuser-investigateblock-target": "Kullanıcı adları ve IP adresleri",
+ "checkuser-investigateblock-actions": "Engellenecek eylemler",
+ "checkuser-investigateblock-reason": "Sebep",
+ "checkuser-investigateblock-options": "Ek seçenekler",
+ "checkuser-investigateblock-email-label": "E-posta göndermesini önle",
+ "checkuser-investigateblock-usertalk-label": "Engellenirken kendi tartışma sayfalarını düzenlemeyi önle",
+ "checkuser-investigateblock-reblock-label": "Mevcut engelleri geçersiz kıl",
+ "checkuser-investigateblock-notice-user-page-label": "Kullanıcı sayfasında bir bildirim bırakın",
+ "checkuser-investigateblock-notice-talk-page-label": "Kullanıcı Mesaj sayfasında bir bildirim bırakın",
+ "checkuser-investigateblock-notice-position-label": "Konum",
+ "checkuser-investigateblock-notice-text-label": "Vikimetin",
+ "checkuser-investigateblock-notice-append": "Sayfaya ekle",
+ "checkuser-investigateblock-notice-prepend": "Sayfa başa ekle",
+ "checkuser-investigateblock-notice-replace": "Sayfayı değiştir",
+ "checkuser-investigateblock-failure": "Hiçbir kullanıcı engellenmedi. Mevcut blokları geçersiz kılmak için şunları kontrol edin: \"{{int:checkuser-investigateblock-reblock-label}}\". Yeni engel mevcut engel ile aynı ise bir engel geçersiz kılmayacaktır.",
+ "checkuser-investigateblock-success": "$1 {{PLURAL:$2|kullanıcısı|kullanıcıları}} artık engellendi.",
+ "checkuser-investigateblock-notices-failed": "Bazı bildirimler kullanıcı sayfalarına veya kullanıcı mesaj sayfalarına eklenemedi.",
+ "checkuser-investigate-log": "Araştırma günlükleri",
+ "checkuser-investigate-log-entry": "$3, $1 <bdi>$2</bdi> için bilgi aradı $4",
+ "checkuser-investigate-log-empty": "Araştırma günlüğü girişi bulunamadı.",
+ "checkuser-investigate-log-subtitle": "Soruşturma formuna değiştir",
+ "checkuser-investigate": "İncele",
+ "checkuser-investigate-page-subtitle": "Mevcut soruşturma $1",
+ "checkuser-investigate-subtitle-block-button-label": "Engelle",
+ "checkuser-investigate-subtitle-cancel-button-label": "İptal",
+ "checkuser-investigate-subtitle-continue-button-label": "Devam et",
+ "checkuser-investigate-indicator-new-investigation": "Yeni soruşturma",
+ "checkuser-investigate-indicator-logs": "Günlükler",
+ "checkuser-investigate-legend": "Kullanıcı adlarını, IP adreslerini veya IP aralıklarını arayın",
+ "checkuser-investigate-notice-no-results": "Sonuç yok.",
+ "checkuser-investigate-tab-preliminary-check": "Hesap bilgisi",
+ "checkuser-investigate-tab-compare": "IP'ler ve Kullanıcı aracıları",
+ "checkuser-investigate-tab-timeline": "Zaman çizelgesi",
+ "checkuser-investigate-targets-label": "Kullanıcı adları ve IP adresleri",
+ "checkuser-investigate-targets-placeholder": "KullanıcıAdı veya 1.1.1.1",
+ "checkuser-investigate-duration-label": "Süre",
+ "checkuser-investigate-duration-option-all": "Hepsi",
+ "checkuser-investigate-duration-option-1w": "Geçen hafta",
+ "checkuser-investigate-duration-option-2w": "Son 2 hafta",
+ "checkuser-investigate-duration-option-30d": "Son 30 gün",
+ "checkuser-investigate-reason-label": "Sebep",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Hesap bilgileri sekmesi IP'ler hakkında herhangi bir bilgi içermez. Bu ayrıntılar için <span class=\"plainlinks\">[$1 IP'ler ve Kullanıcı aracıları sekmesine]</span> bakın.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Engellendi",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 düzenleme",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Engellenmemiş",
+ "checkuser-investigate-preliminary-table-header-blocked": "Durum",
+ "checkuser-investigate-preliminary-table-header-editcount": "Düzenlemeler",
+ "checkuser-investigate-preliminary-table-header-groups": "Gruplar",
+ "checkuser-investigate-preliminary-table-header-name": "Kullanıcı adı",
+ "checkuser-investigate-preliminary-table-header-registration": "Eklenme tarihi",
+ "checkuser-investigate-preliminary-table-header-wiki": "Viki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Viki bulunamadı",
+ "checkuser-investigate-filters-legend": "Filtreler",
+ "checkuser-investigate-filters-exclude-targets-label": "Aşağıdaki kullanıcıları veya IP'leri gizle",
+ "checkuser-investigate-timeline-notice-no-results": "Sonuç yok: son 90 gün içinde bu kullanıcılardan veya IP'lerden kaydedilmiş bir etkinlik yok",
+ "checkuser-investigate-timeline-notice-no-results-filters": "Bu filtreleme ölçütleriyle eşleşen sonuç bulunamadı. Aramayı genişletmek için bazı filtreleri kaldırmayı deneyin.",
+ "checkuser-investigate-compare-copy-button-label": "Vikimetin göster",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Proxy kontrolü",
+ "checkuser-investigate-compare-copy-message-label": "Bu bilgileri bir Vikimetin tablosu olarak kopyalamak ister misiniz?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Teknik sınırlamalar nedeniyle sunulabilecek kayıt sayısına ulaştık. Aşağıdaki hedefler için döndürülen veriler eksik: $1. Lütfen daha az hedef, daha küçük zaman aralığı veya daha dar IP aralıkları kullanmayı deneyin.",
+ "checkuser-investigate-compare-notice-no-results": "Sonuç yok: Son 90 gün içinde bu kullanıcılardan veya IP'lerden hiçbir düzenleme yapılmadı",
+ "checkuser-investigate-compare-notice-no-results-filters": "Bu filtreleme ölçütleriyle eşleşen sonuç bulunamadı. Aramayı genişletmek için bazı filtreleri kaldırmayı deneyin.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Bu IP'deki tüm kullanıcıyı göster",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Bu kullanıcının tüm IP'yi göster",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Bu IP'yi araştırmaya ekle",
+ "checkuser-investigate-compare-table-button-checks-label": "Kontroller",
+ "checkuser-investigate-compare-table-button-contribs-label": "Katkılar",
+ "checkuser-investigate-compare-table-button-filter-label": "Sonuçlara göre filtrele",
+ "checkuser-investigate-compare-table-cell-unregistered": "Kayıtsız",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 düzenleme]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(Tüm kullanıcılardan ~$1)</i>",
+ "checkuser-investigate-compare-table-header-username": "Kullanıcı adı",
+ "checkuser-investigate-compare-table-header-activity": "Tarih aralığı",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "Kullanıcı temsilcisi",
+ "checkuser-investigate-subtitle-link-restart-tour": "Turu Sıfırla",
+ "checkuser-investigate-tour-targets-title": "Birden çok kullanıcıyı ve IP'leri kontrol ediliyor mu?",
+ "checkuser-investigate-tour-targets-desc": "$1 Kullanıcı Adı veya IP'ye kadar ekleyin ve tüm bilgileri tek bir yerde alın. Endişelenmeyin, her biri için ayrı bir Denetçi günlüğü oluştururuz.",
+ "checkuser-investigate-tour-useragents-title": "Kullanıcı Denetimi Eşleşiyor mu?",
+ "checkuser-investigate-tour-useragents-desc": "Aynı verilere sahip diğer tüm satırları vurgulamak için bir hücrenin üzerine sürükleyin. Veriler arasında gezinirken vurguyu açık tutmak için pin simgesini tıklayın.",
+ "checkuser-investigate-tour-addusertargets-title": "Daha fazla bağlam mı gerekiyor?",
+ "checkuser-investigate-tour-addusertargets-desc": "IP'deki diğer tüm kullanıcıları görmek için tıklayın. Bunu Kullanıcılar için de yapabilir ve kullandıkları tüm IP'leri görebilirsiniz. Sizin için otomatik olarak bir Denetçi günlük öğesi oluştururuz.",
+ "checkuser-investigate-tour-filterip-title": "Soruşturmanı daraltıyor musun?",
+ "checkuser-investigate-tour-filterip-desc": "Kullanıcı adlarını, IP'leri veya kullanıcı aracılarını filtreleyerek dağınıklığı kaldırın. Verileri geri getirmek ister misin? Filtreleri kaldırmak için üstteki Filtreler panelini kullanın.",
+ "checkuser-investigate-tour-block-title": "Engellemek mi istiyorsun?",
+ "checkuser-investigate-tour-block-desc": "Engellemek istediğiniz kullanıcıları seçmenize olanak tanır ve ardından uygun engeli seçmek için engel formuna götürür.",
+ "checkuser-investigate-tour-copywikitext-title": "Verileri kopyalamak ister misiniz?",
+ "checkuser-investigate-tour-copywikitext-desc": "Karşılaştırma tablosunu tek tıklamayla kopyalayın ve CUWiki'ye götürün. Soruşturmanın tüm sayfalarını değil, yalnızca görünür olanları kopyaladığınızı unutmayın."
}
diff --git a/CheckUser/i18n/trv.json b/CheckUser/i18n/trv.json
new file mode 100644
index 00000000..fcf9d2a7
--- /dev/null
+++ b/CheckUser/i18n/trv.json
@@ -0,0 +1,6 @@
+{
+ "@metadata": {
+ "authors": []
+ },
+ "checkuser-search-submit": "Miying"
+}
diff --git a/CheckUser/i18n/tt-cyrl.json b/CheckUser/i18n/tt-cyrl.json
index 269ee060..26be56f7 100644
--- a/CheckUser/i18n/tt-cyrl.json
+++ b/CheckUser/i18n/tt-cyrl.json
@@ -1,10 +1,12 @@
{
"@metadata": {
"authors": [
+ "Ерней",
"Ильнар"
]
},
"group-checkuser": "Кулланучыларны тикшереп торучылар",
"group-checkuser-member": "{{GENDER:$1|кулланучыларны тикшерүче}}",
- "right-checkuser": "куланучының IP-юлламасын тикшерү"
+ "right-checkuser": "Кулланучыларның IP адресларын һәм башка мәгълүматларын тикшерү",
+ "checkuser-all": "барысы"
}
diff --git a/CheckUser/i18n/udm.json b/CheckUser/i18n/udm.json
index 593818e8..e10ee853 100644
--- a/CheckUser/i18n/udm.json
+++ b/CheckUser/i18n/udm.json
@@ -1,8 +1,11 @@
{
"@metadata": {
"authors": [
- "Kaganer"
+ "Kaganer",
+ "Kotwys"
]
},
- "checkuser-all": "ваньзэ"
+ "checkuser-all": "ваньзэ",
+ "checkuser-investigate-compare-table-button-checks-label": "Эскеронъёс",
+ "checkuser-investigate-subtitle-link-restart-tour": "Турез выльысь кутсконо"
}
diff --git a/CheckUser/i18n/ug-arab.json b/CheckUser/i18n/ug-arab.json
index b4f05fe9..ab91297b 100644
--- a/CheckUser/i18n/ug-arab.json
+++ b/CheckUser/i18n/ug-arab.json
@@ -48,7 +48,6 @@
"checkuser-block-limit": "بەك كۆپ ئىشلەتكۈچى تاللاندى.",
"checkuser-block-noreason": "توسۇش سەۋەبىنى چۈشەندۈرۈڭ.",
"checkuser-noreason": "بۇ سۈرۈشتۈرۈشنىڭ سەۋەبىنى چۈشەندۈرۈڭ.",
- "checkuser-accounts": "$1 يېڭى {{PLURAL:$1|ھېسابات}}",
"checkuser-user-nonexistent": "بەلگىلەنگەن ئىشلەتكۈچى مەۋجۇت ئەمەس.",
"checkuser-search": "ئىزدە",
"checkuser-search-submit": "ئىزدە",
diff --git a/CheckUser/i18n/uk.json b/CheckUser/i18n/uk.json
index 4bec869f..2ddb7e0f 100644
--- a/CheckUser/i18n/uk.json
+++ b/CheckUser/i18n/uk.json
@@ -3,16 +3,17 @@
"authors": [
"AS",
"Ahonc",
+ "Alex Khimich",
"Base",
"Dim Grits",
+ "Movses",
"NickK",
+ "Piramidion",
"Prima klasy4na",
"Sodmy",
- "Тест",
- "Piramidion",
- "Alex Khimich",
+ "Vlad5250",
"Ата",
- "Vlad5250"
+ "Тест"
]
},
"checkuser-summary": "Цей засіб переглядає нові редагування для отримання IP-адрес, які використовував певний користувач, або щоб знайти редагування/користувача за IP-адресою.\nРедагування і користувачів, що редагували з певної IP-адреси, заначеної в X-Forwarded-For, можна отримати, додавши префікс <code>/xff</code> до IP-адреси. Підтримувані версії IP: 4 (CIDR $1—32) і 6 (CIDR $2-128).\nЗ огляду на продуктивність буде показано не більше 5000 редагувань.\nВикористовуйте цей засіб тільки відповідно до правил.",
@@ -24,14 +25,14 @@
"checkuser-contribs-log": "недавні перевірки користувача",
"group-checkuser": "Чек'юзери",
"group-checkuser-member": "{{GENDER:$1|чек'юзер|чек'юзерка}}",
- "right-checkuser": "перевірка IP-адрес та іншої інформації користувачів",
- "right-checkuser-log": "перегляд журналу перевірки користувачів",
- "action-checkuser": "перевіряти IP-адреси користувача та іншу інформацію",
+ "right-checkuser": "Перевірка IP-адрес та іншої інформації про користувачів",
+ "right-checkuser-log": "Перегляд журналу перевірки користувачів",
+ "action-checkuser": "перевірку IP-адрес та іншої інформації про користувача",
"action-checkuser-log": "перегляд журналу перевірки користувачів",
"grouppage-checkuser": "{{ns:project}}:Чек'юзери",
"checkuser-reason": "Причина:",
"checkuser-reason-api": "API: $1",
- "checkuser-showlog": "Перейти на журнал перевірок",
+ "checkuser-showlog": "Перейти до журналу перевірок",
"checkuser-query": "Переглянути останні зміни",
"checkuser-target": "IP-адреса або ім'я користувача:",
"checkuser-users": "Отримати користувачів",
@@ -63,15 +64,15 @@
"checkuser-blocktalk": "Заборонити редагування власної сторінки обговорення під час блокування",
"checkuser-blocktag": "Замінити сторінки користувачів на:",
"checkuser-blocktag-talk": "Замінити сторінки обговорення на:",
+ "checkuser-reblock": "Ігнорувати наявні блокування",
"checkuser-massblock-commit": "Заблокувати вибраних користувачів",
- "checkuser-block-success": "'''Зараз {{PLURAL:$2|заблокований $1 користувач|заблоковані $1 користувачі|заблоковані $1 користувачів}}.'''",
+ "checkuser-block-success": "'''{{PLURAL:$2|Користувач $1 зараз заблокований|Користувачі $1 зараз заблоковані}}.'''",
"checkuser-block-failure": "'''Немає заблокованих користувачів.'''",
"checkuser-block-limit": "Вибрано забагато користувачів.",
"checkuser-block-noreason": "Ви повинні вказати причину блокувань.",
"checkuser-centralauth-multilock": "Заблокувати вибрані облікові записи",
"checkuser-noreason": "Вам необхідно зазначити причину цього запиту.",
- "checkuser-accounts": "$1 {{PLURAL:$1|новий обліковий запис|нові облікові записи|нових облікових записів}}",
- "checkuser-too-many": "Забагато результатів (згідно з оцінкою запиту), будь ласка, звузьте CIDR.\nВикористані IP (максимум 5000, відсортовані за адресою):",
+ "checkuser-too-many": "Забагато результатів (згідно з оцінкою запиту), будь ласка, звузьте CIDR.\nВикористані IP (максимум $1, відсортовані за адресою):",
"checkuser-user-nonexistent": "Зазначений користувач не існує.",
"checkuser-search": "Знайти записи в журналі перевірок",
"checkuser-search-submit": "Знайти",
@@ -83,10 +84,10 @@
"checkuser-showmain": "Перейти до головної сторінки перевірки",
"checkuser-limited": "'''Результати урізано, щоб не обтяжувати сервер.'''",
"checkuser-log-entry-userips": "$3, $1 отримав IP-адреси для $2",
- "checkuser-log-entry-ipedits": "$3, $1 отримав редагування для $2",
- "checkuser-log-entry-ipusers": "$3, $1 отримав користувачів для $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 отримав редагування для XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 отримав користувачів для XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 отримав редагування для <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 отримав користувачів для <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 отримав редагування для XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 отримав користувачів для XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 отримав редагування для $2",
"checkuser-autocreate-action": "створений автоматично",
"checkuser-create-action": "створено",
@@ -97,26 +98,84 @@
"checkuser-login-success": "Виконано вхід у систему на сайті {{SITENAME}} як $1",
"group-checkuser.css": "/* Розміщений тут CSS-код буде використаний тільки для чек'юзерів */",
"group-checkuser.js": "/* Розміщений тут код JavaScript буде завантажений тільки для чек'юзерів */",
- "apihelp-query+checkuser-description": "Перевірка того, які IP-адреси використовуються даним іменем користувача, або які імена користувачів використовуються даною IP-адресою.",
- "apihelp-query+checkuser-summary": "Перевірка того, які IP-адреси використовуються даним іменем користувача, або які імена користувачів використовуються даною IP-адресою.",
- "apihelp-query+checkuser-param-request": "Тип запиту перевірки користувача:\n;userips:Отримати IP-адреси цільового користувача.\n;edits:Отримати зміни з цільової IP-адреси або діапазону.\n;ipusers:Отримати користувачів з цільової IP-адреси або діапазону.",
- "apihelp-query+checkuser-param-target": "Ім'я користувача, IP-адреса, або CIDR-діапазон для перевірки.",
- "apihelp-query+checkuser-param-reason": "Причина перевірки.",
- "apihelp-query+checkuser-param-limit": "Обмеження рядків.",
- "apihelp-query+checkuser-param-timecond": "Обмеження часу для даних користувача (як то \"-2 weeks\" чи \"2 weeks ago\").",
- "apihelp-query+checkuser-param-xff": "Використовуйте XFF-дані замість IP-адреси.",
- "apihelp-query+checkuser-example-1": "Перевірити IP-адреси для [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Перевірити редагування з 192.0.2.0/24",
- "apihelp-query+checkuserlog-description": "Отримати записи з журналу перевірки користувачів.",
- "apihelp-query+checkuserlog-summary": "Отримати записи з журналу перевірки користувачів.",
- "apihelp-query+checkuserlog-param-user": "Ім'я користувача перевіряльника користувачів.",
- "apihelp-query+checkuserlog-param-target": "Перевірений користувач, IP-адреса чи CIDR-діапазон.",
- "apihelp-query+checkuserlog-param-limit": "Обмеження рядків.",
- "apihelp-query+checkuserlog-param-from": "Часова мітка початку переліку.",
- "apihelp-query+checkuserlog-param-to": "Часова мітка завершення переліку.",
- "apihelp-query+checkuserlog-example-1": "Показати перевірки [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Показати перевірки 192.0.2.0/24 після 2011-10-15T23:00:00Z",
- "apierror-checkuser-missingsummary": "Вам необхідно зазначити причину для перевірки.",
- "apierror-checkuser-timelimit": "Вам необхідно використовувати правильне обмеження за часом (наприклад, \"-2 weeks\" або \"2 weeks ago\").",
- "apierror-checkuser-invalidmode": "Неправильний параметр запиту"
+ "checkuser-link-investigate-label": "Спробуйте новий інструмент CheckUser",
+ "checkuser-investigateblock": "Блокувати користувачів",
+ "checkuser-investigateblock-target": "Імена користувачів та IP-адреси",
+ "checkuser-investigateblock-actions": "Дії, які слід заблокувати",
+ "checkuser-investigateblock-reason": "Причина",
+ "checkuser-investigateblock-options": "Додаткові опції",
+ "checkuser-investigateblock-email-label": "Заборонити надсилання електронної пошти",
+ "checkuser-investigateblock-usertalk-label": "Заборонити редагування власної сторінки обговорення під час блокування",
+ "checkuser-investigateblock-reblock-label": "Ігнорувати наявні блокування",
+ "checkuser-investigateblock-notice-user-page-label": "Залишити сповіщення на сторінці користувача",
+ "checkuser-investigateblock-notice-talk-page-label": "Залишити сповіщення на сторінці обговорення користувача",
+ "checkuser-investigateblock-notice-position-label": "Позиція",
+ "checkuser-investigateblock-notice-text-label": "Вікітекст",
+ "checkuser-investigateblock-notice-append": "Додати укінці сторінки",
+ "checkuser-investigateblock-notice-prepend": "Додати на початку сторінки",
+ "checkuser-investigateblock-notice-replace": "Замінити сторінку",
+ "checkuser-investigateblock-failure": "Жодних користувачів не заблоковано. Щоб ігнорувати наявні блокування, виберіть: «{{int:checkuser-investigateblock-reblock-label}}». Блокування не буде перезаписане, якщо нове блокування ідентичне наявному.",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|Користувач $1 зараз заблокований|Користувачі $1 зараз заблоковані}}.",
+ "checkuser-investigateblock-notices-failed": "Деякі сповіщення не вдалося додати на сторінки користувачів чи сторінки обговорення користувачів.",
+ "checkuser-investigate-log": "Журнал розслідувань",
+ "checkuser-investigate-log-entry": "$3, $1 {{GENDER:$1|шукав|шукала}} інформацію щодо <bdi>$2</bdi> $4",
+ "checkuser-investigate-log-empty": "Не знайдено записів у журналі розслідувань.",
+ "checkuser-investigate-log-subtitle": "Перемкнути на форму розслідування",
+ "checkuser-investigate": "Розслідування",
+ "checkuser-investigate-page-subtitle": "Поточне розслідування для $1",
+ "checkuser-investigate-subtitle-block-button-label": "Заблокувати",
+ "checkuser-investigate-subtitle-cancel-button-label": "Скасувати",
+ "checkuser-investigate-subtitle-continue-button-label": "Продовжити",
+ "checkuser-investigate-indicator-new-investigation": "Нове розслідування",
+ "checkuser-investigate-indicator-logs": "Журнали",
+ "checkuser-investigate-legend": "Пошук імен користувачів, IP-адрес чи IP-діапазонів",
+ "checkuser-investigate-notice-no-results": "Результатів немає.",
+ "checkuser-investigate-tab-preliminary-check": "Відомості облікового запису",
+ "checkuser-investigate-tab-compare": "IP-адреси й агенти користувача",
+ "checkuser-investigate-tab-timeline": "Хронологія",
+ "checkuser-investigate-targets-label": "Імена користувачів та IP-адреси",
+ "checkuser-investigate-targets-placeholder": "Ім'я користувача або 1.1.1.1",
+ "checkuser-investigate-duration-label": "Тривалість",
+ "checkuser-investigate-duration-option-all": "Усе",
+ "checkuser-investigate-duration-option-1w": "Минулий тиждень",
+ "checkuser-investigate-duration-option-2w": "Минулі два тижні",
+ "checkuser-investigate-duration-option-30d": "Минулі 30 днів",
+ "checkuser-investigate-reason-label": "Причина",
+ "checkuser-investigate-preliminary-notice-ip-targets": "Вкладка відомостей облікового запису не містить жодної інформації про IP-адреси. Див. вкладку <span class=\"plainlinks\">[$1 IP-адреси й агенти користувача]</span>, аби переглянути такі подробиці.",
+ "checkuser-investigate-preliminary-table-cell-blocked": "Заблоковано",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|редагування|редагування|редагувань}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "Не заблоковано",
+ "checkuser-investigate-preliminary-table-header-blocked": "Статус",
+ "checkuser-investigate-preliminary-table-header-editcount": "Редагування",
+ "checkuser-investigate-preliminary-table-header-groups": "Групи",
+ "checkuser-investigate-preliminary-table-header-name": "Ім'я користувача",
+ "checkuser-investigate-preliminary-table-header-registration": "Дата долучення",
+ "checkuser-investigate-preliminary-table-header-wiki": "Вікі",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "Вікі не знайдено",
+ "checkuser-investigate-filters-legend": "Фільтри",
+ "checkuser-investigate-filters-exclude-targets-label": "Приховати вказаних користувачів чи IP-адреси",
+ "checkuser-investigate-timeline-notice-no-results": "Немає результатів: у цих користувачів чи IP не було активності за останні 90 днів",
+ "checkuser-investigate-timeline-notice-no-results-filters": "За цими критеріями нічого не знайдено. Спробуйте вилучити певні фільтри для розширення області пошуку.",
+ "checkuser-investigate-compare-copy-button-label": "Показати вікітекст",
+ "checkuser-investigate-compare-toollinks-ipcheck": "Перевірка проксі",
+ "checkuser-investigate-compare-copy-message-label": "Хочете скопіювати цю інформацію у форматі вікітаблиці?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "Через технічні обмеження ми досягли максимальної кількості записів, які можна презентувати. Виведені для вказаних цілей дані є неповними: $1. Будь ласка, спробуйте використати менше цілей, коротше часове вікно, чи вужчі IP-діапазони.",
+ "checkuser-investigate-compare-notice-no-results": "Нічого не знайдено, оскільки останні 90 днів не було редагувань з цих IP",
+ "checkuser-investigate-compare-notice-no-results-filters": "За цими критеріями нічого не знайдено. Спробуйте вилучити певні фільтри для розширення області пошуку.",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "Показати всі IP-адреси цього користувача",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "Показати всіх користувачів цієї IP-адреси",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "Додати цю IP до розслідування",
+ "checkuser-investigate-compare-table-button-checks-label": "Перевірки",
+ "checkuser-investigate-compare-table-button-contribs-label": "Внесок",
+ "checkuser-investigate-compare-table-button-filter-label": "Фільтрувати з результатів",
+ "checkuser-investigate-compare-table-cell-unregistered": "Незареєстровані",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|редагування|редагування|редагувань}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 від усіх користувачів)</i>",
+ "checkuser-investigate-compare-table-header-username": "Ім'я користувача",
+ "checkuser-investigate-compare-table-header-activity": "Діапазон дат",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "User Agent",
+ "checkuser-investigate-subtitle-link-restart-tour": "Почати спочатку",
+ "checkuser-investigate-tour-targets-title": "Перевіряєте багато користувачів та IP?",
+ "checkuser-investigate-tour-targets-desc": "Додайте до $1 {{PLURAL:$1|імені користувача|імен користувача}} чи IP й отримайте всю інформацію в одному місці. Не переживайте, ми створимо окремий запис у журналі чек'юзерів для кожного з них."
}
diff --git a/CheckUser/i18n/ur.json b/CheckUser/i18n/ur.json
index 3a524a22..e74e3f97 100644
--- a/CheckUser/i18n/ur.json
+++ b/CheckUser/i18n/ur.json
@@ -1,9 +1,9 @@
{
"@metadata": {
"authors": [
- "පසිඳු කාවින්ද",
+ "BukhariSaeed",
"Muhammad Shuaib",
- "BukhariSaeed"
+ "පසිඳු කාවින්ද"
]
},
"checkuser-logcase": "لاگ ان کریں تلاش کیس حساس ہے.",
diff --git a/CheckUser/i18n/vec.json b/CheckUser/i18n/vec.json
index a4b92602..998171ac 100644
--- a/CheckUser/i18n/vec.json
+++ b/CheckUser/i18n/vec.json
@@ -1,23 +1,25 @@
{
"@metadata": {
"authors": [
- "Candalua"
+ "Candalua",
+ "Conky77",
+ "Fierodelveneto"
]
},
"checkuser-summary": "Sto strumento qua l'analiza le modifiche reçenti par recuperar i indirizi IP doparà da un utente o mostrar contributi e dati de un IP. Utenti e contributi de un client IP i se pol rintraciar atraverso i header XFF, zontàndoghe a l'IP el suffisso \"/xff\". Xe suportà IPv4 (CIDR $1-32) e IPv6 (CIDR $2-128). No sarà restituìe piassè de 5.000 modifiche, par ragioni de prestazioni. Dòpara sto strumento in streta conformità a le policy.",
"checkuser-desc": "Consente ai utenti co le oportune autorizazion de sotopor a verifica i indirizi IP e altre informazion relative ai utenti",
- "checkuser-logcase": "La riçerca nei registri la xe ''case sensitive'' (cioè la distingue fra majuscole e minuscole).",
+ "checkuser-logcase": "Ła riçerca in tei rejistri ła difarensia intrà letare grande e picenine",
"checkuser": "Controlo utenze",
"checkuserlog": "Registro dei checkuser",
"checkuser-contribs": "controlar i indirissi IP",
- "group-checkuser": "Controlori",
+ "group-checkuser": "Tendidori de utenti",
"group-checkuser-member": "Controlor",
"right-checkuser": "Controla i indirissi IP de l'utente e altre informassion",
"right-checkuser-log": "Varda el registro del controlo utenti (checkuser)",
"grouppage-checkuser": "{{ns:project}}:Controlo utenze",
"checkuser-reason": "Motivo:",
"checkuser-showlog": "Mostra el registro",
- "checkuser-query": "Çerca ne le ultime modifiche",
+ "checkuser-query": "Serca inte ƚe ùltime modifiche",
"checkuser-target": "Utente o indirisso IP:",
"checkuser-users": "Çerca utenti",
"checkuser-edits": "Varda i contributi dei IP",
@@ -25,7 +27,7 @@
"checkuser-period": "Par quanto:",
"checkuser-week-1": "ultima stimana",
"checkuser-week-2": "ultime do stimane",
- "checkuser-month": "ultimi 30 zorni",
+ "checkuser-month": "ultimi 30 dì",
"checkuser-all": "tuti quanti",
"checkuser-cidr-label": "Sercar un interval comune e i indirissi interessà par na lista de IP",
"checkuser-cidr-res": "CIDR comune:",
@@ -43,14 +45,13 @@
"checkuser-massblock": "Bloca i utenti selessionà",
"checkuser-massblock-text": "Le utense selezionà le vegnarà blocà par senpre, col bloco automatico inpizà e la creazion de utense nove disativà.\nI indirissi IP i vegnarà blocà par na stimana solo par i utenti anonimi e co' la creazion de utense disativà.",
"checkuser-blocktag": "Sostituìssi le pagine utente con:",
- "checkuser-blocktag-talk": "Rinpiazza le pàxene de discussion con:",
+ "checkuser-blocktag-talk": "Rinpiasa łe pàjine de discusion co:",
"checkuser-massblock-commit": "Bloca i utenti selessionà",
"checkuser-block-success": "'''{{PLURAL:$2|L'utente|I utenti}} $1 {{PLURAL:$2|el|i}} xe stà blocà.'''",
"checkuser-block-failure": "'''Nissun utente blocà.'''",
"checkuser-block-limit": "Ti gà selessionà massa utenti.",
"checkuser-block-noreason": "Ti gà da dar na motivassion par i blochi.",
"checkuser-noreason": "Te ghè da indicar na motivassion par sta richiesta.",
- "checkuser-accounts": "$1 account {{PLURAL:$1|novo|novi}}",
"checkuser-too-many": "Vien fora massa risultati (secondo la stima), par piaser dòpara un CIDR piassè ristreto.\nSti qua i xe i IP doparà (fin a un massimo de 5000, ordinà par indirizo):",
"checkuser-user-nonexistent": "L'utente indicà no l'esiste mìa.",
"checkuser-search": "Çerca",
@@ -62,5 +63,5 @@
"checkuser-limited": "'''Sti risultati i xe stà tajà a metà par motivi de prestazion.'''",
"checkuser-autocreate-action": "xe stà creà automaticamente",
"checkuser-email-action": "gà mandà na e-mail a \"$1\"",
- "checkuser-reset-action": "reinposta la password par l'utente \"$1\""
+ "checkuser-reset-action": "reinposta ła ciave par l'utente \"$1\""
}
diff --git a/CheckUser/i18n/vi.json b/CheckUser/i18n/vi.json
index e9713239..4bffff33 100644
--- a/CheckUser/i18n/vi.json
+++ b/CheckUser/i18n/vi.json
@@ -1,7 +1,9 @@
{
"@metadata": {
"authors": [
+ "Leducthn",
"Minh Nguyen",
+ "Nguyễn Mạnh An",
"Vinhtantran"
]
},
@@ -58,7 +60,6 @@
"checkuser-block-noreason": "Phải đưa ra lý do cấm.",
"checkuser-centralauth-multilock": "Khóa các tài khoản được chọn",
"checkuser-noreason": "Bạn phải đưa ra lý do truy vấn.",
- "checkuser-accounts": "$1 tài khoản mới",
"checkuser-too-many": "Có quá nhiều kết quả (theo ước lượng truy vấn). Xin hãy thu hẹp CIDR. Đây là các địa chỉ IP được sử dụng (tối đa 5.000, xếp theo địa chỉ):",
"checkuser-user-nonexistent": "Thành viên chỉ định không tồn tại.",
"checkuser-search": "Tìm kiếm mục trong nhật trình CheckUser",
@@ -71,10 +72,10 @@
"checkuser-showmain": "Mở mẫu CheckUser chính",
"checkuser-limited": "'''Các kết quả đã được lược bớt để tăng hiệu suất hoạt động.'''",
"checkuser-log-entry-userips": "$3, $1 lấy địa chỉ IP của $2",
- "checkuser-log-entry-ipedits": "$3, $1 lấy sửa đổi của $2",
- "checkuser-log-entry-ipusers": "$3, $1 lấy tên thành viên của $2",
- "checkuser-log-entry-ipedits-xff": "$3, $1 lấy sửa đổi của XFF $2",
- "checkuser-log-entry-ipusers-xff": "$3, $1 lấy tên thành viên của XFF $2",
+ "checkuser-log-entry-ipedits": "$3, $1 lấy sửa đổi của <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers": "$3, $1 lấy tên thành viên của <bdi>$2</bdi>",
+ "checkuser-log-entry-ipedits-xff": "$3, $1 lấy sửa đổi của XFF <bdi>$2</bdi>",
+ "checkuser-log-entry-ipusers-xff": "$3, $1 lấy tên thành viên của XFF <bdi>$2</bdi>",
"checkuser-log-entry-useredits": "$3, $1 lấy sửa đổi của $2",
"checkuser-autocreate-action": "được tạo ra tự động",
"checkuser-create-action": "được tạo ra",
@@ -83,21 +84,14 @@
"checkuser-token-fail": "Phiên làm việc bị thất bại. Xin hãy thử lại.",
"group-checkuser.css": "/* Mã CSS tại đây sẽ chỉ ảnh hưởng đến các kiểm tra viên */",
"group-checkuser.js": "/* Mã JS tại đây sẽ chỉ ảnh hưởng đến các kiểm tra viên */",
- "apihelp-query+checkuser-description": "Kiểm tra địa chỉ IP nào được sử dụng bởi một tên người dùng nào đó hoặc tên người dùng nào được sử dụng bởi một địa chỉ IP nào đó.",
- "apihelp-query+checkuser-param-request": "Kiểu yêu cầu CheckUser:\n;userips:Lấy địa chỉ IP của người dùng mục tiêu.\n;edits:Lấy các thay đổi do địa chỉ hoặc dãy IP mục tiêu thực hiện.\n;ipusers:Lấy những người dùng theo địa chỉ hoặc dãy IP.",
- "apihelp-query+checkuser-param-target": "Tên người dùng, địa chỉ IP, hoặc dãy CIDR để kiểm tra.",
- "apihelp-query+checkuser-param-reason": "Lý do kiểm tra.",
- "apihelp-query+checkuser-param-limit": "Số hàng tối đa.",
- "apihelp-query+checkuser-param-timecond": "Giới hạn thời gian của dữ liệu người dùng (ví dụ “-2 weeks” hoặc “2 weeks ago”).",
- "apihelp-query+checkuser-param-xff": "Sử dụng dữ liệu XFF thay vì địa chỉ IP.",
- "apihelp-query+checkuser-example-1": "Kiểm tra địa chỉ IP của [[User:Example]]",
- "apihelp-query+checkuser-example-2": "Kiểm tra các sửa đổi do 192.0.2.0/24 thực hiện",
- "apihelp-query+checkuserlog-description": "Lấy mục từ nhật trình CheckUser.",
- "apihelp-query+checkuserlog-param-user": "Tên đăng nhập của kiểm định viên.",
- "apihelp-query+checkuserlog-param-target": "Thành viên, địa chỉ IP, hoặc dãy CIDR để kiểm tra.",
- "apihelp-query+checkuserlog-param-limit": "Số hàng tối đa.",
- "apihelp-query+checkuserlog-param-from": "Dấu thời gian đầu tiên trong danh sách.",
- "apihelp-query+checkuserlog-param-to": "Dấu thời gian cuối cùng trong danh sách.",
- "apihelp-query+checkuserlog-example-1": "Xem các tác vụ kiểm tra [[User:Example]]",
- "apihelp-query+checkuserlog-example-2": "Xem các tác vụ kiểm tra 192.0.2.0/24 sau 2011-10-15T23:00:00Z"
+ "checkuser-investigateblock-notice-text-label": "Wikitext",
+ "checkuser-investigate-tour-targets-title": "Kiểm tra nhiều người dùng và IP?",
+ "checkuser-investigate-tour-useragents-desc": "Di chuột qua một ô để tô sáng tất cả các hàng khác có cùng dữ liệu. Nhấp vào biểu tượng pin để giữ điểm sáng khi bạn đi qua dữ liệu.",
+ "checkuser-investigate-tour-addusertargets-desc": "Nhấn vào đây để xem tất cả người dùng khác trên IP. Bạn cũng có thể làm điều này cho Người dùng và xem tất cả các IP mà họ đã sử dụng. Chúng tôi sẽ tự động tạo một mục nhật ký CheckUser cho bạn.",
+ "checkuser-investigate-tour-filterip-title": "Thu hẹp điều tra của bạn?",
+ "checkuser-investigate-tour-filterip-desc": "Loại bỏ sự lộn xộn bằng cách lọc ra tên người dùng, IP hoặc tác nhân người dùng. Bạn muốn dữ liệu trở lại? Sử dụng bảng Bộ lọc trên đầu để loại bỏ các bộ lọc.",
+ "checkuser-investigate-tour-block-title": "Bạn muốn chặn?",
+ "checkuser-investigate-tour-block-desc": "Cho phép bạn chọn người dùng mà bạn muốn chặn và sau đó đưa bạn đến biểu mẫu khối để chọn khối thích hợp.",
+ "checkuser-investigate-tour-copywikitext-title": "Bạn muốn sao chép dữ liệu?",
+ "checkuser-investigate-tour-copywikitext-desc": "Sao chép bảng so sánh bằng một cú nhấp chuột và đưa nó vào CUWiki. Xin lưu ý rằng bạn chỉ sao chép những gì có thể nhìn thấy và không phải tất cả các trang điều tra."
}
diff --git a/CheckUser/i18n/vo.json b/CheckUser/i18n/vo.json
index 21460c46..8d08f521 100644
--- a/CheckUser/i18n/vo.json
+++ b/CheckUser/i18n/vo.json
@@ -46,7 +46,6 @@
"checkuser-block-failure": "'''Gebans nonik peblokons.'''",
"checkuser-block-limit": "Gebans tumödik pevälons.",
"checkuser-block-noreason": "Mutol nunön kodi blokamas.",
- "checkuser-accounts": "{{PLURAL:$1|kal|kals}} nulik $1",
"checkuser-too-many": "Sukaseks tu mödiks, nedol gebön eli CIDR smalikum.\nIs palisedons ladets-IP pegeböl (jü 5000, peleodüköls ma ladet):",
"checkuser-user-nonexistent": "Geban at no dabinon.",
"checkuser-search": "Sukolöd",
diff --git a/CheckUser/i18n/wa.json b/CheckUser/i18n/wa.json
index 5f6c5f4a..c3c714f8 100644
--- a/CheckUser/i18n/wa.json
+++ b/CheckUser/i18n/wa.json
@@ -53,7 +53,6 @@
"checkuser-block-limit": "Pår trop d' uzeus ont stî tchoezis.",
"checkuser-block-noreason": "Vos dvoz dner ene råjhon d' pocwè les blocaedjes.",
"checkuser-noreason": "Vos dvoz dner ene råjhon di pocwè ç' cweraedje ci.",
- "checkuser-accounts": "$1 {{PLURAL:$1|novea conte|noveas contes}}",
"checkuser-too-many": "Pår trop di rzultats (d' après l' estimaedje), dinez s' i vs plait on CIDR pus tene.\nVochal on boket des rzultats ({{formatnum:5000}} macsimom, relîts pa adresse):",
"checkuser-user-nonexistent": "L' uzeu dmandé n' egzistêye nén.",
"checkuser-search": "Cweri",
diff --git a/CheckUser/i18n/war.json b/CheckUser/i18n/war.json
index 3e1d77cb..ae7ac35e 100644
--- a/CheckUser/i18n/war.json
+++ b/CheckUser/i18n/war.json
@@ -1,11 +1,12 @@
{
"@metadata": {
"authors": [
+ "BaRaN6161 TURK",
"JinJian"
]
},
"group-checkuser": "Mga manginginsayod hin gumaramit",
- "group-checkuser-member": "{{HENERO:$1|manginginsayod hin gumaramit}}",
+ "group-checkuser-member": "{{GENDER:$1|manginginsayod hin gumaramit}}",
"checkuser-all": "ngatanan",
"checkuser-check": "Panginsayori",
"checkuser-massblock": "Pugngi an mga ginpili nga gumaramit",
diff --git a/CheckUser/i18n/wuu.json b/CheckUser/i18n/wuu.json
index 2e5952e4..6159ab00 100644
--- a/CheckUser/i18n/wuu.json
+++ b/CheckUser/i18n/wuu.json
@@ -1,4 +1,6 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": []
+ },
"checkuser-reason": "理由:"
}
diff --git a/CheckUser/i18n/xmf.json b/CheckUser/i18n/xmf.json
new file mode 100644
index 00000000..c12dcff4
--- /dev/null
+++ b/CheckUser/i18n/xmf.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Narazeni"
+ ]
+ },
+ "checkuser-investigate-preliminary-table-cell-blocked": "ბლოკირი რე",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|რედაქტირაფა|რედაქტირაფა}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "ვა რე ბლოკირი",
+ "checkuser-investigate-preliminary-table-header-editcount": "რედაქტირაფეფი",
+ "checkuser-investigate-preliminary-table-header-groups": "ბუნეფი",
+ "checkuser-investigate-preliminary-table-header-name": "მახვარებუშ ჯოხო",
+ "checkuser-investigate-preliminary-table-header-registration": "თარიღი ეკოჸუნს",
+ "checkuser-investigate-preliminary-table-header-wiki": "ვიკი:",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "თე მახვარებუშ არძა IP-მიოწურაფუშ ძირაფა"
+}
diff --git a/CheckUser/i18n/yue.json b/CheckUser/i18n/yue.json
index 158e4a3b..b9d07cb1 100644
--- a/CheckUser/i18n/yue.json
+++ b/CheckUser/i18n/yue.json
@@ -1,15 +1,15 @@
{
"@metadata": {
"authors": [
- "Xiaomingyan",
- "Hello903hello"
+ "Hello903hello",
+ "Xiaomingyan"
]
},
"checkuser-summary": "呢個工具會響最近更改度掃瞄對一位用戶用過嘅IP地址,或者係睇一個IP嘅用戶資料同埋佢嘅編輯記錄。\n\t響用戶同埋用戶端IP嘅編輯係可幾經由XFF頭,加上 \"/xff\" 就可以拎到。呢個工具係支援 IPv4 (CIDR $1-32) 同埋 IPv6 (CIDR $2-128)。\n\t由於為咗效能方面嘅原因,將唔會顯示多過5000次嘅編輯。請跟源政策去用呢個工具。",
- "checkuser-desc": "畀合適去查用戶IP或其它嘢嘅能力畀用戶",
+ "checkuser-desc": "畀有合適權限嘅用戶查其他用戶嘅IP地址同其他資料",
"checkuser-logcase": "搵呢個日誌係有分大細楷嘅。",
"checkuser": "核對用戶",
- "checkuserlog": "核對用戶日誌",
+ "checkuserlog": "稽查用戶日誌",
"group-checkuser": "稽查員",
"group-checkuser-member": "{{GENDER:$1|用戶稽查員}}",
"right-checkuser": "核對用戶嘅IP地址同埋其它嘅資料",
@@ -33,6 +33,6 @@
"checkuser-search-submit": "搵",
"checkuser-search-initiator": "創始者",
"checkuser-search-target": "目標",
- "checkuser-ipeditcount": "~響全部用戶度搵$1",
- "checkuser-showmain": "返去核對用戶主要表格"
+ "checkuser-ipeditcount": "~響全部用戶度搵到$1",
+ "checkuser-showmain": "轉去稽查用戶主要表格"
}
diff --git a/CheckUser/i18n/zh-hans.json b/CheckUser/i18n/zh-hans.json
index 05de2202..a09ff0d6 100644
--- a/CheckUser/i18n/zh-hans.json
+++ b/CheckUser/i18n/zh-hans.json
@@ -9,16 +9,22 @@
"Jimmy xu wrk",
"Liangent",
"Liuxinyu970226",
+ "Mywood",
"PhiLiP",
"Shirayuki",
+ "Shuiwater",
+ "SomeyaMako",
+ "Ssc",
+ "WhitePhosphorus",
+ "Wmr",
"Wmr89502270",
"Xiaomingyan",
- "白布飘扬",
- "乌拉跨氪",
- "Mywood",
"Yfdyh000",
- "WhitePhosphorus",
- "Wmr"
+ "乌拉跨氪",
+ "列维劳德",
+ "沈澄心",
+ "白布飘扬",
+ "铁桶"
]
},
"checkuser-summary": "本工具会从最近更改中获取用户使用过的IP地址,可使用XFF头信息来获取同一客户端IP地址下的用户和编辑,即在IP地址后方附加“/xff”。本工具支持IPv4(CIDR $1-32)和IPv6(CIDR $2-128)。由于效率原因,本工具只能查询最近5000笔编辑次数。请确保您的操作符合方针。",
@@ -69,6 +75,7 @@
"checkuser-blocktalk": "在封禁期间阻止编辑他们自己的讨论页",
"checkuser-blocktag": "替换用户页面内容为:",
"checkuser-blocktag-talk": "替换讨论页内容:",
+ "checkuser-reblock": "覆盖现有的封禁",
"checkuser-massblock-commit": "封禁选中用户",
"checkuser-block-success": "'''{{PLURAL:$2|用户}} $1 {{PLURAL:$2|已被}}封禁。'''",
"checkuser-block-failure": "'''没有用户被封禁。'''",
@@ -76,8 +83,7 @@
"checkuser-block-noreason": "您必须解释此次封禁的原因。",
"checkuser-centralauth-multilock": "多重锁定选定帐户",
"checkuser-noreason": "您必须解释此次查询的原因。",
- "checkuser-accounts": "$1个新{{PLURAL:$1|账户}}",
- "checkuser-too-many": "结果过多(根据查询估计),请缩小CIDR的范围。\n下面列出了使用过的IP地址(最多5000个,按地址排列):",
+ "checkuser-too-many": "结果过多(根据查询估计),请缩小CIDR的范围。\n下面列出了使用过的IP地址(最多$1个,按地址排列):",
"checkuser-user-nonexistent": "指定的用户不存在。",
"checkuser-search": "搜索用户查核日志记录",
"checkuser-search-submit": "搜索",
@@ -89,10 +95,10 @@
"checkuser-showmain": "切换到用户查核主表单",
"checkuser-limited": "'''结果已因效率原因而被删减。'''",
"checkuser-log-entry-userips": "$3,$1获取了$2的IP地址",
- "checkuser-log-entry-ipedits": "$3,$1获取了$2的编辑记录",
- "checkuser-log-entry-ipusers": "$3,$1获取了$2的用户信息",
- "checkuser-log-entry-ipedits-xff": "$3,$1获取了XFF $2的编辑记录",
- "checkuser-log-entry-ipusers-xff": "$3,$1获取了XFF $2的用户信息",
+ "checkuser-log-entry-ipedits": "$3,$1获取了<bdi>$2</bdi>的编辑记录",
+ "checkuser-log-entry-ipusers": "$3,$1获取了<bdi>$2</bdi>的用户信息",
+ "checkuser-log-entry-ipedits-xff": "$3,$1获取了XFF <bdi>$2</bdi>的编辑记录",
+ "checkuser-log-entry-ipusers-xff": "$3,$1获取了XFF <bdi>$2</bdi>的用户信息",
"checkuser-log-entry-useredits": "$3,$1获取了$2的编辑记录",
"checkuser-autocreate-action": "已自动创建",
"checkuser-create-action": "已创建",
@@ -103,26 +109,35 @@
"checkuser-login-success": "成功作为$1登录至{{SITENAME}}",
"group-checkuser.css": "/* 这里放置的CSS将只影响用户查核员 */",
"group-checkuser.js": "/* 这里放置的JS将只影响用户查核员 */",
- "apihelp-query+checkuser-description": "检查指定用户名使用的IP地址或指定IP地址使用过的用户名。",
- "apihelp-query+checkuser-summary": "检查指定用户名使用过的IP地址或指定IP地址使用过的用户名。",
- "apihelp-query+checkuser-param-request": "用户查核请求类型:\n;userips:获取目标用户的IP地址。\n;edits:获取目标IP地址或地址段的更改。\n;ipusers:获取目标IP地址或地址段的用户。",
- "apihelp-query+checkuser-param-target": "要查核的用户名、IP地址或CIDR地址段。",
- "apihelp-query+checkuser-param-reason": "查核原因。",
- "apihelp-query+checkuser-param-limit": "限定行数。",
- "apihelp-query+checkuser-param-timecond": "用户数据的限定(例如“-2 weeks”或“2 weeks ago”)。",
- "apihelp-query+checkuser-param-xff": "使用XFF数据代替IP地址。",
- "apihelp-query+checkuser-example-1": "查核[[User:Example]]的IP地址",
- "apihelp-query+checkuser-example-2": "查核来自192.0.2.0/24的编辑",
- "apihelp-query+checkuserlog-description": "从用户查核日志获得记录。",
- "apihelp-query+checkuserlog-summary": "获取用户查核日志中的记录。",
- "apihelp-query+checkuserlog-param-user": "用户查核员的用户名。",
- "apihelp-query+checkuserlog-param-target": "已查核的用户、IP地址或CIDR地址段。",
- "apihelp-query+checkuserlog-param-limit": "限定行数。",
- "apihelp-query+checkuserlog-param-from": "枚举的起始时间戳。",
- "apihelp-query+checkuserlog-param-to": "枚举的结束时间戳。",
- "apihelp-query+checkuserlog-example-1": "显示[[User:Example]]的查核",
- "apihelp-query+checkuserlog-example-2": "显示2011-10-15T23:00:00Z之后对192.0.2.0/24的查核",
- "apierror-checkuser-missingsummary": "您必须定义查核原因。",
- "apierror-checkuser-timelimit": "您需要使用正确的时间限制(例如“-2 weeks”或“2 weeks ago”)。",
- "apierror-checkuser-invalidmode": "无效的请求模式"
+ "checkuser-investigateblock": "封禁用户",
+ "checkuser-investigateblock-target": "用户名和IP地址",
+ "checkuser-investigateblock-actions": "封禁操作",
+ "checkuser-investigateblock-reason": "原因",
+ "checkuser-investigateblock-options": "额外选项",
+ "checkuser-investigateblock-email-label": "阻止发送电子邮件",
+ "checkuser-investigateblock-usertalk-label": "在封禁期间阻止其编辑自己的讨论页",
+ "checkuser-investigateblock-reblock-label": "覆盖现有的封禁",
+ "checkuser-investigateblock-notice-user-page-label": "在用户页留下通知",
+ "checkuser-investigateblock-notice-talk-page-label": "在用户讨论页留下通知",
+ "checkuser-investigateblock-notice-position-label": "位置",
+ "checkuser-investigateblock-notice-text-label": "Wiki文本",
+ "checkuser-investigateblock-notice-append": "增加至页面",
+ "checkuser-investigateblock-notice-prepend": "预载页面",
+ "checkuser-investigateblock-notice-replace": "替换页面",
+ "checkuser-investigate-subtitle-block-button-label": "封禁",
+ "checkuser-investigate-subtitle-cancel-button-label": "取消",
+ "checkuser-investigate-subtitle-continue-button-label": "继续",
+ "checkuser-investigate-indicator-logs": "日志",
+ "checkuser-investigate-tab-preliminary-check": "账户信息",
+ "checkuser-investigate-duration-label": "期限",
+ "checkuser-investigate-duration-option-all": "全部",
+ "checkuser-investigate-duration-option-1w": "上周",
+ "checkuser-investigate-duration-option-2w": "上两周",
+ "checkuser-investigate-duration-option-30d": "前30天",
+ "checkuser-investigate-compare-copy-button-label": "显示维基文本",
+ "checkuser-investigate-compare-copy-message-label": "您是否想要将这些信息复制为维基文本格式的表格?",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "显示该用户使用的所有IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "显示使用该IP的所有用户",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "添加此IP到调查中",
+ "checkuser-investigate-compare-table-button-filter-label": "从结果中筛选"
}
diff --git a/CheckUser/i18n/zh-hant.json b/CheckUser/i18n/zh-hant.json
index 68340841..231b5e80 100644
--- a/CheckUser/i18n/zh-hant.json
+++ b/CheckUser/i18n/zh-hant.json
@@ -1,23 +1,24 @@
{
"@metadata": {
"authors": [
+ "A2093064",
"Alexsh",
"Anakmalaysia",
+ "Cwlin0416",
+ "EagerLin",
"Horacewai2",
+ "Kly",
+ "LNDDYL",
+ "Laundry Machine",
"Liangent",
"Liuxinyu970226",
"Mark85296341",
"Oapbtommy",
+ "Sanmosa",
"Waihorace",
"Wrightbus",
- "Cwlin0416",
- "LNDDYL",
- "EagerLin",
- "一個正常人",
- "Kly",
- "Laundry Machine",
- "Sanmosa",
- "A2093064"
+ "Xiplus",
+ "一個正常人"
]
},
"checkuser-summary": "本工具會從最近更改中取得使用者使用過的 IP 位址,可使用 XFF 標頭資訊來取得同一客戶端 IP 位址下的使用者和編輯,即在 IP 位址後方加上 \"/xff\"。 本工具支援 IPv4 (CIDR $1-32) 與 IPv6 (CIDR $2-128)。 考量到效率問題,本工具只允許查詢最近 5000 筆編輯。 請確認你的操作符合政策規範。",
@@ -39,9 +40,9 @@
"checkuser-showlog": "切換到用戶查核日誌",
"checkuser-query": "查詢最近變更",
"checkuser-target": "IP 位址或使用者名稱:",
- "checkuser-users": "查詢使用者",
- "checkuser-edits": "查詢編輯",
- "checkuser-ips": "查詢 IP 位址",
+ "checkuser-users": "取得使用者",
+ "checkuser-edits": "取得編輯",
+ "checkuser-ips": "取得 IP 位址",
"checkuser-period": "期間:",
"checkuser-week-1": "最近 1 週",
"checkuser-week-2": "最近 2 週",
@@ -68,6 +69,7 @@
"checkuser-blocktalk": "在封禁期間禁止編輯自己的用戶討論頁",
"checkuser-blocktag": "替換使用者頁面為:",
"checkuser-blocktag-talk": "替換對話頁面為:",
+ "checkuser-reblock": "覆蓋現有的封鎖",
"checkuser-massblock-commit": "封鎖選擇的使用者",
"checkuser-block-success": "'''{{PLURAL:$2|使用者}} $1 {{PLURAL:$2|已被}}封鎖。'''",
"checkuser-block-failure": "'''沒有使用者被封鎖。'''",
@@ -75,8 +77,7 @@
"checkuser-block-noreason": "您必須提供進行禁鎖的原因。",
"checkuser-centralauth-multilock": "多重鎖定選定帳戶",
"checkuser-noreason": "您必須提供進行查詢的原因。",
- "checkuser-accounts": "$1 個新帳號",
- "checkuser-too-many": "查詢結果過多 (根據查詢估計),請縮小 CIDR 的範圍。\n以下為使用到的 IP 位址 (最多 5000 個,依位址排列):",
+ "checkuser-too-many": "查詢結果過多 (根據查詢估計),請縮小 CIDR 的範圍。\n以下為使用到的 IP 位址 (最多 $1 個,依位址排列):",
"checkuser-user-nonexistent": "指定的使用者不存在。",
"checkuser-search": "搜尋用戶查核日誌",
"checkuser-search-submit": "搜尋",
@@ -88,10 +89,10 @@
"checkuser-showmain": "切換至檢查使用者主表單",
"checkuser-limited": "'''查詢結果因效能問題已刪減。'''",
"checkuser-log-entry-userips": "$3,$1取得了$2的IP地址",
- "checkuser-log-entry-ipedits": "$3,$1獲取了$2的編輯記錄",
- "checkuser-log-entry-ipusers": "$3,$1獲取了$2的用戶資料",
- "checkuser-log-entry-ipedits-xff": "$3,$1 獲取了 $2 的 XFF 編輯記錄",
- "checkuser-log-entry-ipusers-xff": "$3,$1 獲取了 $2 的使用者",
+ "checkuser-log-entry-ipedits": "$3,$1獲取了<bdi>$2</bdi>的編輯記錄",
+ "checkuser-log-entry-ipusers": "$3,$1獲取了<bdi>$2</bdi>的用戶資料",
+ "checkuser-log-entry-ipedits-xff": "$3,$1 獲取了 <bdi>$2</bdi> 的 XFF 編輯記錄",
+ "checkuser-log-entry-ipusers-xff": "$3,$1 獲取了 <bdi>$2</bdi> 的使用者",
"checkuser-log-entry-useredits": "$3,$1 獲取了 $2 的編輯記錄",
"checkuser-autocreate-action": "已自動建立",
"checkuser-create-action": "已建立",
@@ -100,26 +101,94 @@
"checkuser-token-fail": "連線階段錯誤,請再試一次。",
"checkuser-login-failure": "以$1身分登入{{SITENAME}}失敗",
"checkuser-login-success": "成功以$1身分登入{{SITENAME}}",
- "apihelp-query+checkuser-description": "檢查指定使用者使用的 IP 地址或指定 IP 地址使用的使用者",
- "apihelp-query+checkuser-summary": "檢查指定使用者使用的 IP 地址或指定 IP 地址使用的使用者",
- "apihelp-query+checkuser-param-request": "使用者查核請求類型:\n;userips:取得目標使用者的 IP。\n;edits:取得目標 IP 或地址段所作的更改。\n;ipusers:取得目標 IP 或地址段的使用者。",
- "apihelp-query+checkuser-param-target": "要查核的使用者名稱 IP 地址,或 CIDR 地址段。",
- "apihelp-query+checkuser-param-reason": "查核原因。",
- "apihelp-query+checkuser-param-limit": "行數限制。",
- "apihelp-query+checkuser-param-timecond": "使用者資料的時限 (例如 \"-2 weeks\" 或 \"2 weeks ago\" ) 。",
- "apihelp-query+checkuser-param-xff": "使用 XFF 資料代替 IP。",
- "apihelp-query+checkuser-example-1": "查核[[User:Example]]的 IP",
- "apihelp-query+checkuser-example-2": "查核來自 192.0.2.0/24 的編輯",
- "apihelp-query+checkuserlog-description": "從使用者查核日誌獲得記錄。",
- "apihelp-query+checkuserlog-summary": "從使用者查核日誌獲得記錄。",
- "apihelp-query+checkuserlog-param-user": "使用者查核員的使用者名稱。",
- "apihelp-query+checkuserlog-param-target": "已查核的使用者、IP 地址或 CIDR 地址段。",
- "apihelp-query+checkuserlog-param-limit": "行數限制。",
- "apihelp-query+checkuserlog-param-from": "起始列舉的時間戳記。",
- "apihelp-query+checkuserlog-param-to": "結束列舉的時間戳記。",
- "apihelp-query+checkuserlog-example-1": "顯示[[User:Example]]的查核",
- "apihelp-query+checkuserlog-example-2": "顯示在 2011-10-15T23:00:00Z 之後的 192.0.2.0/24 檢查",
- "apierror-checkuser-missingsummary": "您必須定義檢查的原因。",
- "apierror-checkuser-timelimit": "您必須使用正確的時間限制(例如:「-2 weeks」或「2 weeks ago」)。",
- "apierror-checkuser-invalidmode": "無效請求模式"
+ "checkuser-link-investigate-label": "嘗試新的使用者檢查工具",
+ "checkuser-investigateblock": "封鎖使用者",
+ "checkuser-investigateblock-target": "使用者名稱與 IP 位址",
+ "checkuser-investigateblock-actions": "封鎖操作",
+ "checkuser-investigateblock-reason": "原因",
+ "checkuser-investigateblock-options": "額外選項",
+ "checkuser-investigateblock-email-label": "禁止傳送電郵",
+ "checkuser-investigateblock-usertalk-label": "在封鎖期間禁止編輯自己的使用者討論頁",
+ "checkuser-investigateblock-reblock-label": "覆蓋現有的封鎖",
+ "checkuser-investigateblock-notice-user-page-label": "在使用者頁面留下通知",
+ "checkuser-investigateblock-notice-talk-page-label": "在使用者的討論頁面留下通知",
+ "checkuser-investigateblock-notice-position-label": "位置",
+ "checkuser-investigateblock-notice-text-label": "Wiki 語法",
+ "checkuser-investigateblock-notice-append": "在頁面末端",
+ "checkuser-investigateblock-notice-prepend": "在頁面頂端",
+ "checkuser-investigateblock-notice-replace": "取代頁面",
+ "checkuser-investigateblock-failure": "沒有要被封鎖的使用者。要覆蓋現有的封鎖,請勾選:「{{int:checkuser-investigateblock-reblock-label}}」。若新的封鎖與現有封鎖內容相同,則不會做出覆蓋。",
+ "checkuser-investigateblock-success": "{{PLURAL:$2|使用者}}$1{{PLURAL:$2|現已被}}封鎖。",
+ "checkuser-investigateblock-notices-failed": "一些通知可能無法添加到使用者頁面或是使用者的討論頁。",
+ "checkuser-investigate-log": "調查日誌",
+ "checkuser-investigate-log-entry": "$3,$1查看<bdi>$2</bdi>$4的資訊",
+ "checkuser-investigate-log-empty": "找不到調查日誌項目。",
+ "checkuser-investigate-log-subtitle": "切換到調查表單",
+ "checkuser-investigate": "調查",
+ "checkuser-investigate-page-subtitle": "目前的$1調查",
+ "checkuser-investigate-subtitle-block-button-label": "封鎖",
+ "checkuser-investigate-subtitle-cancel-button-label": "取消",
+ "checkuser-investigate-subtitle-continue-button-label": "繼續",
+ "checkuser-investigate-indicator-new-investigation": "新調查",
+ "checkuser-investigate-indicator-logs": "日誌",
+ "checkuser-investigate-legend": "搜尋使用者名稱、IP 位址、或是 IP 範圍",
+ "checkuser-investigate-notice-no-results": "沒有結果。",
+ "checkuser-investigate-tab-preliminary-check": "帳號資訊",
+ "checkuser-investigate-tab-compare": "IP 與使用者代理",
+ "checkuser-investigate-tab-timeline": "時間軸",
+ "checkuser-investigate-targets-label": "使用者名稱與 IP 位址",
+ "checkuser-investigate-targets-placeholder": "使用者名稱或 1.1.1.1",
+ "checkuser-investigate-duration-label": "期間",
+ "checkuser-investigate-duration-option-all": "全部",
+ "checkuser-investigate-duration-option-1w": "上週",
+ "checkuser-investigate-duration-option-2w": "前兩週",
+ "checkuser-investigate-duration-option-30d": "最近 30 天",
+ "checkuser-investigate-reason-label": "原因",
+ "checkuser-investigate-preliminary-notice-ip-targets": "帳號資訊表格沒有包含任何在 IP 上的資訊。請查看 <span class=\"plainlinks\">[$1 IP 與使用者代理分頁]</span>來取得詳細內容。",
+ "checkuser-investigate-preliminary-table-cell-blocked": "已封鎖",
+ "checkuser-investigate-preliminary-table-cell-edits": "$1 {{PLURAL:$1|次編輯}}",
+ "checkuser-investigate-preliminary-table-cell-unblocked": "尚未封鎖",
+ "checkuser-investigate-preliminary-table-header-blocked": "狀態",
+ "checkuser-investigate-preliminary-table-header-editcount": "編輯",
+ "checkuser-investigate-preliminary-table-header-groups": "群組",
+ "checkuser-investigate-preliminary-table-header-name": "使用者名稱",
+ "checkuser-investigate-preliminary-table-header-registration": "日期已附上",
+ "checkuser-investigate-preliminary-table-header-wiki": "Wiki",
+ "checkuser-investigate-preliminary-table-cell-wiki-nowiki": "找不到 Wiki",
+ "checkuser-investigate-filters-legend": "篩選",
+ "checkuser-investigate-filters-exclude-targets-label": "隱藏以下使用者或 IP",
+ "checkuser-investigate-timeline-notice-no-results": "沒有結果:沒有在過去 90 天來自這些使用者或 IP 的記錄活動",
+ "checkuser-investigate-timeline-notice-no-results-filters": "沒有符合這些篩選條件的結果。嘗試移除一些篩選來擴大搜尋。",
+ "checkuser-investigate-compare-copy-button-label": "顯示 wiki 語法",
+ "checkuser-investigate-compare-toollinks-ipcheck": "代理檢查",
+ "checkuser-investigate-compare-copy-message-label": "您想要將此資訊複製成 wiki 語法表格嗎?",
+ "checkuser-investigate-compare-notice-exceeded-limit": "由於技術上的限制,我們已達到可呈現紀錄的數量。以下目標所回傳的資料內容不完整:$1。請嘗試使用較少的目標、較小的時窗、或是較窄的 IP 範圍。",
+ "checkuser-investigate-compare-notice-no-results": "沒有結果:沒有在過去 90 天來自這些使用者或 IP 的結果",
+ "checkuser-investigate-compare-notice-no-results-filters": "沒有符合這些篩選條件的結果。嘗試移除一些篩選來擴大搜尋。",
+ "checkuser-investigate-compare-table-button-add-ip-targets-label": "顯示此使用者的全部 IP",
+ "checkuser-investigate-compare-table-button-add-user-targets-label": "顯示在此 IP 上的所有使用者",
+ "checkuser-investigate-compare-table-button-add-user-targets-log-label": "添加此 IP 到調查裡",
+ "checkuser-investigate-compare-table-button-checks-label": "檢查",
+ "checkuser-investigate-compare-table-button-contribs-label": "貢獻",
+ "checkuser-investigate-compare-table-button-filter-label": "從結果篩選",
+ "checkuser-investigate-compare-table-cell-unregistered": "未註冊",
+ "checkuser-investigate-compare-table-cell-edits": "<b>[$1 {{PLURAL:$1|次編輯}}]</b>",
+ "checkuser-investigate-compare-table-cell-other-edits": "<i>(~$1 來自所有使用者)</i>",
+ "checkuser-investigate-compare-table-header-username": "使用者名稱",
+ "checkuser-investigate-compare-table-header-activity": "日期範圍",
+ "checkuser-investigate-compare-table-header-ip": "IP",
+ "checkuser-investigate-compare-table-header-useragent": "使用者代理",
+ "checkuser-investigate-subtitle-link-restart-tour": "重新開始導覽",
+ "checkuser-investigate-tour-targets-title": "檢查多個使用者與 IP?",
+ "checkuser-investigate-tour-targets-desc": "合計 $1 {{PLURAL:$1|個使用者名稱或 IP}},並將所有資訊集中在一起。別擔心,我們會為各個建立單獨的 CheckUser 日誌。",
+ "checkuser-investigate-tour-useragents-title": "匹配使用者代理?",
+ "checkuser-investigate-tour-useragents-desc": "游標懸停在單元格上,把具有相同資料的所有橫列給強調出來。點擊針頭圖標可在您瀏覽資料時維持強調效果。",
+ "checkuser-investigate-tour-addusertargets-title": "需要更多的事情由來?",
+ "checkuser-investigate-tour-addusertargets-desc": "點擊來查看在 IP 上的所有其他使用者。您也可以對使用者執行此操作,來查看他們曾使用過的所有 IP。我們將會自動替您建立一個 CheckUser 日誌項目。",
+ "checkuser-investigate-tour-filterip-title": "縮小您的調查?",
+ "checkuser-investigate-tour-filterip-desc": "透過篩選使用者名稱、IP、或是使用者代理來消除雜亂內容。若想恢復成原來的資料,請使用在頂端的篩選面板把篩選給移除。",
+ "checkuser-investigate-tour-block-title": "想要封鎖?",
+ "checkuser-investigate-tour-block-desc": "允許您選擇要封鎖的使用者,並帶您到封鎖表單來選擇適當的封鎖方式。",
+ "checkuser-investigate-tour-copywikitext-title": "想要複製資料?",
+ "checkuser-investigate-tour-copywikitext-desc": "透過單次點擊來複製比較表,並將其內容帶到 CUWiki。請注意您只能複製可見的內容,而非調查的所有頁面。"
}
diff --git a/CheckUser/i18n/zh-hk.json b/CheckUser/i18n/zh-hk.json
index ad06788b..bf377b38 100644
--- a/CheckUser/i18n/zh-hk.json
+++ b/CheckUser/i18n/zh-hk.json
@@ -1,8 +1,9 @@
{
"@metadata": {
"authors": [
+ "A2093064",
"Liuxinyu970226",
- "A2093064"
+ "Xiplus"
]
},
"checkuser": "查核用戶",
diff --git a/CheckUser/includes/CheckUserEncryptedData.php b/CheckUser/includes/CheckUserEncryptedData.php
index eede1d6d..26509acd 100644
--- a/CheckUser/includes/CheckUserEncryptedData.php
+++ b/CheckUser/includes/CheckUserEncryptedData.php
@@ -34,7 +34,7 @@ class CheckUserEncryptedData {
*
* @param string $privateKey String with ascii-armored block,
* or the return of openssl_get_privatekey
- * @return string plaintext
+ * @return string|false plaintext
*/
public function getPlaintext( $privateKey ) {
$result = openssl_open(
@@ -60,8 +60,10 @@ class CheckUserEncryptedData {
* or the return of openssl_get_publickey
*/
private function encryptData( $data, $publicKey ) {
+ // @phan-suppress-next-line PhanTypeMismatchArgumentInternal
openssl_seal( $data, $encryptedString, $envelopeKeys, [ $publicKey ], $this->algName );
$this->encString = $encryptedString;
+ // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
$this->envKeys = $envelopeKeys[0];
}
}
diff --git a/CheckUser/includes/CheckUserHooks.php b/CheckUser/includes/CheckUserHooks.php
index 9a8b4256..4facc308 100644
--- a/CheckUser/includes/CheckUserHooks.php
+++ b/CheckUser/includes/CheckUserHooks.php
@@ -1,9 +1,68 @@
<?php
-use MediaWiki\MediaWikiServices;
use MediaWiki\Auth\AuthenticationResponse;
+use MediaWiki\Block\DatabaseBlock;
+use MediaWiki\CheckUser\SpecialInvestigate;
+use MediaWiki\CheckUser\SpecialInvestigateBlock;
+use MediaWiki\CheckUser\SpecialInvestigateLog;
+use MediaWiki\MediaWikiServices;
+use Wikimedia\IPUtils;
+use Wikimedia\Rdbms\IDatabase;
class CheckUserHooks {
+
+ /**
+ * The maximum number of bytes that fit in CheckUser's text fields
+ * (cuc_agent,cuc_actiontext,cuc_comment,cuc_xff)
+ */
+ private const TEXT_FIELD_LENGTH = 255;
+
+ /**
+ * @param array &$list
+ * @return bool
+ */
+ public static function onSpecialPage_initList( &$list ) {
+ global $wgCheckUserEnableSpecialInvestigate;
+
+ if ( $wgCheckUserEnableSpecialInvestigate ) {
+ $list['Investigate'] = [
+ 'class' => SpecialInvestigate::class,
+ 'services' => [
+ 'LinkRenderer',
+ 'ContentLanguage',
+ 'UserOptionsManager',
+ 'CheckUserPreliminaryCheckPagerFactory',
+ 'CheckUserComparePagerFactory',
+ 'CheckUserTimelinePagerFactory',
+ 'CheckUserTokenQueryManager',
+ 'CheckUserDurationManager',
+ 'CheckUserEventLogger',
+ 'CheckUserGuidedTourLauncher',
+ 'CheckUserHookRunner',
+ ],
+ ];
+
+ $list['InvestigateLog'] = [
+ 'class' => SpecialInvestigateLog::class,
+ 'services' => [
+ 'CheckUserInvestigateLogPagerFactory',
+ ],
+ ];
+
+ $list['InvestigateBlock'] = [
+ 'class' => SpecialInvestigateBlock::class,
+ 'services' => [
+ 'PermissionManager',
+ 'TitleFormatter',
+ 'UserFactory',
+ 'CheckUserEventLogger',
+ ]
+ ];
+ }
+
+ return true;
+ }
+
/**
* Hook function for RecentChange_save
* Saves user data into the cu_changes table
@@ -13,14 +72,14 @@ class CheckUserHooks {
* @return bool
*/
public static function updateCheckUserData( RecentChange $rc ) {
- global $wgRequest;
+ global $wgRequest, $wgCheckUserLogAdditionalRights;
/**
* RC_CATEGORIZE recent changes are generally triggered by other edits.
* Thus there is no reason to store checkuser data about them.
* @see https://phabricator.wikimedia.org/T125209
*/
- if ( defined( 'RC_CATEGORIZE' ) && $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
+ if ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
return true;
}
/**
@@ -28,7 +87,7 @@ class CheckUserHooks {
* Thus there is no reason to store checkuser data about them.
* @see https://phabricator.wikimedia.org/T125664
*/
- if ( defined( 'RC_EXTERNAL' ) && $rc->getAttribute( 'rc_type' ) == RC_EXTERNAL ) {
+ if ( $rc->getAttribute( 'rc_type' ) == RC_EXTERNAL ) {
return true;
}
@@ -45,17 +104,33 @@ class CheckUserHooks {
// BC: check if log_type and log_action exists
// If not, then $rc_comment is the actiontext and comment
if ( isset( $attribs['rc_log_type'] ) && $attribs['rc_type'] == RC_LOG ) {
+ $pm = MediaWikiServices::getInstance()->getPermissionManager();
$target = Title::makeTitle( $attribs['rc_namespace'], $attribs['rc_title'] );
$context = RequestContext::newExtraneousContext( $target );
+ $scope = $pm->addTemporaryUserRights( $context->getUser(), $wgCheckUserLogAdditionalRights );
+
$formatter = LogFormatter::newFromRow( $rc->getAttributes() );
$formatter->setContext( $context );
$actionText = $formatter->getPlainActionText();
+
+ \Wikimedia\ScopedCallback::consume( $scope );
} else {
$actionText = '';
}
- $dbw = wfGetDB( DB_MASTER );
+ $comment = $rc->getAttribute( 'rc_comment' );
+
+ $services = MediaWikiServices::getInstance();
+ $contLang = $services->getContentLanguage();
+
+ // (T199323) Truncate text fields prior to database insertion
+ // Attempting to insert too long text will cause an error in MariaDB/MySQL strict mode
+ $actionText = $contLang->truncateForDatabase( $actionText, self::TEXT_FIELD_LENGTH );
+ $agent = $contLang->truncateForDatabase( $agent, self::TEXT_FIELD_LENGTH );
+ $xff = $contLang->truncateForDatabase( $xff, self::TEXT_FIELD_LENGTH );
+ $comment = $contLang->truncateForDatabase( $comment, self::TEXT_FIELD_LENGTH );
+
$rcRow = [
'cuc_namespace' => $attribs['rc_namespace'],
'cuc_title' => $attribs['rc_title'],
@@ -63,15 +138,15 @@ class CheckUserHooks {
'cuc_user' => $attribs['rc_user'],
'cuc_user_text' => $attribs['rc_user_text'],
'cuc_actiontext' => $actionText,
- 'cuc_comment' => $rc->getAttribute( 'rc_comment' ),
+ 'cuc_comment' => $comment,
'cuc_this_oldid' => $attribs['rc_this_oldid'],
'cuc_last_oldid' => $attribs['rc_last_oldid'],
'cuc_type' => $attribs['rc_type'],
'cuc_timestamp' => $attribs['rc_timestamp'],
- 'cuc_ip' => IP::sanitizeIP( $ip ),
- 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
+ 'cuc_ip' => IPUtils::sanitizeIP( $ip ),
+ 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null,
'cuc_xff' => !$isSquidOnly ? $xff : '',
- 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null,
'cuc_agent' => $agent
];
# On PG, MW unsets cur_id due to schema incompatibilites. So it may not be set!
@@ -80,6 +155,8 @@ class CheckUserHooks {
}
Hooks::run( 'CheckUserInsertForRecentChange', [ $rc, &$rcRow ] );
+
+ $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_MASTER );
$dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
return true;
@@ -102,24 +179,36 @@ class CheckUserHooks {
list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff );
// Get agent
$agent = $wgRequest->getHeader( 'User-Agent' );
- $dbw = wfGetDB( DB_MASTER );
+
+ $actionText = wfMessage( 'checkuser-reset-action', $account->getName() )
+ ->inContentLanguage()->text();
+
+ $services = MediaWikiServices::getInstance();
+ $contLang = $services->getContentLanguage();
+
+ // (T199323) Truncate comment fields prior to database insertion
+ // Attempting to insert too long text will cause an error in MariaDB/MySQL strict mode
+ $actionText = $contLang->truncateForDatabase( $actionText, self::TEXT_FIELD_LENGTH );
+ $agent = $contLang->truncateForDatabase( $agent, self::TEXT_FIELD_LENGTH );
+ $xff = $contLang->truncateForDatabase( $xff, self::TEXT_FIELD_LENGTH );
+
+ $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_MASTER );
$rcRow = [
'cuc_namespace' => NS_USER,
'cuc_title' => '',
'cuc_minor' => 0,
'cuc_user' => $user->getId(),
'cuc_user_text' => $user->getName(),
- 'cuc_actiontext' => wfMessage( 'checkuser-reset-action', $account->getName() )
- ->inContentLanguage()->text(),
+ 'cuc_actiontext' => $actionText,
'cuc_comment' => '',
'cuc_this_oldid' => 0,
'cuc_last_oldid' => 0,
'cuc_type' => RC_LOG,
'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
- 'cuc_ip' => IP::sanitizeIP( $ip ),
- 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
+ 'cuc_ip' => IPUtils::sanitizeIP( $ip ),
+ 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null,
'cuc_xff' => !$isSquidOnly ? $xff : '',
- 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null,
'cuc_agent' => $agent
];
$dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
@@ -160,24 +249,36 @@ class CheckUserHooks {
// Get agent
$agent = $wgRequest->getHeader( 'User-Agent' );
- $dbr = wfGetDB( DB_REPLICA );
+ $actionText = wfMessage( 'checkuser-email-action', $hash )->inContentLanguage()->text();
+
+ $services = MediaWikiServices::getInstance();
+ $contLang = $services->getContentLanguage();
+
+ // (T199323) Truncate text fields prior to database insertion
+ // Attempting to insert too long text will cause an error in MariaDB/MySQL strict mode
+ $actionText = $contLang->truncateForDatabase( $actionText, self::TEXT_FIELD_LENGTH );
+ $agent = $contLang->truncateForDatabase( $agent, self::TEXT_FIELD_LENGTH );
+ $xff = $contLang->truncateForDatabase( $xff, self::TEXT_FIELD_LENGTH );
+
+ $lb = $services->getDBLoadBalancer();
+ $dbr = $lb->getConnectionRef( DB_REPLICA );
+
$rcRow = [
'cuc_namespace' => NS_USER,
'cuc_title' => '',
'cuc_minor' => 0,
'cuc_user' => $userFrom->getId(),
'cuc_user_text' => $userFrom->getName(),
- 'cuc_actiontext' =>
- wfMessage( 'checkuser-email-action', $hash )->inContentLanguage()->text(),
+ 'cuc_actiontext' => $actionText,
'cuc_comment' => '',
'cuc_this_oldid' => 0,
'cuc_last_oldid' => 0,
'cuc_type' => RC_LOG,
'cuc_timestamp' => $dbr->timestamp( wfTimestampNow() ),
- 'cuc_ip' => IP::sanitizeIP( $ip ),
- 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
+ 'cuc_ip' => IPUtils::sanitizeIP( $ip ),
+ 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null,
'cuc_xff' => !$isSquidOnly ? $xff : '',
- 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null,
'cuc_agent' => $agent
];
if ( trim( $wgCUPublicKey ) != '' ) {
@@ -187,8 +288,8 @@ class CheckUserHooks {
}
$fname = __METHOD__;
- DeferredUpdates::addCallableUpdate( function () use ( $rcRow, $fname ) {
- $dbw = wfGetDB( DB_MASTER );
+ DeferredUpdates::addCallableUpdate( function () use ( $lb, $rcRow, $fname ) {
+ $dbw = $lb->getConnectionRef( DB_MASTER );
$dbw->insert( 'cu_changes', $rcRow, $fname );
} );
@@ -225,7 +326,19 @@ class CheckUserHooks {
list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff );
// Get agent
$agent = $wgRequest->getHeader( 'User-Agent' );
- $dbw = wfGetDB( DB_MASTER );
+ $services = MediaWikiServices::getInstance();
+ $contLang = $services->getContentLanguage();
+
+ $actiontext = wfMessage( $actiontext )->inContentLanguage()->text();
+
+ // (T199323) Truncate text fields prior to database insertion
+ // Attempting to insert too long text will cause an error in MariaDB/MySQL strict mode
+ $actionText = $contLang->truncateForDatabase( $actiontext, self::TEXT_FIELD_LENGTH );
+ $agent = $contLang->truncateForDatabase( $agent, self::TEXT_FIELD_LENGTH );
+ $xff = $contLang->truncateForDatabase( $xff, self::TEXT_FIELD_LENGTH );
+
+ $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_MASTER );
+
$rcRow = [
'cuc_page_id' => 0,
'cuc_namespace' => NS_USER,
@@ -233,16 +346,16 @@ class CheckUserHooks {
'cuc_minor' => 0,
'cuc_user' => $user->getId(),
'cuc_user_text' => $user->getName(),
- 'cuc_actiontext' => wfMessage( $actiontext )->inContentLanguage()->text(),
+ 'cuc_actiontext' => $actionText,
'cuc_comment' => '',
'cuc_this_oldid' => 0,
'cuc_last_oldid' => 0,
'cuc_type' => RC_LOG,
'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
- 'cuc_ip' => IP::sanitizeIP( $ip ),
- 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
+ 'cuc_ip' => IPUtils::sanitizeIP( $ip ),
+ 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null,
'cuc_xff' => !$isSquidOnly ? $xff : '',
- 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null,
'cuc_agent' => $agent
];
$dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
@@ -258,7 +371,7 @@ class CheckUserHooks {
public static function onAuthManagerLoginAuthenticateAudit(
AuthenticationResponse $ret, $user, $username
) {
- global $wgRequest, $wgCheckUserLogLogins;
+ global $wgRequest, $wgCheckUserLogLogins, $wgCheckUserLogSuccessfulBotLogins;
if ( !$wgCheckUserLogLogins ) {
return;
@@ -272,42 +385,68 @@ class CheckUserHooks {
return;
}
+ if (
+ $wgCheckUserLogSuccessfulBotLogins !== true &&
+ $ret->status === AuthenticationResponse::PASS
+ ) {
+ $userGroups = MediaWikiServices::getInstance()
+ ->getUserGroupManager()
+ ->getUserGroups( $user );
+
+ if ( in_array( 'bot', $userGroups ) ) {
+ return;
+ }
+ }
+
+ $ip = $wgRequest->getIP();
+ $xff = $wgRequest->getHeader( 'X-Forwarded-For' );
+ list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff );
+ $agent = $wgRequest->getHeader( 'User-Agent' );
+ $userName = $user->getName();
+
if ( $ret->status === AuthenticationResponse::FAIL ) {
$msg = 'checkuser-login-failure';
+ $cuc_user = 0;
+ $cuc_user_text = $ip;
} elseif ( $ret->status === AuthenticationResponse::PASS ) {
$msg = 'checkuser-login-success';
+ $cuc_user = $user->getId();
+ $cuc_user_text = $userName;
} else {
// Abstain, Redirect, etc.
return;
}
- $ip = $wgRequest->getIP();
- $xff = $wgRequest->getHeader( 'X-Forwarded-For' );
- list( $xff_ip, $isSquidOnly ) = self::getClientIPfromXFF( $xff );
- $agent = $wgRequest->getHeader( 'User-Agent' );
- $userName = $user->getName();
$target = "[[User:$userName|$userName]]";
- $msg = wfMessage( $msg );
- $msg->params( $target );
+ $actionText = wfMessage( $msg )->params( $target )->inContentLanguage()->text();
- $dbw = wfGetDB( DB_MASTER );
+ $services = MediaWikiServices::getInstance();
+ $contLang = $services->getContentLanguage();
+
+ // (T199323) Truncate text fields prior to database insertion
+ // Attempting to insert too long text will cause an error in MariaDB/MySQL strict mode
+ $actionText = $contLang->truncateForDatabase( $actionText, self::TEXT_FIELD_LENGTH );
+ $agent = $contLang->truncateForDatabase( $agent, self::TEXT_FIELD_LENGTH );
+ $xff = $contLang->truncateForDatabase( $xff, self::TEXT_FIELD_LENGTH );
+
+ $dbw = $services->getDBLoadBalancer()->getConnectionRef( DB_MASTER );
$rcRow = [
'cuc_page_id' => 0,
'cuc_namespace' => NS_USER,
'cuc_title' => '',
'cuc_minor' => 0,
- 'cuc_user' => 0,
- 'cuc_user_text' => $ip,
- 'cuc_actiontext' => $msg->inContentLanguage()->text(),
+ 'cuc_user' => $cuc_user,
+ 'cuc_user_text' => $cuc_user_text,
+ 'cuc_actiontext' => $actionText,
'cuc_comment' => '',
'cuc_this_oldid' => 0,
'cuc_last_oldid' => 0,
'cuc_type' => RC_LOG,
'cuc_timestamp' => $dbw->timestamp( wfTimestampNow() ),
- 'cuc_ip' => IP::sanitizeIP( $ip ),
- 'cuc_ip_hex' => $ip ? IP::toHex( $ip ) : null,
+ 'cuc_ip' => IPUtils::sanitizeIP( $ip ),
+ 'cuc_ip_hex' => $ip ? IPUtils::toHex( $ip ) : null,
'cuc_xff' => !$isSquidOnly ? $xff : '',
- 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IP::toHex( $xff_ip ) : null,
+ 'cuc_xff_hex' => ( $xff_ip && !$isSquidOnly ) ? IPUtils::toHex( $xff_ip ) : null,
'cuc_agent' => $agent
];
$dbw->insert( 'cu_changes', $rcRow, __METHOD__ );
@@ -315,16 +454,24 @@ class CheckUserHooks {
/**
* Hook function to prune data from the cu_changes table
- * @return true
*/
public static function maybePruneIPData() {
- # Every 50th edit, prune the checkuser changes table.
- if ( 0 == mt_rand( 0, 49 ) ) {
- $fname = __METHOD__;
- DeferredUpdates::addCallableUpdate( function () use ( $fname ) {
+ if ( mt_rand( 0, 9 ) != 0 ) {
+ return;
+ }
+
+ DeferredUpdates::addUpdate( new AutoCommitUpdate(
+ wfGetDB( DB_MASTER ),
+ __METHOD__,
+ function ( IDatabase $dbw, $fname ) {
global $wgCUDMaxAge;
- $dbw = wfGetDB( DB_MASTER );
+ $key = "{$dbw->getDomainID()}:PruneCheckUserData"; // per-wiki
+ $scopedLock = $dbw->getScopedLockAndFlush( $key, $fname, 1 );
+ if ( !$scopedLock ) {
+ return;
+ }
+
$encCutoff = $dbw->addQuotes( $dbw->timestamp( time() - $wgCUDMaxAge ) );
$ids = $dbw->selectFieldValues( 'cu_changes',
'cuc_id',
@@ -336,10 +483,8 @@ class CheckUserHooks {
if ( $ids ) {
$dbw->delete( 'cu_changes', [ 'cuc_id' => $ids ], $fname );
}
- } );
- }
-
- return true;
+ }
+ ) );
}
/**
@@ -366,12 +511,7 @@ class CheckUserHooks {
$ipchain = array_map( 'trim', explode( ',', $xff ) );
$ipchain = array_reverse( $ipchain );
- if ( class_exists( ProxyLookup::class ) ) { // MW 1.28+
- $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
- } else {
- // This is kind of sketch, but is good enough for back-compat
- $proxyLookup = new IP();
- }
+ $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
$client = null; // best guess of the client IP
$isSquidOnly = false; // all proxy servers where site Squid/Varnish servers?
@@ -380,7 +520,7 @@ class CheckUserHooks {
# unless the address is not sensible (e.g. private). However, prefer private
# IP addresses over proxy servers controlled by this site (more sensible).
foreach ( $ipchain as $i => $curIP ) {
- $curIP = IP::canonicalize( $curIP );
+ $curIP = IPUtils::canonicalize( $curIP );
if ( $curIP === null ) {
break; // not a valid IP address
}
@@ -391,14 +531,14 @@ class CheckUserHooks {
}
if (
isset( $ipchain[$i + 1] ) &&
- IP::isIPAddress( $ipchain[$i + 1] ) &&
+ IPUtils::isIPAddress( $ipchain[$i + 1] ) &&
(
- IP::isPublic( $ipchain[$i + 1] ) ||
+ IPUtils::isPublic( $ipchain[$i + 1] ) ||
$wgUsePrivateIPs ||
$curIsSquid // bug 48919
)
) {
- $client = IP::canonicalize( $ipchain[$i + 1] );
+ $client = IPUtils::canonicalize( $ipchain[$i + 1] );
$isSquidOnly = ( $isSquidOnly && $curIsSquid );
continue;
}
@@ -446,7 +586,7 @@ class CheckUserHooks {
// First time so populate cu_changes with recentchanges data.
// Note: We cannot completely rely on updatelog here for old entries
// as populateCheckUserTable.php doesn't check for duplicates
- $updater->addPostDatabaseUpdateMaintenance( 'PopulateCheckUserTable' );
+ $updater->addPostDatabaseUpdateMaintenance( PopulateCheckUserTable::class );
}
}
@@ -487,7 +627,9 @@ class CheckUserHooks {
) {
$user = $sp->getUser();
$linkRenderer = $sp->getLinkRenderer();
- if ( $user->isAllowed( 'checkuser' ) ) {
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+ if ( $permissionManager->userHasRight( $user, 'checkuser' ) ) {
$links['checkuser'] = $linkRenderer->makeKnownLink(
SpecialPage::getTitleFor( 'CheckUser' ),
$sp->msg( 'checkuser-contribs' )->text(),
@@ -495,7 +637,7 @@ class CheckUserHooks {
[ 'user' => $nt->getText() ]
);
}
- if ( $user->isAllowed( 'checkuser-log' ) ) {
+ if ( $permissionManager->userHasRight( $user, 'checkuser-log' ) ) {
$links['checkuser-log'] = $linkRenderer->makeKnownLink(
SpecialPage::getTitleFor( 'CheckUserLog' ),
$sp->msg( 'checkuser-contribs-log' )->text(),
@@ -510,13 +652,13 @@ class CheckUserHooks {
/**
* Retroactively autoblocks the last IP used by the user (if it is a user)
- * blocked by this Block.
+ * blocked by this block.
*
- * @param Block $block
+ * @param DatabaseBlock $block
* @param array &$blockIds
* @return bool
*/
- public static function doRetroactiveAutoblock( Block $block, array &$blockIds ) {
+ public static function doRetroactiveAutoblock( DatabaseBlock $block, array &$blockIds ) {
$dbr = wfGetDB( DB_REPLICA );
$user = User::newFromName( (string)$block->getTarget(), false );
diff --git a/CheckUser/includes/CheckUserLogPager.php b/CheckUser/includes/CheckUserLogPager.php
index cd175b28..433eb4c6 100644
--- a/CheckUser/includes/CheckUserLogPager.php
+++ b/CheckUser/includes/CheckUserLogPager.php
@@ -1,34 +1,38 @@
<?php
+use MediaWiki\Cache\LinkBatchFactory;
use Wikimedia\Rdbms\IResultWrapper;
class CheckUserLogPager extends ReverseChronologicalPager {
/**
- * @var array $searchConds
+ * @var array
*/
protected $searchConds;
+ /** @var LinkBatchFactory */
+ private $linkBatchFactory;
+
/**
* @param IContextSource $context
* @param array $conds Should include 'queryConds', 'year', and 'month' keys
+ * @param LinkBatchFactory $linkBatchFactory
*/
- public function __construct( IContextSource $context, array $conds ) {
+ public function __construct( IContextSource $context, array $conds, LinkBatchFactory $linkBatchFactory ) {
parent::__construct( $context );
$this->searchConds = $conds['queryConds'];
// getDateCond() actually *sets* the timestamp offset..
$this->getDateCond( $conds['year'], $conds['month'] );
+ $this->linkBatchFactory = $linkBatchFactory;
}
- function formatRow( $row ) {
+ public function formatRow( $row ) {
$user = Linker::userLink( $row->cul_user, $row->user_name );
- if ( $row->cul_type == 'userips' || $row->cul_type == 'useredits' ) {
- $target = Linker::userLink( $row->cul_target_id, $row->cul_target_text ) .
- Linker::userToolLinks( $row->cul_target_id, $row->cul_target_text );
- } else {
- $target = $row->cul_target_text;
- }
+ $target = Linker::userLink( $row->cul_target_id, $row->cul_target_text ) .
+ Linker::userToolLinks( $row->cul_target_id, $row->cul_target_text );
+ $lang = $this->getLanguage();
+ $contextUser = $this->getUser();
// Give grep a chance to find the usages:
// checkuser-log-entry-userips, checkuser-log-entry-ipedits,
// checkuser-log-entry-ipusers, checkuser-log-entry-ipedits-xff
@@ -38,9 +42,9 @@ class CheckUserLogPager extends ReverseChronologicalPager {
'checkuser-log-entry-' . $row->cul_type,
$user,
$target,
- $this->getLanguage()->timeanddate( wfTimestamp( TS_MW, $row->cul_timestamp ), true ),
- $this->getLanguage()->date( wfTimestamp( TS_MW, $row->cul_timestamp ), true ),
- $this->getLanguage()->time( wfTimestamp( TS_MW, $row->cul_timestamp ), true )
+ $lang->userTimeAndDate( wfTimestamp( TS_MW, $row->cul_timestamp ), $contextUser ),
+ $lang->userDate( wfTimestamp( TS_MW, $row->cul_timestamp ), $contextUser ),
+ $lang->userTime( wfTimestamp( TS_MW, $row->cul_timestamp ), $contextUser )
)->text() .
Linker::commentBlock( $row->cul_reason ) .
'</li>';
@@ -49,7 +53,7 @@ class CheckUserLogPager extends ReverseChronologicalPager {
/**
* @return string
*/
- function getStartBody() {
+ public function getStartBody() {
if ( $this->getNumRows() ) {
return '<ul>';
} else {
@@ -60,7 +64,7 @@ class CheckUserLogPager extends ReverseChronologicalPager {
/**
* @return string
*/
- function getEndBody() {
+ public function getEndBody() {
if ( $this->getNumRows() ) {
return '</ul>';
} else {
@@ -71,23 +75,29 @@ class CheckUserLogPager extends ReverseChronologicalPager {
/**
* @return string
*/
- function getEmptyBody() {
+ public function getEmptyBody() {
return '<p>' . $this->msg( 'checkuser-empty' )->escaped() . '</p>';
}
- function getQueryInfo() {
+ public function getQueryInfo() {
+ // Filter out log entries from Special:Investigate
+ $excludeType = $this->mDb->addQuotes( 'investigate' );
return [
'tables' => [ 'cu_log', 'user' ],
'fields' => $this->selectFields(),
- 'conds' => array_merge( $this->searchConds, [ 'user_id = cul_user' ] )
+ 'conds' => array_merge(
+ $this->searchConds,
+ [ 'user_id = cul_user' ],
+ [ 'cul_type != ' . $excludeType ]
+ )
];
}
- function getIndexField() {
+ public function getIndexField() {
return 'cul_timestamp';
}
- function selectFields() {
+ public function selectFields() {
return [
'cul_id', 'cul_timestamp', 'cul_user', 'cul_reason', 'cul_type',
'cul_target_id', 'cul_target_text', 'user_name'
@@ -104,7 +114,7 @@ class CheckUserLogPager extends ReverseChronologicalPager {
return;
}
- $lb = new LinkBatch;
+ $lb = $this->linkBatchFactory->newLinkBatch();
$lb->setCaller( __METHOD__ );
foreach ( $result as $row ) {
$lb->add( NS_USER, $row->user_name ); // Performer
diff --git a/CheckUser/includes/ServiceWiring.php b/CheckUser/includes/ServiceWiring.php
new file mode 100644
index 00000000..8052c4bb
--- /dev/null
+++ b/CheckUser/includes/ServiceWiring.php
@@ -0,0 +1,132 @@
+<?php
+
+use MediaWiki\CheckUser\ComparePagerFactory;
+use MediaWiki\CheckUser\CompareService;
+use MediaWiki\CheckUser\DurationManager;
+use MediaWiki\CheckUser\EventLogger;
+use MediaWiki\CheckUser\GuidedTour\TourLauncher;
+use MediaWiki\CheckUser\Hook\HookRunner;
+use MediaWiki\CheckUser\InvestigateLogPagerFactory;
+use MediaWiki\CheckUser\PreliminaryCheckPagerFactory;
+use MediaWiki\CheckUser\PreliminaryCheckService;
+use MediaWiki\CheckUser\TimelinePagerFactory;
+use MediaWiki\CheckUser\TimelineRowFormatterFactory;
+use MediaWiki\CheckUser\TimelineService;
+use MediaWiki\CheckUser\TokenManager;
+use MediaWiki\CheckUser\TokenQueryManager;
+use MediaWiki\CheckUser\UserManager;
+use MediaWiki\MediaWikiServices;
+
+return [
+ 'CheckUserPreliminaryCheckService' => function (
+ MediaWikiServices $services
+ ) : PreliminaryCheckService {
+ return new PreliminaryCheckService(
+ $services->getDBLoadBalancerFactory(),
+ ExtensionRegistry::getInstance(),
+ $services->getUserGroupManagerFactory(),
+ WikiMap::getCurrentWikiDbDomain()->getId()
+ );
+ },
+ 'CheckUserCompareService' => function ( MediaWikiServices $services ) : CompareService {
+ return new CompareService(
+ $services->getDBLoadBalancer(),
+ $services->get( 'CheckUserUserManager' )
+ );
+ },
+ 'CheckUserTimelineService' => function ( MediaWikiServices $services ) : TimelineService {
+ return new TimelineService(
+ $services->getDBLoadBalancer(),
+ $services->get( 'CheckUserUserManager' )
+ );
+ },
+ 'CheckUserTokenManager' => function ( MediaWikiServices $services ) : TokenManager {
+ return new TokenManager(
+ $services->getMainConfig()->get( 'SecretKey' )
+ );
+ },
+ 'CheckUserTokenQueryManager' => function ( MediaWikiServices $services ) : TokenQueryManager {
+ return new TokenQueryManager(
+ $services->get( 'CheckUserTokenManager' )
+ );
+ },
+ 'CheckUserDurationManager' => function ( MediaWikiServices $services ) : DurationManager {
+ return new DurationManager();
+ },
+ 'CheckUserGuidedTourLauncher' => function ( MediaWikiServices $services ) : TourLauncher {
+ return new TourLauncher(
+ ExtensionRegistry::getInstance(),
+ $services->getLinkRenderer()
+ );
+ },
+ 'CheckUserInvestigateLogPagerFactory' => function (
+ MediaWikiServices $services
+ ) : InvestigateLogPagerFactory {
+ return new InvestigateLogPagerFactory(
+ $services->getLinkRenderer()
+ );
+ },
+ 'CheckUserPreliminaryCheckPagerFactory' => function (
+ MediaWikiServices $services
+ ) : PreliminaryCheckPagerFactory {
+ return new PreliminaryCheckPagerFactory(
+ $services->getLinkRenderer(),
+ $services->getNamespaceInfo(),
+ \ExtensionRegistry::getInstance(),
+ $services->get( 'CheckUserTokenQueryManager' ),
+ $services->get( 'CheckUserPreliminaryCheckService' )
+ );
+ },
+ 'CheckUserComparePagerFactory' => function ( MediaWikiServices $services ) : ComparePagerFactory {
+ return new ComparePagerFactory(
+ $services->getLinkRenderer(),
+ $services->get( 'CheckUserTokenQueryManager' ),
+ $services->get( 'CheckUserDurationManager' ),
+ $services->get( 'CheckUserCompareService' )
+ );
+ },
+ 'CheckUserTimelineRowFormatterFactory' => function (
+ MediaWikiServices $services
+ ) : TimelineRowFormatterFactory {
+ return new TimelineRowFormatterFactory(
+ $services->getLinkRenderer(),
+ $services->getDBLoadBalancer(),
+ $services->getRevisionLookup(),
+ $services->getRevisionStore(),
+ $services->getRevisionFactory(),
+ $services->getTitleFormatter(),
+ $services->getSpecialPageFactory()
+ );
+ },
+ 'CheckUserTimelinePagerFactory' => function (
+ MediaWikiServices $services
+ ) : TimelinePagerFactory {
+ return new TimelinePagerFactory(
+ $services->getLinkRenderer(),
+ $services->get( 'CheckUserHookRunner' ),
+ $services->get( 'CheckUserTokenQueryManager' ),
+ $services->get( 'CheckUserDurationManager' ),
+ $services->get( 'CheckUserTimelineService' ),
+ $services->get( 'CheckUserTimelineRowFormatterFactory' )
+ );
+ },
+ 'CheckUserUserManager' => function (
+ MediaWikiServices $services
+ ) : UserManager {
+ return new UserManager();
+ },
+ 'CheckUserEventLogger' => function (
+ MediaWikiServices $services
+ ) : EventLogger {
+ return new EventLogger(
+ \ExtensionRegistry::getInstance()
+ );
+ },
+ 'CheckUserHookRunner' => function (
+ MediaWikiServices $services
+ ) : HookRunner {
+ return new HookRunner(
+ $services->getHookContainer()
+ );
+ }
+];
diff --git a/CheckUser/includes/api/ApiQueryCheckUser.php b/CheckUser/includes/api/ApiQueryCheckUser.php
index 15584c76..7562d090 100644
--- a/CheckUser/includes/api/ApiQueryCheckUser.php
+++ b/CheckUser/includes/api/ApiQueryCheckUser.php
@@ -1,5 +1,9 @@
<?php
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Revision\RevisionRecord;
+use Wikimedia\IPUtils;
+
/**
* CheckUser API Query Module
*/
@@ -10,15 +14,19 @@ class ApiQueryCheckUser extends ApiQueryBase {
public function execute() {
$db = $this->getDB();
- $params = $this->extractRequestParams();
- list( $request, $target, $reason, $timecond, $limit, $xff ) = [
- $params['request'], $params['target'], $params['reason'],
- $params['timecond'], $params['limit'], $params['xff'] ];
+ [
+ 'request' => $request,
+ 'target' => $target,
+ 'reason' => $reason,
+ 'timecond' => $timecond,
+ 'limit' => $limit,
+ 'xff' => $xff,
+ ] = $this->extractRequestParams();
$this->checkUserRightsAny( 'checkuser' );
- if ( $this->getConfig()->get( 'CheckUserForceSummary' ) && is_null( $reason ) ) {
+ if ( $this->getConfig()->get( 'CheckUserForceSummary' ) && $reason === null ) {
$this->dieWithError( 'apierror-checkuser-missingsummary', 'missingdata' );
}
@@ -43,7 +51,8 @@ class ApiQueryCheckUser extends ApiQueryBase {
}
$this->addFields( [ 'cuc_timestamp', 'cuc_ip', 'cuc_xff' ] );
- $this->addWhereFld( 'cuc_user_text', $target );
+ // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141
+ $this->addWhereFld( 'cuc_user', $user_id );
$res = $this->select( __METHOD__ );
$result = $this->getResult();
@@ -53,8 +62,10 @@ class ApiQueryCheckUser extends ApiQueryBase {
$ip = strval( $row->cuc_ip );
if ( !isset( $ips[$ip] ) ) {
- $ips[$ip]['end'] = $timestamp;
- $ips[$ip]['editcount'] = 1;
+ $ips[$ip] = [
+ 'end' => $timestamp,
+ 'editcount' => 1
+ ];
} else {
$ips[$ip]['start'] = $timestamp;
$ips[$ip]['editcount']++;
@@ -75,7 +86,7 @@ class ApiQueryCheckUser extends ApiQueryBase {
break;
case 'edits':
- if ( IP::isIPAddress( $target ) ) {
+ if ( IPUtils::isIPAddress( $target ) ) {
$cond = SpecialCheckUser::getIpConds( $db, $target, isset( $xff ) );
if ( !$cond ) {
$this->dieWithError( 'apierror-badip', 'invalidip' );
@@ -90,18 +101,19 @@ class ApiQueryCheckUser extends ApiQueryBase {
$log_type[] = 'ip';
} else {
$user_id = User::idFromName( $target );
- if ( !$user_id ) {
+ if ( $user_id === null ) {
$this->dieWithError(
[ 'nosuchusershort', wfEscapeWikiText( $target ) ], 'nosuchuser'
);
}
- $this->addWhereFld( 'cuc_user_text', $target );
+ // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141
+ $this->addWhereFld( 'cuc_user', $user_id );
$log_type = [ 'useredits', 'user' ];
}
$this->addFields( [
- 'cuc_namespace', 'cuc_title', 'cuc_user_text', 'cuc_actiontext',
- 'cuc_comment', 'cuc_minor', 'cuc_timestamp', 'cuc_ip', 'cuc_xff', 'cuc_agent'
+ 'cuc_namespace', 'cuc_title', 'cuc_user_text', 'cuc_actiontext', 'cuc_this_oldid',
+ 'cuc_comment', 'cuc_minor', 'cuc_timestamp', 'cuc_ip', 'cuc_xff', 'cuc_agent', 'cuc_type'
] );
$res = $this->select( __METHOD__ );
@@ -117,10 +129,52 @@ class ApiQueryCheckUser extends ApiQueryBase {
'ip' => $row->cuc_ip,
'agent' => $row->cuc_agent,
];
+
if ( $row->cuc_actiontext ) {
$edit['summary'] = $row->cuc_actiontext;
} elseif ( $row->cuc_comment ) {
$edit['summary'] = $row->cuc_comment;
+ if ( $row->cuc_this_oldid != 0 &&
+ ( $row->cuc_type == RC_EDIT || $row->cuc_type == RC_NEW )
+ ) {
+ $revRecord = MediaWikiServices::getInstance()
+ ->getRevisionLookup()
+ ->getRevisionById( $row->cuc_this_oldid );
+ if ( !$revRecord ) {
+ $dbr = wfGetDB( DB_REPLICA );
+ $queryInfo = MediaWikiServices::getInstance()
+ ->getRevisionStore()
+ ->getArchiveQueryInfo();
+ $tmp = $dbr->selectRow(
+ $queryInfo['tables'],
+ $queryInfo['fields'],
+ [ 'ar_rev_id' => $row->cuc_this_oldid ],
+ __METHOD__,
+ [],
+ $queryInfo['joins']
+ );
+ if ( $tmp ) {
+ $revRecord = MediaWikiServices::getInstance()
+ ->getRevisionFactory()
+ ->newRevisionFromArchiveRow( $tmp );
+ }
+ }
+ if ( !$revRecord ) {
+ // This shouldn't happen, CheckUser points to a revision
+ // that isn't in revision nor archive table?
+ throw new Exception(
+ "Couldn't fetch revision cu_changes table links to " .
+ "(cuc_this_oldid {$row->cuc_this_oldid})"
+ );
+ }
+ if ( !RevisionRecord::userCanBitfield(
+ $revRecord->getVisibility(),
+ RevisionRecord::DELETED_COMMENT,
+ $this->getUser()
+ ) ) {
+ $edit['summary'] = $this->msg( 'rev-deleted-comment' )->text();
+ }
+ }
}
if ( $row->cuc_minor ) {
$edit['minor'] = 'm';
@@ -132,7 +186,7 @@ class ApiQueryCheckUser extends ApiQueryBase {
}
SpecialCheckUser::addLogEntry( $log_type[0], $log_type[1],
- $target, $reason, isset( $user_id ) ? $user_id : '0' );
+ $target, $reason, $user_id ?? '0' );
$result->addValue( [
'query', $this->getModuleName() ], 'edits', $edits );
$result->addIndexedTagName( [
@@ -140,7 +194,7 @@ class ApiQueryCheckUser extends ApiQueryBase {
break;
case 'ipusers':
- if ( IP::isIPAddress( $target ) ) {
+ if ( IPUtils::isIPAddress( $target ) ) {
$cond = SpecialCheckUser::getIpConds( $db, $target, isset( $xff ) );
$this->addWhere( $cond );
$log_type = 'ipusers';
@@ -149,6 +203,7 @@ class ApiQueryCheckUser extends ApiQueryBase {
}
} else {
$this->dieWithError( 'apierror-badip', 'invalidip' );
+ throw new LogicException();
}
$this->addFields( [
@@ -164,10 +219,12 @@ class ApiQueryCheckUser extends ApiQueryBase {
$agent = $row->cuc_agent;
if ( !isset( $users[$user] ) ) {
- $users[$user]['end'] = wfTimestamp( TS_ISO_8601, $row->cuc_timestamp );
- $users[$user]['editcount'] = 1;
- $users[$user]['ips'][] = $ip;
- $users[$user]['agents'][] = $agent;
+ $users[$user] = [
+ 'end' => wfTimestamp( TS_ISO_8601, $row->cuc_timestamp ),
+ 'editcount' => 1,
+ 'ips' => [ $ip ],
+ 'agents' => [ $agent ]
+ ];
} else {
$users[$user]['start'] = wfTimestamp( TS_ISO_8601, $row->cuc_timestamp );
$users[$user]['editcount']++;
@@ -224,11 +281,11 @@ class ApiQueryCheckUser extends ApiQueryBase {
],
'reason' => null,
'limit' => [
- ApiBase::PARAM_DFLT => 1000,
+ ApiBase::PARAM_DFLT => 500,
ApiBase::PARAM_TYPE => 'limit',
ApiBase::PARAM_MIN => 1,
ApiBase::PARAM_MAX => 500,
- ApiBase::PARAM_MAX2 => 5000,
+ ApiBase::PARAM_MAX2 => $this->getConfig()->get( 'CheckUserMaximumRowCount' ),
],
'timecond' => [
ApiBase::PARAM_DFLT => '-2 weeks'
@@ -251,7 +308,7 @@ class ApiQueryCheckUser extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/Extension:CheckUser#API';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:CheckUser#API';
}
public function needsToken() {
diff --git a/CheckUser/includes/api/ApiQueryCheckUserLog.php b/CheckUser/includes/api/ApiQueryCheckUserLog.php
index 0ffa7b01..5ef84ca4 100644
--- a/CheckUser/includes/api/ApiQueryCheckUserLog.php
+++ b/CheckUser/includes/api/ApiQueryCheckUserLog.php
@@ -9,6 +9,7 @@ class ApiQueryCheckUserLog extends ApiQueryBase {
}
public function execute() {
+ $db = $this->getDB();
$params = $this->extractRequestParams();
$this->checkUserRightsAny( 'checkuser-log' );
@@ -34,13 +35,15 @@ class ApiQueryCheckUserLog extends ApiQueryBase {
$this->addWhereFld( 'cul_target_text', $params['target'] );
}
+ // Filter out log entries from Special:Investigate
+ $this->addWhere( 'cul_type != ' . $db->addQuotes( 'investigate' ) );
+
if ( $continue !== null ) {
$cont = explode( '|', $continue );
$op = $dir === 'older' ? '<' : '>';
$this->dieContinueUsageIf( count( $cont ) !== 2 );
$this->dieContinueUsageIf( wfTimestamp( TS_UNIX, $cont[0] ) === false );
- $db = $this->getDB();
$timestamp = $db->addQuotes( $db->timestamp( $cont[0] ) );
$id = intval( $cont[1] );
$this->dieContinueUsageIf( $cont[1] !== (string)$id );
@@ -126,6 +129,6 @@ class ApiQueryCheckUserLog extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/Extension:CheckUser#API';
+ return 'https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:CheckUser#API';
}
}
diff --git a/CheckUser/includes/specials/SpecialCheckUser.php b/CheckUser/includes/specials/SpecialCheckUser.php
index 83a12fec..1c73ce66 100644
--- a/CheckUser/includes/specials/SpecialCheckUser.php
+++ b/CheckUser/includes/specials/SpecialCheckUser.php
@@ -1,16 +1,37 @@
<?php
+use MediaWiki\Block\DatabaseBlock;
+use MediaWiki\Cache\LinkBatchFactory;
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Revision\RevisionRecord;
+use Wikimedia\IPUtils;
+use Wikimedia\Rdbms\FakeResultWrapper;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\IResultWrapper;
class SpecialCheckUser extends SpecialPage {
/**
- * @var null|array $message Used to cache frequently used messages
+ * @var string[] $message Used to cache frequently used messages
*/
- protected $message = null;
+ protected $message = [];
- public function __construct() {
+ /**
+ * @var null|string
+ */
+ private $lastdate = null;
+
+ /**
+ * Reason for executing a CheckUser
+ * @var string
+ */
+ protected $reason = '';
+
+ /** @var LinkBatchFactory */
+ private $linkBatchFactory;
+
+ public function __construct( LinkBatchFactory $linkBatchFactory ) {
parent::__construct( 'CheckUser', 'checkuser' );
+ $this->linkBatchFactory = $linkBatchFactory;
}
public function doesWrites() {
@@ -19,22 +40,24 @@ class SpecialCheckUser extends SpecialPage {
public function execute( $subpage ) {
$this->setHeaders();
+ $this->addHelpLink( 'Extension:CheckUser' );
$this->checkPermissions();
// Logging and blocking requires writing so stop from here if read-only mode
$this->checkReadOnly();
// Blocked users are not allowed to run checkuser queries (bug T157883)
- $callingUser = $this->getUser();
- if ( $callingUser->isBlocked() ) {
- throw new UserBlockedError( $callingUser->getBlock() );
+ $block = $this->getUser()->getBlock();
+ if ( $block && $block->isSitewide() ) {
+ throw new UserBlockedError( $block );
}
$out = $this->getOutput();
$request = $this->getRequest();
$user = $request->getText( 'user', $request->getText( 'ip', $subpage ) );
$user = trim( $user );
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
- if ( $this->getUser()->isAllowed( 'checkuser-log' ) ) {
+ if ( $permissionManager->userHasRight( $this->getUser(), 'checkuser-log' ) ) {
$subtitleLink = $this->getLinkRenderer()->makeKnownLink(
SpecialPage::getTitleFor( 'CheckUserLog' ),
$this->msg( 'checkuser-showlog' )->text()
@@ -48,7 +71,18 @@ class SpecialCheckUser extends SpecialPage {
$out->addSubtitle( $subtitleLink );
}
- $reason = $request->getText( 'reason' );
+ if ( $this->getConfig()->get( 'CheckUserEnableSpecialInvestigate' ) ) {
+ $out->enableOOUI();
+ $out->addModuleStyles( 'oojs-ui.styles.icons-interactions' );
+ $icon = new OOUI\IconWidget( [ 'icon' => 'lightbulb' ] );
+ $investigateLink = $this->getLinkRenderer()->makeKnownLink(
+ SpecialPage::getTitleFor( 'Investigate' ),
+ $this->msg( 'checkuser-link-investigate-label' )->text()
+ );
+ $out->setIndicators( [ 'investigate-link' => $icon . $investigateLink ] );
+ }
+
+ $this->reason = $request->getText( 'reason' );
$blockreason = $request->getText( 'blockreason', '' );
$disableUserTalk = $request->getBool( 'blocktalk', false );
$disableEmail = $request->getBool( 'blockemail', false );
@@ -64,23 +98,24 @@ class SpecialCheckUser extends SpecialPage {
'reason' => $blockreason,
'talk' => $disableUserTalk,
'email' => $disableEmail,
+ 'reblock' => $request->getBool( 'reblock' )
];
$ip = $name = $xff = '';
$m = [];
- if ( IP::isIPAddress( $user ) ) {
+ if ( IPUtils::isIPAddress( $user ) ) {
// A single IP address or an IP range
- $ip = IP::sanitizeIP( $user );
- } elseif ( preg_match( '/^(.+)\/xff$/', $user, $m ) && IP::isIPAddress( $m[1] ) ) {
+ $ip = IPUtils::sanitizeIP( $user );
+ } elseif ( preg_match( '/^(.+)\/xff$/', $user, $m ) && IPUtils::isIPAddress( $m[1] ) ) {
// A single IP address or range with XFF string included
- $xff = IP::sanitizeIP( $m[1] );
+ $xff = IPUtils::sanitizeIP( $m[1] );
} else {
// A user?
$name = $user;
}
$this->showIntroductoryText();
- $this->showForm( $user, $reason, $checktype, $ip, $xff, $name, $period );
+ $this->showForm( $user, $checktype, $ip, $xff, $name, $period );
// Perform one of the various submit operations...
if ( $request->wasPosted() ) {
@@ -88,34 +123,34 @@ class SpecialCheckUser extends SpecialPage {
$out->wrapWikiMsg( '<div class="error">$1</div>', 'checkuser-token-fail' );
} elseif ( $request->getVal( 'action' ) === 'block' ) {
$this->doMassUserBlock( $users, $blockParams, $tag, $talkTag );
- } elseif ( !$this->checkReason( $reason ) ) {
+ } elseif ( !$this->checkReason() ) {
$out->addWikiMsg( 'checkuser-noreason' );
} elseif ( $checktype == 'subuserips' ) {
- $this->doUserIPsRequest( $name, $reason, $period );
+ $this->doUserIPsRequest( $name, $period );
} elseif ( $xff && $checktype == 'subedits' ) {
- $this->doIPEditsRequest( $xff, true, $reason, $period );
+ $this->doIPEditsRequest( $xff, true, $period );
} elseif ( $ip && $checktype == 'subedits' ) {
- $this->doIPEditsRequest( $ip, false, $reason, $period );
+ $this->doIPEditsRequest( $ip, false, $period );
} elseif ( $name && $checktype == 'subedits' ) {
- $this->doUserEditsRequest( $user, $reason, $period );
+ $this->doUserEditsRequest( $user, $period );
} elseif ( $xff && $checktype == 'subipusers' ) {
- $this->doIPUsersRequest( $xff, true, $reason, $period, $tag, $talkTag );
+ $this->doIPUsersRequest( $xff, true, $period, $tag, $talkTag );
} elseif ( $checktype == 'subipusers' ) {
- $this->doIPUsersRequest( $ip, false, $reason, $period, $tag, $talkTag );
+ $this->doIPUsersRequest( $ip, false, $period, $tag, $talkTag );
}
}
// Add CIDR calculation convenience JS form
$this->addJsCIDRForm();
$out->addModules( 'ext.checkUser' );
+ $out->addModuleStyles( 'mediawiki.interface.helpers.styles' );
}
protected function showIntroductoryText() {
$cidrLimit = $this->getConfig()->get( 'CheckUserCIDRLimit' );
- $this->getOutput()->addWikiText(
- $this->msg( 'checkuser-summary',
- $cidrLimit['IPv4'],
- $cidrLimit['IPv6']
- )->text()
+ $this->getOutput()->addWikiMsg(
+ 'checkuser-summary',
+ $cidrLimit['IPv4'],
+ $cidrLimit['IPv6']
);
}
@@ -123,28 +158,27 @@ class SpecialCheckUser extends SpecialPage {
* Show the CheckUser query form
*
* @param string $user
- * @param string $reason
* @param string $checktype
* @param string $ip
* @param string $xff
* @param string $name
* @param int $period
*/
- protected function showForm( $user, $reason, $checktype, $ip, $xff, $name, $period ) {
+ protected function showForm( $user, $checktype, $ip, $xff, $name, $period ) {
$action = htmlspecialchars( $this->getPageTitle()->getLocalURL() );
// Fill in requested type if it makes sense
- $encipusers = $encedits = $encuserips = 0;
+ $encipusers = $encedits = $encuserips = false;
if ( $checktype == 'subipusers' && ( $ip || $xff ) ) {
- $encipusers = 1;
+ $encipusers = true;
} elseif ( $checktype == 'subuserips' && $name ) {
- $encuserips = 1;
+ $encuserips = true;
} elseif ( $checktype == 'subedits' ) {
- $encedits = 1;
+ $encedits = true;
// Defaults otherwise
} elseif ( $ip || $xff ) {
- $encedits = 1;
+ $encedits = true;
} else {
- $encuserips = 1;
+ $encuserips = true;
}
$form = Xml::openElement( 'form', [ 'action' => $action,
@@ -176,7 +210,7 @@ class SpecialCheckUser extends SpecialPage {
$form .= Xml::closeElement( 'td' );
$form .= '</tr><tr>';
$form .= '<td>' . $this->msg( 'checkuser-reason' )->escaped() . '</td>';
- $form .= '<td>' . Xml::input( 'reason', 46, $reason,
+ $form .= '<td>' . Xml::input( 'reason', 46, $this->reason,
[ 'maxlength' => '150', 'id' => 'checkreason' ] );
$form .= '&#160; &#160;' . Xml::submitButton( $this->msg( 'checkuser-check' )->text(),
[ 'id' => 'checkusersubmit', 'name' => 'checkusersubmit' ] ) . '</td>';
@@ -201,10 +235,10 @@ class SpecialCheckUser extends SpecialPage {
'select',
[ 'name' => 'period', 'id' => 'period', 'style' => 'margin-top:.2em;' ]
);
- $s .= Xml::option( $this->msg( 'checkuser-week-1' )->text(), 7, $selected === 7 );
- $s .= Xml::option( $this->msg( 'checkuser-week-2' )->text(), 14, $selected === 14 );
- $s .= Xml::option( $this->msg( 'checkuser-month' )->text(), 31, $selected === 31 );
- $s .= Xml::option( $this->msg( 'checkuser-all' )->text(), 0, $selected === 0 );
+ $s .= Xml::option( $this->msg( 'checkuser-week-1' )->text(), '7', $selected === 7 );
+ $s .= Xml::option( $this->msg( 'checkuser-week-2' )->text(), '14', $selected === 14 );
+ $s .= Xml::option( $this->msg( 'checkuser-month' )->text(), '31', $selected === 31 );
+ $s .= Xml::option( $this->msg( 'checkuser-all' )->text(), '0', $selected === 0 );
$s .= Xml::closeElement( 'select' ) . "\n";
return $s;
}
@@ -224,11 +258,10 @@ class SpecialCheckUser extends SpecialPage {
}
/**
- * @param string $reason
* @return bool
*/
- protected function checkReason( $reason ) {
- return ( !$this->getConfig()->get( 'CheckUserForceSummary' ) || strlen( $reason ) );
+ protected function checkReason() {
+ return ( !$this->getConfig()->get( 'CheckUserForceSummary' ) || strlen( $this->reason ) );
}
/**
@@ -236,7 +269,7 @@ class SpecialCheckUser extends SpecialPage {
* they are called often, we call them once and save them in $this->message
*/
protected function preCacheMessages() {
- if ( $this->message === null ) {
+ if ( $this->message === [] ) {
$msgKeys = [ 'diff', 'hist', 'minoreditletter', 'newpageletter', 'blocklink', 'log' ];
foreach ( $msgKeys as $msg ) {
$this->message[$msg] = $this->msg( $msg )->escaped();
@@ -253,7 +286,10 @@ class SpecialCheckUser extends SpecialPage {
*/
protected function doMassUserBlock( $users, $blockParams, $tag = '', $talkTag = '' ) {
$usersCount = count( $users );
- if ( !$this->getUser()->isAllowed( 'block' ) || $this->getUser()->isBlocked()
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+ if ( !$permissionManager->userHasRight( $this->getUser(), 'block' )
+ || $this->getUser()->getBlock()
|| !$usersCount
) {
$this->getOutput()->addWikiMsg( 'checkuser-block-failure' );
@@ -266,7 +302,12 @@ class SpecialCheckUser extends SpecialPage {
return;
}
- $blockedUsers = $this->doMassUserBlockInternal( $users, $blockParams, $tag, $talkTag );
+ $blockedUsers = $this->doMassUserBlockInternal(
+ $users,
+ $blockParams,
+ $tag,
+ $talkTag
+ );
$blockedCount = count( $blockedUsers );
if ( $blockedCount > 0 ) {
$lang = $this->getLanguage();
@@ -288,8 +329,12 @@ class SpecialCheckUser extends SpecialPage {
* @param string $talkTag replaces user talk pages
* @return string[] List of html-safe usernames which were actually were blocked
*/
- protected function doMassUserBlockInternal( $users, array $blockParams,
- $tag = '', $talkTag = '' ) {
+ protected function doMassUserBlockInternal(
+ $users,
+ array $blockParams,
+ $tag = '',
+ $talkTag = ''
+ ) {
$currentUser = $this->getUser();
$blockAllowsUTEdit = $this->getConfig()->get( 'BlockAllowsUTEdit' );
$safeUsers = [];
@@ -300,89 +345,52 @@ class SpecialCheckUser extends SpecialPage {
// Invalid user
continue;
}
- $isIP = IP::isIPAddress( $u->getName() );
+ $isIP = IPUtils::isIPAddress( $u->getName() );
if ( !$u->getId() && !$isIP ) {
// Not a registered user or an IP
continue;
}
- if ( $u->isBlocked() ) {
- // If the user is already blocked, just leave it as is
+ if ( $u->getBlock() && !$blockParams['reblock'] ) {
continue;
}
- $userTitle = $u->getUserPage();
- $userTalkTitle = $u->getTalkPage();
- $safeUsers[] = "[[{$userTitle->getPrefixedText()}|{$userTitle->getText()}]]";
- $expirestr = $isIP ? '1 week' : 'indefinite';
- $expiry = SpecialBlock::parseExpiryInput( $expirestr );
-
- // Create the block
- $block = new Block();
- $block->setTarget( $u );
- $block->setBlocker( $currentUser );
- $block->mReason = $blockParams['reason'];
- $block->mExpiry = $expiry;
- $block->isHardblock( !$isIP );
- $block->isAutoblocking( true );
- $block->prevents( 'createaccount', true );
- $block->prevents( 'sendemail',
- ( SpecialBlock::canBlockEmail( $currentUser ) && $blockParams['email'] )
- );
- $block->prevents( 'editownusertalk', ( !$blockAllowsUTEdit || $blockParams['talk'] ) );
- $status = $block->insert();
-
- // Prepare log parameters for the block
- $logParams = [];
- $logParams['5::duration'] = $expirestr;
- $logParams['6::flags'] = self::userBlockLogFlags( $isIP, $blockParams );
-
- $logEntry = new ManualLogEntry( 'block', 'block' );
- $logEntry->setTarget( $userTitle );
- $logEntry->setComment( $blockParams['reason'] );
- $logEntry->setPerformer( $currentUser );
- $logEntry->setParameters( $logParams );
- $blockIds = array_merge( [ $status['id'] ], $status['autoIds'] );
- $logEntry->setRelations( [ 'ipb_id' => $blockIds ] );
- $logEntry->publish( $logEntry->insert() );
+ if (
+ SpecialBlock::canBlockEmail( $this->getUser() ) ||
+ !isset( $blockParams['email' ] ) ||
+ $blockParams['email'] === false
+ ) {
+ $res = SpecialBlock::processForm( [
+ 'Target' => $u->getName(),
+ 'Reason' => [ $blockParams['reason'] ],
+ 'Expiry' => $isIP ? '1 week' : 'indefinite',
+ 'HardBlock' => !$isIP,
+ 'CreateAccount' => true,
+ 'AutoBlock' => true,
+ 'DisableEmail' => $blockParams['email'] ?? false,
+ 'DisableUTEdit' => $blockParams['talk'],
+ 'Reblock' => $blockParams['reblock'],
+ 'Confirm' => true,
+ 'Watch' => false,
+ ], $this->getContext() );
+
+ if ( $res === true ) {
+ $userPage = $u->getUserPage();
+
+ $safeUsers[] = "[[{$userPage->getPrefixedText()}|{$userPage->getText()}]]";
+
+ // Tag user page and user talk page
+ $this->tagPage( $userPage, $tag, $blockParams['reason'] );
+ $this->tagPage( $u->getTalkPage(), $talkTag, $blockParams['reason'] );
+ }
- // Tag user page and user talk page
- $this->tagPage( $userTitle, $tag, $blockParams['reason'] );
- $this->tagPage( $userTalkTitle, $talkTag, $blockParams['reason'] );
+ }
}
return $safeUsers;
}
/**
- * Return a comma-delimited list of "flags" to be passed to the block log.
- * Flags are 'anononly', 'nocreate', 'noemail' and 'nousertalk'.
- * @param bool $anonOnly
- * @param array $blockParams
- * @return string
- */
- protected static function userBlockLogFlags( $anonOnly, array $blockParams ) {
- global $wgBlockAllowsUTEdit;
- $flags = [];
-
- if ( $anonOnly ) {
- $flags[] = 'anononly';
- }
-
- $flags[] = 'nocreate';
-
- if ( $blockParams['email'] ) {
- $flags[] = 'noemail';
- }
-
- if ( $wgBlockAllowsUTEdit && $blockParams['talk'] ) {
- $flags[] = 'nousertalk';
- }
-
- return implode( ',', $flags );
- }
-
- /**
* Make an edit to the given page with the tag provided
*
* @param Title $title
@@ -444,10 +452,11 @@ class SpecialCheckUser extends SpecialPage {
if ( $lastEdit ) {
$lastEditTime = wfTimestamp( TS_MW, $lastEdit );
$lang = $this->getLanguage();
+ $contextUser = $this->getUser();
// FIXME: don't pass around parsed messages
return $this->msg( 'checkuser-nomatch-edits',
- $lang->date( $lastEditTime, true ),
- $lang->time( $lastEditTime, true )
+ $lang->userDate( $lastEditTime, $contextUser ),
+ $lang->userTime( $lastEditTime, $contextUser )
)->parseAsBlock();
}
}
@@ -458,14 +467,14 @@ class SpecialCheckUser extends SpecialPage {
* Show all the IPs used by a user
*
* @param string $user
- * @param string $reason
* @param int $period
+ * @return void
*/
- protected function doUserIPsRequest( $user, $reason = '', $period = 0 ) {
+ protected function doUserIPsRequest( $user, $period = 0 ) {
$out = $this->getOutput();
$userTitle = Title::newFromText( $user, NS_USER );
- if ( !is_null( $userTitle ) ) {
+ if ( $userTitle !== null ) {
// normalize the username
$user = $userTitle->getText();
}
@@ -484,107 +493,197 @@ class SpecialCheckUser extends SpecialPage {
}
// Record check...
- self::addLogEntry( 'userips', 'user', $user, $reason, $user_id );
+ self::addLogEntry( 'userips', 'user', $user, $this->reason, $user_id );
+
+ $result = $this->doUserIPsDBRequest( $user_id, $period );
+ $this->doUserIPsRequestOutput( $result, $user, $period );
+ }
+
+ /**
+ * Issue a DB query for doUserIPsRequestOutput
+ *
+ * @param int $user_id
+ * @param int $period
+ * @param int|null $limit
+ * @return IResultWrapper
+ */
+ protected function doUserIPsDBRequest( $user_id, $period = 0, $limit = null ) : IResultWrapper {
+ if ( $limit === null ) {
+ // We add 1 to the row count here because the number of rows returned is used to determine
+ // whether the data has been truncated.
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' ) + 1;
+ }
$dbr = wfGetDB( DB_REPLICA );
+ $conds = [ 'cuc_user' => $user_id ];
$time_conds = $this->getTimeConds( $period );
- // Ordering by the latest timestamp makes a small filesort on the IP list
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
- $ret = $dbr->select(
+ // Ordering by the latest timestamp makes a small filesort on the IP list
+ return $dbr->select(
'cu_changes',
[
'cuc_ip',
'cuc_ip_hex',
- 'COUNT(*) AS count',
- 'MIN(cuc_timestamp) AS first',
- 'MAX(cuc_timestamp) AS last',
+ 'count' => 'COUNT(*)',
+ 'first' => 'MIN(cuc_timestamp)',
+ 'last' => 'MAX(cuc_timestamp)',
],
- [ 'cuc_user' => $user_id, $time_conds ],
+ $conds,
__METHOD__,
[
'ORDER BY' => 'last DESC',
- 'GROUP BY' => 'cuc_ip,cuc_ip_hex',
- 'LIMIT' => 5001,
+ 'GROUP BY' => [ 'cuc_ip', 'cuc_ip_hex' ],
+ 'LIMIT' => $limit,
'USE INDEX' => 'cuc_user_ip_time',
]
);
+ }
- if ( !$dbr->numRows( $ret ) ) {
- $s = $this->noMatchesMessage( $user ) . "\n";
- } else {
- $ips_edits = [];
- $ips_first = [];
- $ips_last = [];
- $ips_hex = [];
- $counter = 0;
- foreach ( $ret as $row ) {
- if ( $counter >= 5000 ) {
- $out->addWikiMsg( 'checkuser-limited' );
- break;
- }
- $ips_edits[$row->cuc_ip] = $row->count;
- $ips_first[$row->cuc_ip] = $row->first;
- $ips_last[$row->cuc_ip] = $row->last;
- $ips_hex[$row->cuc_ip] = $row->cuc_ip_hex;
- ++$counter;
+ /**
+ * Return "checkuser-ipeditcount" number
+ *
+ * @param array $ips_hex
+ * @param string $ip
+ * @param int $period
+ * @return int
+ */
+ protected function getCountForIPedits( array $ips_hex, $ip, $period = 0 ) {
+ $dbr = wfGetDB( DB_REPLICA );
+ $conds = [ 'cuc_ip_hex' => $ips_hex[$ip] ];
+ $time_conds = $this->getTimeConds( $period );
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
+
+ $ipedits = $dbr->estimateRowCount(
+ 'cu_changes',
+ '*',
+ $conds,
+ __METHOD__
+ );
+ // If small enough, get a more accurate count
+ if ( $ipedits <= 1000 ) {
+ $ipedits = $dbr->selectField(
+ 'cu_changes',
+ 'COUNT(*)',
+ $conds,
+ __METHOD__
+ );
+ }
+
+ return $ipedits;
+ }
+
+ /**
+ * @param IResultWrapper $result
+ * @param int|null $limit
+ * @return array
+ */
+ protected function getIPSets( IResultWrapper $result, $limit = null ) : array {
+ if ( $limit === null ) {
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' );
+ }
+
+ $ipSets = [
+ 'edits' => [],
+ 'first' => [],
+ 'last' => [],
+ 'hex' => [],
+ 'exceed' => false
+ ];
+ $counter = 0;
+
+ foreach ( $result as $row ) {
+ if ( $counter >= $limit ) {
+ $ipSets['exceed'] = true;
+ break;
}
- // Count pinging might take some time...make sure it is there
- Wikimedia\suppressWarnings();
- set_time_limit( 60 );
- Wikimedia\restoreWarnings();
- $lang = $this->getLanguage();
+ $ipSets['edits'][$row->cuc_ip] = $row->count;
+ $ipSets['first'][$row->cuc_ip] = $row->first;
+ $ipSets['last'][$row->cuc_ip] = $row->last;
+ $ipSets['hex'][$row->cuc_ip] = $row->cuc_ip_hex;
+ ++$counter;
+ }
+ // Count pinging might take some time...make sure it is there
+ Wikimedia\suppressWarnings();
+ set_time_limit( 60 );
+ Wikimedia\restoreWarnings();
- $s = '<div id="checkuserresults"><ul>';
- foreach ( $ips_edits as $ip => $edits ) {
- $s .= '<li>';
- $s .= $this->getSelfLink( $ip,
- [
- 'user' => $ip,
- 'reason' => $reason,
- ]
- );
- $s .= ' ' . $this->msg( 'parentheses' )->rawParams(
- $this->getLinkRenderer()->makeKnownLink(
- SpecialPage::getTitleFor( 'Block', $ip ),
- $this->msg( 'blocklink' )->text()
- )
- )->escaped();
- $s .= ' ' . $this->getTimeRangeString( $ips_first[$ip], $ips_last[$ip] ) . ' ';
- $s .= ' <strong>[' . htmlspecialchars( $lang->formatNum( $edits ) ) . ']</strong>';
-
- // If we get some results, it helps to know if the IP in general
- // has a lot more edits, e.g. "tip of the iceberg"...
- $ipedits = $dbr->estimateRowCount( 'cu_changes', '*',
- [ 'cuc_ip_hex' => $ips_hex[$ip], $time_conds ],
- __METHOD__ );
- // If small enough, get a more accurate count
- if ( $ipedits <= 1000 ) {
- $ipedits = $dbr->selectField( 'cu_changes', 'COUNT(*)',
- [ 'cuc_ip_hex' => $ips_hex[$ip], $time_conds ],
- __METHOD__ );
- }
- if ( $ipedits > $ips_edits[$ip] ) {
- $s .= ' <i>(' .
- $this->msg( 'checkuser-ipeditcount' )->numParams( $ipedits )->escaped() .
- ')</i>';
- }
+ return $ipSets;
+ }
- // If this IP is blocked, give a link to the block log
- $s .= $this->getIPBlockInfo( $ip );
- $s .= '<div style="margin-left:5%">';
- $s .= '<small>' . $this->msg( 'checkuser-toollinks', urlencode( $ip ) )->parse() .
- '</small>';
- $s .= '</div>';
- $s .= "</li>\n";
+ /**
+ * Result output for doUserIPsRequest
+ *
+ * @param IResultWrapper $result
+ * @param string $user
+ * @param int $period
+ * @return void
+ */
+ protected function doUserIPsRequestOutput( IResultWrapper $result, $user, $period ) {
+ $out = $this->getOutput();
+ $lang = $this->getLanguage();
+
+ if ( !$result->numRows() ) {
+ $out->addHTML( $this->noMatchesMessage( $user ) . "\n" );
+ return;
+ }
+
+ $ipSets = $this->getIPSets( $result );
+ $ips_edits = $ipSets['edits'];
+ $ips_first = $ipSets['first'];
+ $ips_last = $ipSets['last'];
+ $ips_hex = $ipSets['hex'];
+
+ if ( $ipSets['exceed'] ) {
+ $out->addWikiMsg( 'checkuser-limited' );
+ }
+
+ $s = '<div id="checkuserresults"><ul>';
+ foreach ( $ips_edits as $ip => $edits ) {
+ $s .= '<li>';
+ $s .= $this->getSelfLink( $ip,
+ [
+ 'user' => $ip,
+ 'reason' => $this->reason,
+ ]
+ );
+ $s .= ' ' . $this->msg( 'parentheses' )->rawParams(
+ $this->getLinkRenderer()->makeKnownLink(
+ SpecialPage::getTitleFor( 'Block', $ip ),
+ $this->msg( 'blocklink' )->text()
+ )
+ )->escaped();
+ $s .= ' ' . $this->getTimeRangeString( $ips_first[$ip], $ips_last[$ip] ) . ' ';
+ $s .= ' <strong>[' . htmlspecialchars( $lang->formatNum( $edits ) ) . ']</strong>';
+
+ // If we get some results, it helps to know if the IP in general
+ // has a lot more edits, e.g. "tip of the iceberg"...
+ $ipedits = $this->getCountForIPedits( $ips_hex, $ip, $period );
+ if ( $ipedits > $ips_edits[$ip] ) {
+ $s .= ' <i>(' .
+ $this->msg( 'checkuser-ipeditcount' )->numParams( $ipedits )->escaped() .
+ ')</i>';
}
- $s .= '</ul></div>';
+
+ // If this IP is blocked, give a link to the block log
+ $s .= $this->getIPBlockInfo( $ip );
+ $s .= '<div style="margin-left:5%">';
+ $s .= '<small>' . $this->msg( 'checkuser-toollinks', urlencode( $ip ) )->parse() .
+ '</small>';
+ $s .= '</div>';
+ $s .= "</li>\n";
}
+ $s .= '</ul></div>';
$out->addHTML( $s );
}
protected function getIPBlockInfo( $ip ) {
- $block = Block::newFromTarget( null, $ip, false );
- if ( $block instanceof Block ) {
+ $block = DatabaseBlock::newFromTarget( null, $ip, false );
+ if ( $block instanceof DatabaseBlock ) {
return $this->getBlockFlag( $block );
}
return '';
@@ -593,11 +692,11 @@ class SpecialCheckUser extends SpecialPage {
/**
* Get a link to block information about the passed block for displaying to the user.
*
- * @param Block $block
+ * @param DatabaseBlock $block
* @return string
*/
- protected function getBlockFlag( Block $block ) {
- if ( $block->getType() == Block::TYPE_AUTO ) {
+ protected function getBlockFlag( DatabaseBlock $block ) {
+ if ( $block->getType() == DatabaseBlock::TYPE_AUTO ) {
$ret = $this->getLinkRenderer()->makeKnownLink(
SpecialPage::getTitleFor( 'BlockList' ),
$this->msg( 'checkuser-blocked' )->text(),
@@ -618,7 +717,7 @@ class SpecialCheckUser extends SpecialPage {
}
// Add the blocked range if the block is on a range
- if ( $block->getType() == Block::TYPE_RANGE ) {
+ if ( $block->getType() == DatabaseBlock::TYPE_RANGE ) {
$ret .= ' - ' . htmlspecialchars( $block->getTarget() );
}
@@ -632,16 +731,15 @@ class SpecialCheckUser extends SpecialPage {
*
* @param string $ip
* @param bool $xfor if query is for XFF
- * @param string $reason
* @param int $period
+ * @return void
*/
- protected function doIPEditsRequest( $ip, $xfor = false, $reason = '', $period = 0 ) {
+ protected function doIPEditsRequest( $ip, $xfor = false, $period = 0 ) {
$out = $this->getOutput();
- $dbr = wfGetDB( DB_REPLICA );
+ $index = $xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time';
// Invalid IPs are passed in as a blank string
- $ip_conds = self::getIpConds( $dbr, $ip, $xfor );
- if ( !$ip || $ip_conds === false ) {
+ if ( !$ip || !self::isValidRange( $ip ) ) {
$out->addWikiMsg( 'badipaddress' );
return;
}
@@ -649,138 +747,265 @@ class SpecialCheckUser extends SpecialPage {
$logType = $xfor ? 'ipedits-xff' : 'ipedits';
// Record check in the logs
- self::addLogEntry( $logType, 'ip', $ip, $reason );
+ self::addLogEntry( $logType, 'ip', $ip, $this->reason );
- $ip_conds = $dbr->makeList( $ip_conds, LIST_AND );
- $time_conds = $this->getTimeConds( $period );
// Ordered in descent by timestamp. Can cause large filesorts on range scans.
// Check how many rows will need sorting ahead of time to see if this is too big.
// Also, if we only show 5000, too many will be ignored as well.
- $index = $xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time';
- if ( strpos( $ip, '/' ) !== false ) {
- // Quick index check only OK if no time constraint
- if ( $period ) {
- $rangecount = $dbr->selectField( 'cu_changes', 'COUNT(*)',
- [ $ip_conds, $time_conds ],
- __METHOD__,
- [ 'USE INDEX' => $index ] );
- } else {
- $rangecount = $dbr->estimateRowCount( 'cu_changes', '*',
- [ $ip_conds ],
- __METHOD__,
- [ 'USE INDEX' => $index ] );
- }
- // Sorting might take some time...make sure it is there
- Wikimedia\suppressWarnings();
- set_time_limit( 60 );
- Wikimedia\restoreWarnings();
+ $rangecount = $this->getIPEditsCount( $ip, $xfor, $index, $period );
+ if ( $rangecount > $this->getConfig()->get( 'CheckUserMaximumRowCount' ) ) {
+ // See what is best to do after testing the waters...
+ $result = $this->IPEditsTooManyDB( $ip, $xfor, $index, $period );
+ $this->IPEditsTooMany( $result, $ip, $xfor );
+ return;
+ } elseif ( $rangecount === 0 ) {
+ $out->addHTML( $this->noMatchesMessage( $ip, !$xfor ) . "\n" );
+ return;
}
- $counter = 0;
- // See what is best to do after testing the waters...
- if ( isset( $rangecount ) && $rangecount > 5000 ) {
- $lang = $this->getLanguage();
- $ret = $dbr->select(
+
+ // OK, do the real query...
+ $result = $this->doIPEditsDBRequest( $ip, $xfor, $index, $period );
+ $this->doIPEditsRequestOutput( $result, $ip, $xfor );
+ }
+
+ /**
+ * Get count for target IP range edits
+ *
+ * @param string $ip
+ * @param bool $xfor if query is for XFF
+ * @param string $index
+ * @param int $period
+ * @param int $timeLimit
+ * @return int
+ */
+ protected function getIPEditsCount( $ip, $xfor, $index, $period = 0, $timeLimit = 60 ) {
+ // Is not a IP range
+ if ( strpos( $ip, '/' ) === false ) {
+ return -1;
+ }
+
+ $dbr = wfGetDB( DB_REPLICA );
+ $conds = self::getIpConds( $dbr, $ip, $xfor );
+ if ( $conds === false ) {
+ return -1;
+ }
+ // Quick index check only OK if no time constraint
+ if ( $period ) {
+ $time_conds = $this->getTimeConds( $period );
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
+ $rangecount = $dbr->selectField(
'cu_changes',
- [
- 'cuc_ip_hex',
- 'COUNT(*) AS count',
- 'MIN(cuc_timestamp) AS first',
- 'MAX(cuc_timestamp) AS last'
- ],
- [ $ip_conds, $time_conds ],
+ 'COUNT(*)',
+ $conds,
__METHOD__,
+ [ 'USE INDEX' => $index ]
+ );
+ } else {
+ $rangecount = $dbr->estimateRowCount(
+ 'cu_changes',
+ '*',
+ $conds,
+ __METHOD__,
+ [ 'USE INDEX' => $index ]
+ );
+ }
+ // Sorting might take some time...make sure it is there
+ Wikimedia\suppressWarnings();
+ set_time_limit( $timeLimit );
+ Wikimedia\restoreWarnings();
+
+ return $rangecount;
+ }
+
+ /**
+ * Issue a DB query for IPEditsTooMany
+ *
+ * @param string $ip
+ * @param bool $xfor if query is for XFF
+ * @param string $index
+ * @param int $period
+ * @param int|null $limit
+ * @return IResultWrapper
+ */
+ protected function IPEditsTooManyDB(
+ $ip, $xfor, $index, $period = 0, $limit = null
+ ) : IResultWrapper {
+ if ( $limit === null ) {
+ // We add 1 to the row count here because the number of rows returned is used to determine
+ // whether the data has been truncated.
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' ) + 1;
+ }
+
+ $dbr = wfGetDB( DB_REPLICA );
+ $conds = self::getIpConds( $dbr, $ip, $xfor );
+ if ( $conds === false ) {
+ return new FakeResultWrapper( [] );
+ }
+ $time_conds = $this->getTimeConds( $period );
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
+
+ return $dbr->select(
+ 'cu_changes',
+ [
+ 'cuc_ip_hex',
+ 'count' => 'COUNT(*)',
+ 'first' => 'MIN(cuc_timestamp)',
+ 'last' => 'MAX(cuc_timestamp)',
+ ],
+ $conds,
+ __METHOD__,
+ [
+ 'GROUP BY' => 'cuc_ip_hex',
+ 'ORDER BY' => 'cuc_ip_hex',
+ 'LIMIT' => $limit,
+ 'USE INDEX' => $index,
+ ]
+ );
+ }
+
+ /**
+ * Return "checkuser-too-many" error with some hints
+ *
+ * @param IResultWrapper $result
+ * @param string $ip
+ * @param bool $xfor if query is for XFF
+ * @param int|null $limit
+ */
+ protected function IPEditsTooMany( IResultWrapper $result, $ip, $xfor, $limit = null ) {
+ if ( $limit === null ) {
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' );
+ }
+
+ $out = $this->getOutput();
+ $lang = $this->getLanguage();
+
+ // List out each IP that has edits
+ $s = $this->msg( 'checkuser-too-many', $lang->formatNum( $limit ) )->parseAsBlock();
+ $s .= '<ol>';
+
+ $counter = 0;
+ foreach ( $result as $row ) {
+ if ( $counter >= $limit ) {
+ $out->addWikiMsg( 'checkuser-limited' );
+ break;
+ }
+ // Convert the IP hexes into normal form
+ if ( strpos( $row->cuc_ip_hex, 'v6-' ) !== false ) {
+ $ip = substr( $row->cuc_ip_hex, 3 );
+ $ip = IPUtils::hexToOctet( $ip );
+ } else {
+ $ip = long2ip( Wikimedia\base_convert( $row->cuc_ip_hex, 16, 10, 8 ) );
+ }
+ $s .= '<li>';
+ $s .= $this->getSelfLink( $ip,
[
- 'GROUP BY' => 'cuc_ip_hex',
- 'ORDER BY' => 'cuc_ip_hex',
- 'LIMIT' => 5001,
- 'USE INDEX' => $index,
+ 'user' => $ip,
+ 'reason' => $this->reason,
+ 'checktype' => 'subipusers'
]
);
- // List out each IP that has edits
- $s = $this->msg( 'checkuser-too-many' )->parseAsBlock();
- $s .= '<ol>';
- foreach ( $ret as $row ) {
- if ( $counter >= 5000 ) {
- $out->addWikiMsg( 'checkuser-limited' );
- break;
- }
- // Convert the IP hexes into normal form
- if ( strpos( $row->cuc_ip_hex, 'v6-' ) !== false ) {
- $ip = substr( $row->cuc_ip_hex, 3 );
- $ip = IP::hexToOctet( $ip );
- } else {
- $ip = long2ip( Wikimedia\base_convert( $row->cuc_ip_hex, 16, 10, 8 ) );
- }
- $s .= '<li>';
- $s .= $this->getSelfLink( $ip,
- [
- 'user' => $ip,
- 'reason' => $reason,
- 'checktype' => 'subipusers'
- ]
- );
- $s .= ' ' . $this->getTimeRangeString( $row->first, $row->last ) . ' ';
- $s .= ' [<strong>' . htmlspecialchars( $lang->formatNum( $row->count ) ) .
- "</strong>]</li>\n";
- ++$counter;
- }
- $s .= '</ol>';
+ $s .= ' ' . $this->getTimeRangeString( $row->first, $row->last ) . ' ';
+ $s .= ' [<strong>' . htmlspecialchars( $lang->formatNum( $row->count ) ) .
+ "</strong>]</li>\n";
+ ++$counter;
+ }
+ $s .= '</ol>';
- $out->addHTML( $s );
- return;
- } elseif ( isset( $rangecount ) && !$rangecount ) {
- $s = $this->noMatchesMessage( $ip, !$xfor ) . "\n";
- $out->addHTML( $s );
- return;
+ $out->addHTML( $s );
+ }
+
+ /**
+ * Issue a DB query for doIPEditsRequestOutput
+ *
+ * @param string $ip
+ * @param bool $xfor if query is for XFF
+ * @param string $index
+ * @param int $period
+ * @param int|null $limit
+ * @return IResultWrapper
+ */
+ protected function doIPEditsDBRequest(
+ $ip, $xfor, $index, $period = 0, $limit = null
+ ) : IResultWrapper {
+ if ( $limit === null ) {
+ // We add 1 to the row count here because the number of rows returned is used to determine
+ // whether the data has been truncated.
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' ) + 1;
}
- // OK, do the real query...
+ $dbr = wfGetDB( DB_REPLICA );
+ $conds = self::getIpConds( $dbr, $ip, $xfor );
+ if ( $conds === false ) {
+ return new FakeResultWrapper( [] );
+ }
+ $time_conds = $this->getTimeConds( $period );
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
- $ret = $dbr->select(
+ return $dbr->select(
'cu_changes',
[
'cuc_namespace', 'cuc_title', 'cuc_user', 'cuc_user_text', 'cuc_comment',
'cuc_actiontext', 'cuc_timestamp', 'cuc_minor', 'cuc_page_id', 'cuc_type',
- 'cuc_this_oldid', 'cuc_last_oldid', 'cuc_ip', 'cuc_xff', 'cuc_agent'
+ 'cuc_this_oldid', 'cuc_last_oldid', 'cuc_ip', 'cuc_xff', 'cuc_agent',
],
- [ $ip_conds, $time_conds ],
+ $conds,
__METHOD__,
[
'ORDER BY' => 'cuc_timestamp DESC',
- 'LIMIT' => 5001,
+ 'LIMIT' => $limit,
'USE INDEX' => $index,
]
);
+ }
- if ( !$dbr->numRows( $ret ) ) {
- $s = $this->noMatchesMessage( $ip, !$xfor ) . "\n";
- } else {
- // Cache common messages
- $this->preCacheMessages();
- // Try to optimize this query
- $lb = new LinkBatch;
- foreach ( $ret as $row ) {
- $userText = str_replace( ' ', '_', $row->cuc_user_text );
- if ( $row->cuc_title !== '' ) {
- $lb->add( $row->cuc_namespace, $row->cuc_title );
- }
- $lb->add( NS_USER, $userText );
- $lb->add( NS_USER_TALK, $userText );
+ /**
+ * Result output for doIPEditsRequest
+ *
+ * @param IResultWrapper $result
+ * @param string $ip
+ * @param bool $xfor
+ * @return void
+ */
+ protected function doIPEditsRequestOutput( IResultWrapper $result, $ip, $xfor ) {
+ $out = $this->getOutput();
+
+ if ( !$result->numRows() ) {
+ $out->addHTML( $this->noMatchesMessage( $ip, !$xfor ) . "\n" );
+ return;
+ }
+
+ // Cache common messages
+ $this->preCacheMessages();
+ // Try to optimize this query
+ $lb = $this->linkBatchFactory->newLinkBatch();
+ foreach ( $result as $row ) {
+ $userText = str_replace( ' ', '_', $row->cuc_user_text );
+ if ( $row->cuc_title !== '' ) {
+ $lb->add( $row->cuc_namespace, $row->cuc_title );
}
- $lb->execute();
- $ret->seek( 0 );
- // List out the edits
- $s = '<div id="checkuserresults">';
- foreach ( $ret as $row ) {
- if ( $counter >= 5000 ) {
- $out->addWikiMsg( 'checkuser-limited' );
- break;
- }
- $s .= $this->CUChangesLine( $row, $reason );
- ++$counter;
+ $lb->add( NS_USER, $userText );
+ $lb->add( NS_USER_TALK, $userText );
+ }
+ $lb->execute();
+ $result->seek( 0 );
+ // List out the edits
+ $s = '<div id="checkuserresults">';
+ $counter = 0;
+ foreach ( $result as $row ) {
+ if ( $counter >= $this->getConfig()->get( 'CheckUserMaximumRowCount' ) ) {
+ $out->addWikiMsg( 'checkuser-limited' );
+ break;
}
- $s .= '</ul></div>';
+ $s .= $this->CUChangesLine( $row );
+ ++$counter;
}
+ $s .= '</ul></div>';
$out->addHTML( $s );
}
@@ -789,7 +1014,7 @@ class SpecialCheckUser extends SpecialPage {
* @param IResultWrapper $rows Results with cuc_namespace and cuc_title field
*/
protected function doLinkCache( IResultWrapper $rows ) {
- $lb = new LinkBatch();
+ $lb = $this->linkBatchFactory->newLinkBatch();
$lb->setCaller( __METHOD__ );
foreach ( $rows as $row ) {
if ( $row->cuc_title !== '' ) {
@@ -804,14 +1029,14 @@ class SpecialCheckUser extends SpecialPage {
* Shows all changes made by a particular user
*
* @param string $user
- * @param string $reason
* @param int $period
+ * @return void
*/
- protected function doUserEditsRequest( $user, $reason = '', $period = 0 ) {
+ protected function doUserEditsRequest( $user, $period = 0 ) {
$out = $this->getOutput();
$userTitle = Title::newFromText( $user, NS_USER );
- if ( !is_null( $userTitle ) ) {
+ if ( $userTitle !== null ) {
// normalize the username
$user = $userTitle->getText();
}
@@ -830,95 +1055,126 @@ class SpecialCheckUser extends SpecialPage {
}
// Record check...
- self::addLogEntry( 'useredits', 'user', $user, $reason, $user_id );
+ self::addLogEntry( 'useredits', 'user', $user, $this->reason, $user_id );
+ // Cache common messages
+ $this->preCacheMessages();
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' );
+
+ // Sorting might take some time...make sure it is there
+ Wikimedia\suppressWarnings();
+ set_time_limit( 60 );
+ Wikimedia\restoreWarnings();
+
+ // OK, do the real query...
+ $result = $this->doUserEditsDBRequest( $user_id, $period, $limit );
+ $this->doUserEditsRequestOutput( $result, $user, $limit );
+ }
+
+ /**
+ * get count for the user edits
+ *
+ * @param int $user_id
+ * @param int $period
+ * @return int
+ */
+ protected function getCountsForUserEdits( $user_id, $period = 0 ) {
$dbr = wfGetDB( DB_REPLICA );
- $user_cond = "cuc_user = " . $dbr->addQuotes( $user_id );
+ $conds = [ 'cuc_user' => $user_id ];
$time_conds = $this->getTimeConds( $period );
- // Ordered in descent by timestamp. Causes large filesorts if there are many edits.
- // Check how many rows will need sorting ahead of time to see if this is too big.
- // If it is, sort by IP,time to avoid the filesort.
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
+
if ( $period ) {
- $count = $dbr->selectField( 'cu_changes', 'COUNT(*)',
- [ $user_cond, $time_conds ],
+ return $dbr->selectField(
+ 'cu_changes',
+ 'COUNT(*)',
+ $conds,
__METHOD__,
- [ 'USE INDEX' => 'cuc_user_ip_time' ] );
+ [ 'USE INDEX' => 'cuc_user_ip_time' ]
+ );
} else {
- $count = $dbr->estimateRowCount( 'cu_changes', '*',
- [ $user_cond, $time_conds ],
- __METHOD__,
- [ 'USE INDEX' => 'cuc_user_ip_time' ] );
- }
- // Cache common messages
- $this->preCacheMessages();
- // See what is best to do after testing the waters...
- if ( $count > 5000 ) {
- $out->addHTML( $this->msg( 'checkuser-limited' )->parse() );
-
- $ret = $dbr->select(
+ return $dbr->estimateRowCount(
'cu_changes',
'*',
- [ $user_cond, $time_conds ],
+ $conds,
__METHOD__,
- [
- 'ORDER BY' => 'cuc_ip ASC, cuc_timestamp DESC',
- 'LIMIT' => 5000,
- 'USE INDEX' => 'cuc_user_ip_time'
- ]
+ [ 'USE INDEX' => 'cuc_user_ip_time' ]
);
- // Try to optimize this query
- $this->doLinkCache( $ret );
- $s = '';
- foreach ( $ret as $row ) {
- $ip = htmlspecialchars( $row->cuc_ip );
- if ( !$ip ) {
- continue;
- }
- if ( !isset( $lastIP ) ) {
- $lastIP = $row->cuc_ip;
- $s .= "\n<h2>$ip</h2>\n<div class=\"special\">";
- } elseif ( $lastIP != $row->cuc_ip ) {
- $s .= "</ul></div>\n<h2>$ip</h2>\n<div class=\"special\">";
- $lastIP = $row->cuc_ip;
- unset( $this->lastdate ); // start over
- }
- $s .= $this->CUChangesLine( $row, $reason );
- }
- $s .= '</ul></div>';
+ }
+ }
- $out->addHTML( $s );
- return;
+ /**
+ * Issue a DB query for doUserEditsRequestOutput
+ *
+ * @param int $user_id
+ * @param int $period
+ * @param int|null $limit
+ * @return IResultWrapper
+ */
+ protected function doUserEditsDBRequest( $user_id, $period = 0, $limit = null ) : IResultWrapper {
+ if ( $limit === null ) {
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' );
}
- // Sorting might take some time...make sure it is there
- Wikimedia\suppressWarnings();
- set_time_limit( 60 );
- Wikimedia\restoreWarnings();
- // OK, do the real query...
+ $dbr = wfGetDB( DB_REPLICA );
+ $conds = [ 'cuc_user' => $user_id ];
+ $time_conds = $this->getTimeConds( $period );
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
- $ret = $dbr->select(
- 'cu_changes',
- '*',
- [ $user_cond, $time_conds ],
+ return $dbr->select(
+ 'cu_changes', [
+ 'cuc_namespace', 'cuc_title', 'cuc_user', 'cuc_user_text', 'cuc_comment',
+ 'cuc_actiontext', 'cuc_timestamp', 'cuc_minor', 'cuc_page_id', 'cuc_type',
+ 'cuc_this_oldid', 'cuc_last_oldid', 'cuc_ip', 'cuc_xff', 'cuc_agent',
+ ],
+ $conds,
__METHOD__,
[
'ORDER BY' => 'cuc_timestamp DESC',
- 'LIMIT' => 5000,
+ 'LIMIT' => $limit,
'USE INDEX' => 'cuc_user_ip_time'
]
);
- if ( !$dbr->numRows( $ret ) ) {
- $html = $this->noMatchesMessage( $user ) . "\n";
- } else {
- $this->doLinkCache( $ret );
- // List out the edits
- $html = '<div id="checkuserresults">';
- foreach ( $ret as $row ) {
- $html .= $this->CUChangesLine( $row, $reason );
- }
- $html .= '</ul></div>';
+ }
+
+ /**
+ * Result output for doUserEditsRequest
+ *
+ * @param IResultWrapper $result
+ * @param string $user
+ * @param int|null $limit
+ * @return void
+ */
+ protected function doUserEditsRequestOutput( IResultWrapper $result, $user, $limit = null ) {
+ if ( $limit === null ) {
+ $limit = $this->getConfig()->get( 'CheckUserMaximumRowCount' );
+ }
+
+ $out = $this->getOutput();
+
+ if ( !$result->numRows() ) {
+ $out->addHTML( $this->noMatchesMessage( $user ) . "\n" );
+ return;
+ }
+
+ if ( $result->numRows() >= $limit ) {
+ // If the actual row count is at or over the limit, provide a warning
+ // that the results may have been truncated
+ $out->addHTML( $this->msg( 'checkuser-limited' )->parse() );
}
+ $this->doLinkCache( $result );
+ // List out the edits
+ $html = '<div id="checkuserresults">';
+ foreach ( $result as $row ) {
+ $html .= $this->CUChangesLine( $row );
+ }
+ $html .= '</ul></div>';
+
$out->addHTML( $html );
}
@@ -929,21 +1185,19 @@ class SpecialCheckUser extends SpecialPage {
*
* @param string $ip
* @param bool $xfor
- * @param string $reason
* @param int $period
* @param string $tag
* @param string $talkTag
+ * @return void
*/
protected function doIPUsersRequest(
- $ip, $xfor = false, $reason = '', $period = 0, $tag = '', $talkTag = ''
+ $ip, $xfor = false, $period = 0, $tag = '', $talkTag = ''
) {
- global $wgMemc;
$out = $this->getOutput();
- $dbr = wfGetDB( DB_REPLICA );
+ $index = $xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time';
// Invalid IPs are passed in as a blank string
- $ip_conds = self::getIpConds( $dbr, $ip, $xfor );
- if ( !$ip || $ip_conds === false ) {
+ if ( !$ip || !self::isValidRange( $ip ) ) {
$out->addWikiMsg( 'badipaddress' );
return;
}
@@ -951,341 +1205,373 @@ class SpecialCheckUser extends SpecialPage {
$logType = $xfor ? 'ipusers-xff' : 'ipusers';
// Log the check...
- self::addLogEntry( $logType, 'ip', $ip, $reason );
+ self::addLogEntry( $logType, 'ip', $ip, $this->reason );
- $ip_conds = $dbr->makeList( $ip_conds, LIST_AND );
- $time_conds = $this->getTimeConds( $period );
- $index = $xfor ? 'cuc_xff_hex_time' : 'cuc_ip_hex_time';
- // Ordered in descent by timestamp. Can cause large filesorts on range scans.
- // Check how many rows will need sorting ahead of time to see if this is too big.
- if ( strpos( $ip, '/' ) !== false ) {
- // Quick index check only OK if no time constraint
- if ( $period ) {
- $rangecount = $dbr->selectField( 'cu_changes', 'COUNT(*)',
- [ $ip_conds, $time_conds ],
- __METHOD__,
- [ 'USE INDEX' => $index ] );
- } else {
- $rangecount = $dbr->estimateRowCount( 'cu_changes', '*',
- [ $ip_conds ],
- __METHOD__,
- [ 'USE INDEX' => $index ] );
- }
- // Sorting might take some time...make sure it is there
- Wikimedia\suppressWarnings();
- set_time_limit( 120 );
- Wikimedia\restoreWarnings();
- }
// Are there too many edits?
- if ( isset( $rangecount ) && $rangecount > 10000 ) {
- $lang = $this->getLanguage();
- $ret = $dbr->select(
- 'cu_changes',
- [
- 'cuc_ip_hex', 'COUNT(*) AS count',
- 'MIN(cuc_timestamp) AS first', 'MAX(cuc_timestamp) AS last'
- ],
- [ $ip_conds, $time_conds ],
- __METHOD__,
- [
- 'GROUP BY' => 'cuc_ip_hex',
- 'ORDER BY' => 'cuc_ip_hex',
- 'LIMIT' => 5001,
- 'USE INDEX' => $index,
- ]
- );
- // List out each IP that has edits
- $s = '<h5>' . $this->msg( 'checkuser-too-many' )->escaped() . '</h5>';
- $s .= '<ol>';
- $counter = 0;
- foreach ( $ret as $row ) {
- if ( $counter >= 5000 ) {
- $out->addHTML( $this->msg( 'checkuser-limited' )->parseAsBlock() );
- break;
- }
- // Convert the IP hexes into normal form
- if ( strpos( $row->cuc_ip_hex, 'v6-' ) !== false ) {
- $ip = substr( $row->cuc_ip_hex, 3 );
- $ip = IP::hexToOctet( $ip );
- } else {
- $ip = long2ip( Wikimedia\base_convert( $row->cuc_ip_hex, 16, 10, 8 ) );
- }
- $s .= '<li>';
- $s .= $this->getSelfLink( $ip,
- [
- 'user' => $ip,
- 'reason' => $reason,
- 'checktype' => 'subipusers'
- ]
- );
- $s .= ' ' . $this->getTimeRangeString( $row->first, $row->last ) . ' ';
- // @todo FIXME: Hard coded brackets.
- $s .= ' [<strong>' . htmlspecialchars( $lang->formatNum( $row->count ) ) .
- "</strong>]</li>\n";
- ++$counter;
- }
- $s .= '</ol>';
-
- $out->addHTML( $s );
+ $rangecount = $this->getIPUsersCount( $ip, $xfor, $index, $period );
+ if ( $rangecount > 10000 ) {
+ $result = $this->IPUsersTooManyDB( $ip, $xfor, $index, $period );
+ $this->IPUsersTooMany( $result, $ip, $xfor );
return;
- } elseif ( isset( $rangecount ) && !$rangecount ) {
- $s = $this->noMatchesMessage( $ip, !$xfor ) . "\n";
- $out->addHTML( $s );
+ } elseif ( $rangecount === 0 ) {
+ $out->addHTML( $this->noMatchesMessage( $ip, !$xfor ) . "\n" );
return;
}
// OK, do the real query...
- $ret = $dbr->select(
+ $result = $this->doIPUsersDBRequest( $ip, $xfor, $index, $period );
+ $this->doIPUsersRequestOutput( $result, $ip, $xfor, $tag, $talkTag );
+ }
+
+ /**
+ * Get count for target edits
+ *
+ * @param string $ip
+ * @param bool $xfor
+ * @param string $index
+ * @param int $period
+ * @param int $timeLimit
+ * @return int
+ */
+ protected function getIPUsersCount( $ip, $xfor, $index, $period = 0, $timeLimit = 120 ) {
+ return $this->getIPEditsCount( $ip, $xfor, $index, $period, $timeLimit );
+ }
+
+ /**
+ * Issue a DB query for IPUsersTooMany
+ *
+ * @param string $ip
+ * @param bool $xfor
+ * @param string $index
+ * @param int $period
+ * @return IResultWrapper
+ */
+ protected function IPUsersTooManyDB( $ip, $xfor, $index, $period = 0 ) : IResultWrapper {
+ return $this->IPEditsTooManyDB( $ip, $xfor, $index, $period );
+ }
+
+ /**
+ * Return 'checkuser-too-many' error with some hints
+ *
+ * @param IResultWrapper $result
+ * @param string $ip
+ * @param bool $xfor
+ * @return void
+ */
+ protected function IPUsersTooMany( IResultWrapper $result, $ip, $xfor ) {
+ $this->IPEditsTooMany( $result, $ip, $xfor );
+ }
+
+ /**
+ * Issue a DB query for doIPUsersRequestOutput
+ *
+ * @param string $ip
+ * @param bool $xfor
+ * @param string $index
+ * @param int $period
+ * @param int $limit
+ * @return IResultWrapper
+ */
+ protected function doIPUsersDBRequest(
+ $ip, $xfor, $index, $period = 0, $limit = 10000
+ ) : IResultWrapper {
+ $dbr = wfGetDB( DB_REPLICA );
+ $conds = self::getIpConds( $dbr, $ip, $xfor );
+ if ( $conds === false ) {
+ return new FakeResultWrapper( [] );
+ }
+ $time_conds = $this->getTimeConds( $period );
+ if ( $time_conds !== false ) {
+ $conds[] = $time_conds;
+ }
+
+ return $dbr->select(
'cu_changes',
[
- 'cuc_user_text', 'cuc_timestamp', 'cuc_user', 'cuc_ip', 'cuc_agent', 'cuc_xff'
+ 'cuc_user_text', 'cuc_timestamp', 'cuc_user', 'cuc_ip', 'cuc_agent', 'cuc_xff',
],
- [ $ip_conds, $time_conds ],
+ $conds,
__METHOD__,
[
'ORDER BY' => 'cuc_timestamp DESC',
- 'LIMIT' => 10000,
+ 'LIMIT' => $limit,
'USE INDEX' => $index,
]
);
+ }
- $users_first = [];
- $users_last = [];
- $users_edits = [];
- $users_ids = [];
- $users_agentsets = [];
- $users_infosets = [];
- if ( !$dbr->numRows( $ret ) ) {
- $s = $this->noMatchesMessage( $ip, !$xfor ) . "\n";
- } else {
- foreach ( $ret as $row ) {
- if ( !array_key_exists( $row->cuc_user_text, $users_edits ) ) {
- $users_last[$row->cuc_user_text] = $row->cuc_timestamp;
- $users_edits[$row->cuc_user_text] = 0;
- $users_ids[$row->cuc_user_text] = $row->cuc_user;
- $users_infosets[$row->cuc_user_text] = [];
- $users_agentsets[$row->cuc_user_text] = [];
- }
- $users_edits[$row->cuc_user_text] += 1;
- $users_first[$row->cuc_user_text] = $row->cuc_timestamp;
- // Treat blank or NULL xffs as empty strings
- $xff = empty( $row->cuc_xff ) ? null : $row->cuc_xff;
- $xff_ip_combo = [ $row->cuc_ip, $xff ];
- // Add this IP/XFF combo for this username if it's not already there
- if ( !in_array( $xff_ip_combo, $users_infosets[$row->cuc_user_text] ) ) {
- $users_infosets[$row->cuc_user_text][] = $xff_ip_combo;
- }
- // Add this agent string if it's not already there; 10 max.
- if ( count( $users_agentsets[$row->cuc_user_text] ) < 10 ) {
- if ( !in_array( $row->cuc_agent, $users_agentsets[$row->cuc_user_text] ) ) {
- $users_agentsets[$row->cuc_user_text][] = $row->cuc_agent;
- }
+ /**
+ * @param IResultWrapper $result
+ * @return array[]
+ */
+ protected function getUserSets( IResultWrapper $result ) : array {
+ $userSets = [
+ 'first' => [],
+ 'last' => [],
+ 'edits' => [],
+ 'ids' => [],
+ 'infosets' => [],
+ 'agentsets' => []
+ ];
+
+ foreach ( $result as $row ) {
+ if ( !array_key_exists( $row->cuc_user_text, $userSets['edits'] ) ) {
+ $userSets['last'][$row->cuc_user_text] = $row->cuc_timestamp;
+ $userSets['edits'][$row->cuc_user_text] = 0;
+ $userSets['ids'][$row->cuc_user_text] = $row->cuc_user;
+ $userSets['infosets'][$row->cuc_user_text] = [];
+ $userSets['agentsets'][$row->cuc_user_text] = [];
+ }
+ $userSets['edits'][$row->cuc_user_text] += 1;
+ $userSets['first'][$row->cuc_user_text] = $row->cuc_timestamp;
+ // Treat blank or NULL xffs as empty strings
+ $xff = empty( $row->cuc_xff ) ? null : $row->cuc_xff;
+ $xff_ip_combo = [ $row->cuc_ip, $xff ];
+ // Add this IP/XFF combo for this username if it's not already there
+ if ( !in_array( $xff_ip_combo, $userSets['infosets'][$row->cuc_user_text] ) ) {
+ $userSets['infosets'][$row->cuc_user_text][] = $xff_ip_combo;
+ }
+ // Add this agent string if it's not already there; 10 max.
+ if ( count( $userSets['agentsets'][$row->cuc_user_text] ) < 10 ) {
+ if ( !in_array( $row->cuc_agent, $userSets['agentsets'][$row->cuc_user_text] ) ) {
+ $userSets['agentsets'][$row->cuc_user_text][] = $row->cuc_agent;
}
}
+ }
- $centralAuthToollink = ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' )
- ? $this->getConfig()->get( 'CheckUserCAtoollink' ) : false;
- $globalBlockingToollink = ExtensionRegistry::getInstance()->isLoaded( 'GlobalBlocking' )
- ? $this->getConfig()->get( 'CheckUserGBtoollink' ) : false;
- $linkrenderer = $this->getLinkRenderer();
- $splang = $this->getLanguage();
- $aliases = $splang->getSpecialPageAliases();
-
- // @todo FIXME: This form (and checkboxes) shouldn't be initiated for users without 'block' right
- $action = htmlspecialchars( $this->getPageTitle()->getLocalURL( 'action=block' ) );
- $s = "<form name='checkuserblock' id='checkuserblock' action=\"$action\" method='post'>";
- $s .= '<div id="checkuserresults"><ul>';
- foreach ( $users_edits as $name => $count ) {
- $s .= '<li>';
- $s .= Xml::check( 'users[]', false, [ 'value' => $name ] ) . '&#160;';
- // Load user object
- $usernfn = User::newFromName( $name, false );
- // Add user page and tool links
- if ( !IP::isIPAddress( $usernfn ) ) {
- $idforlinknfn = -1;
- } else {
- $idforlinknfn = $users_ids[$name];
- }
+ return $userSets;
+ }
+
+ /**
+ * Result output for doIPUsersRequest
+ *
+ * @param IResultWrapper $result
+ * @param string $ip
+ * @param bool $xfor
+ * @param string $tag
+ * @param string $talkTag
+ * @return void
+ */
+ protected function doIPUsersRequestOutput(
+ IResultWrapper $result, $ip, $xfor, $tag = '', $talkTag = ''
+ ) {
+ $out = $this->getOutput();
+
+ if ( !$result->numRows() ) {
+ $out->addHTML( $this->noMatchesMessage( $ip, !$xfor ) . "\n" );
+ return;
+ }
+
+ $userSets = $this->getUserSets( $result );
+ $users_first = $userSets['first'];
+ $users_last = $userSets['last'];
+ $users_edits = $userSets['edits'];
+ $users_ids = $userSets['ids'];
+ $users_agentsets = $userSets['agentsets'];
+ $users_infosets = $userSets['infosets'];
+
+ $centralAuthToollink = ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' )
+ ? $this->getConfig()->get( 'CheckUserCAtoollink' ) : false;
+ $globalBlockingToollink = ExtensionRegistry::getInstance()->isLoaded( 'GlobalBlocking' )
+ ? $this->getConfig()->get( 'CheckUserGBtoollink' ) : false;
+ $linkrenderer = $this->getLinkRenderer();
+ $splang = $this->getLanguage();
+ $aliases = $splang->getSpecialPageAliases();
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
+
+ // @todo FIXME: This form (and checkboxes) shouldn't be initiated for users without 'block' right
+ $action = htmlspecialchars( $this->getPageTitle()->getLocalURL( 'action=block' ) );
+ $s = "<form name='checkuserblock' id='checkuserblock' action=\"$action\" method='post'>";
+ $s .= '<div id="checkuserresults"><ul>';
+ foreach ( $users_edits as $name => $count ) {
+ $s .= '<li>';
+ $s .= Xml::check( 'users[]', false, [ 'value' => $name ] ) . '&#160;';
+ // Load user object
+ $usernfn = User::newFromName( $name, false );
+ // Add user page and tool links
+ if ( !IPUtils::isIPAddress( $usernfn ) ) {
+ $idforlinknfn = -1;
$user = User::newFromId( $users_ids[$name] );
- $classnouser = false;
- if ( IP::isIPAddress( $name ) !== IP::isIPAddress( $user ) ) {
- // User does not exist
- $idforlink = -1;
- $classnouser = true;
- } else {
- $idforlink = $users_ids[$name];
- }
- if ( $classnouser === true ) {
- $s .= '<span class=\'mw-checkuser-nonexistent-user\'>';
- } else {
- $s .= '<span>';
- }
- $s .= Linker::userLink( $idforlinknfn, $name, $name ) . '</span> ';
- $ip = IP::isIPAddress( $name ) ? $name : '';
- $s .= Linker::userToolLinksRedContribs(
- $idforlink, $name, $user->getEditCount() ) . ' ';
- if ( $ip ) {
- $s .= $this->msg( 'checkuser-userlinks-ip', $name )->parse();
- } elseif ( !$classnouser ) {
- if ( $this->msg( 'checkuser-userlinks' )->exists() ) {
- $s .= ' ' . $this->msg( 'checkuser-userlinks', $name )->parse();
- }
+ } else {
+ $idforlinknfn = $users_ids[$name];
+ $user = $usernfn;
+ }
+ $classnouser = false;
+ if ( IPUtils::isIPAddress( $name ) !== IPUtils::isIPAddress( $user ) ) {
+ // User does not exist
+ $idforlink = -1;
+ $classnouser = true;
+ } else {
+ $idforlink = $users_ids[$name];
+ }
+ if ( $classnouser === true ) {
+ $s .= '<span class=\'mw-checkuser-nonexistent-user\'>';
+ } else {
+ $s .= '<span>';
+ }
+ $s .= Linker::userLink( $idforlinknfn, $name, $name ) . '</span> ';
+ $ip = IPUtils::isIPAddress( $name ) ? $name : '';
+ $s .= Linker::userToolLinksRedContribs(
+ $idforlink,
+ $name,
+ $user->getEditCount(),
+ // don't render parentheses in HTML markup (CSS will provide)
+ false
+ ) . ' ';
+ if ( $ip ) {
+ $s .= $this->msg( 'checkuser-userlinks-ip', $name )->parse();
+ } elseif ( !$classnouser ) {
+ if ( $this->msg( 'checkuser-userlinks' )->exists() ) {
+ $s .= ' ' . $this->msg( 'checkuser-userlinks', $name )->parse();
}
- // Add CheckUser link
- $s .= ' ' . $this->msg( 'parentheses' )->rawParams(
- $this->getSelfLink(
- $this->msg( 'checkuser-check' )->text(),
- [
- 'user' => $name,
- 'reason' => $reason
- ]
- )
- )->escaped();
- // Add global user tools links
- // Add CentralAuth link for real registered users
- if ( $centralAuthToollink !== false
- && !IP::isIPAddress( $name )
- && !$classnouser
- ) {
- // Get CentralAuth SpecialPage name in UserLang from the first Alias name
- $spca = $aliases['CentralAuth'][0];
- $calinkAlias = str_replace( '_', ' ', $spca );
- $centralCAUrl = WikiMap::getForeignURL(
- $centralAuthToollink,
- 'Special:CentralAuth'
+ }
+ // Add CheckUser link
+ $s .= ' ' . $this->msg( 'parentheses' )->rawParams(
+ $this->getSelfLink(
+ $this->msg( 'checkuser-check' )->text(),
+ [
+ 'user' => $name,
+ 'reason' => $this->reason
+ ]
+ )
+ )->escaped();
+ // Add global user tools links
+ // Add CentralAuth link for real registered users
+ if ( $centralAuthToollink !== false
+ && !IPUtils::isIPAddress( $name )
+ && !$classnouser
+ ) {
+ // Get CentralAuth SpecialPage name in UserLang from the first Alias name
+ $spca = $aliases['CentralAuth'][0];
+ $calinkAlias = str_replace( '_', ' ', $spca );
+ $centralCAUrl = WikiMap::getForeignURL(
+ $centralAuthToollink,
+ 'Special:CentralAuth'
+ );
+ if ( $centralCAUrl === false ) {
+ throw new Exception(
+ 'Could not retrieve URL for {$centralAuthToollink}'
);
- if ( $centralCAUrl === false ) {
+ }
+ $linkCA = Html::element( 'a',
+ [
+ 'href' => $centralCAUrl . "/" . $name,
+ 'title' => $this->msg( 'centralauth' )->text(),
+ ],
+ $calinkAlias
+ );
+ $s .= ' ' . $this->msg( 'parentheses' )->rawParams( $linkCA )->escaped();
+ }
+ // Add Globalblocking link to CentralWiki
+ if ( $globalBlockingToollink !== false
+ && IPUtils::isIPAddress( $name )
+ ) {
+ // Get GlobalBlock SpecialPage name in UserLang from the first Alias name
+ $centralGBUrl = WikiMap::getForeignURL(
+ $globalBlockingToollink['centralDB'],
+ 'Special:GlobalBlock'
+ );
+ $spgb = $aliases['GlobalBlock'][0];
+ $gblinkAlias = str_replace( '_', ' ', $spgb );
+ if ( ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) ) {
+ $gbUserGroups = CentralAuthUser::getInstance( $this->getUser() )->getGlobalGroups();
+ // Link to GB via WikiMap since CA require it
+ if ( $centralGBUrl === false ) {
throw new Exception(
- 'Could not retrieve URL for {$centralAuthToollink}'
+ 'Could not retrieve URL for {$globalBlockingToollink}'
);
}
- $linkCA = Html::element( 'a',
+ $linkGB = Html::element( 'a',
[
- 'href' => $centralCAUrl . "/" . $name,
- 'title' => $this->msg( 'centralauth' )->text(),
+ 'href' => $centralGBUrl . "/" . $name,
+ 'title' => $this->msg( 'globalblocking-block-submit' )->text(),
],
- $calinkAlias
+ $gblinkAlias
);
- $s .= ' ' . $this->msg( 'parentheses', $linkCA )->escaped();
- }
- // Add Globalblocking link link to CentralWiki
- if ( $globalBlockingToollink !== false
- && IP::isIPAddress( $name )
- ) {
- // Get GlobalBlock SpecialPage name in UserLang from the first Alias name
- $centralGBUrl = WikiMap::getForeignURL(
- $globalBlockingToollink['centralDB'],
- 'Special:GlobalBlock'
+ } elseif ( $centralGBUrl !== false ) {
+ // Case wikimap configured without CentralAuth extension
+ $user = $this->getUser();
+ // Get effective Local user groups since there is a wikimap but there is no CA
+ $gbUserGroups = $user->getEffectiveGroups();
+ $linkGB = Html::element( 'a',
+ [
+ 'href' => $centralGBUrl . "/" . $name,
+ 'title' => $this->msg( 'globalblocking-block-submit' )->text(),
+ ],
+ $gblinkAlias
);
- $spgb = $aliases['GlobalBlock'][0];
- $gblinkAlias = str_replace( '_', ' ', $spgb );
- if ( ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) ) {
- $gbUserGroups = CentralAuthUser::getInstance( $this->getUser() )->getGlobalGroups();
- // Link to GB via WikiMap since CA require it
- if ( $centralGBUrl === false ) {
- throw new Exception(
- 'Could not retrieve URL for {$globalBlockingToollink}'
- );
- }
- $linkGB = Html::element( 'a',
- [
- 'href' => $centralGBUrl . "/" . $name,
- 'title' => $this->msg( 'globalblocking-block-submit' )->text(),
- ],
- $gblinkAlias
- );
- } elseif ( $centralGBUrl !== false ) {
- // Case wikimap configured whithout CentralAuth extension
- $user = $this->getUser();
- // Get effective Local user groups since there is a wikimap but there is no CA
- $gbUserGroups = $user->getEffectiveGroups();
- $linkGB = Html::element( 'a',
- [
- 'href' => $centralGBUrl . "/" . $name,
- 'title' => $this->msg( 'globalblocking-block-submit' )->text(),
- ],
- $gblinkAlias
- );
- } else {
- // Load local user group instead
- $gbUserGroups = [ '' ];
- $user = $this->getUser();
- $gbtitle = $this->getTitleFor( 'GlobalBlock' );
- $linkGB = $linkrenderer->makeKnownLink(
- $gbtitle,
- $gblinkAlias,
- [ 'title' => $this->msg( 'globalblocking-block-submit' ) ]
- );
- $gbUserCanDo = $user->isAllowed( 'globalblock' );
- if ( $gbUserCanDo === true ) {
- $globalBlockingToollink['groups'] = $gbUserGroups;
- }
- }
- // Only load the script for users in the configured global(local) group(s) or
- // for local user with globalblock permission if there is no WikiMap
- if ( count( array_intersect( $globalBlockingToollink['groups'], $gbUserGroups ) ) ) {
- $s .= ' ' . $this->msg( 'parentheses', $linkGB )->escaped();
- }
- }
- // Show edit time range
- $s .= ' ' . $this->getTimeRangeString( $users_first[$name], $users_last[$name] ) . ' ';
- // Total edit count
- // @todo FIXME: i18n issue: Hard coded brackets.
- $s .= ' [<strong>' . htmlspecialchars( $count ) . '</strong>]<br />';
- // Check if this user or IP is blocked. If so, give a link to the block log...
- $flags = $this->userBlockFlags( $ip, $users_ids[$name], $user );
- // Check how many accounts the user made recently
- if ( $ip ) {
- $key = $wgMemc->makeKey( 'acctcreate', 'ip', $ip );
- $count = intval( $wgMemc->get( $key ) );
- if ( $count ) {
- // @todo FIXME: i18n issue: Hard coded brackets.
- $flags[] = '<strong>[' .
- $this->msg( 'checkuser-accounts' )->numParams( $count )->escaped() .
- ']</strong>';
+ } else {
+ // Load local user group instead
+ $gbUserGroups = [ '' ];
+ $user = $this->getUser();
+ $gbtitle = $this->getTitleFor( 'GlobalBlock' );
+ $linkGB = $linkrenderer->makeKnownLink(
+ $gbtitle,
+ $gblinkAlias,
+ [ 'title' => $this->msg( 'globalblocking-block-submit' ) ]
+ );
+ $gbUserCanDo = $permissionManager->userHasRight( $user, 'globalblock' );
+ if ( $gbUserCanDo === true ) {
+ $globalBlockingToollink['groups'] = $gbUserGroups;
}
}
- $s .= implode( ' ', $flags );
- $s .= '<ol>';
- // List out each IP/XFF combo for this username
- for ( $i = ( count( $users_infosets[$name] ) - 1 ); $i >= 0; $i-- ) {
- $set = $users_infosets[$name][$i];
- // IP link
- $s .= '<li>';
- $s .= $this->getSelfLink( $set[0], [ 'user' => $set[0] ] );
- // XFF string, link to /xff search
- if ( $set[1] ) {
- // Flag our trusted proxies
- list( $client ) = CheckUserHooks::getClientIPfromXFF( $set[1] );
- // XFF was trusted if client came from it
- $trusted = ( $client === $row->cuc_ip );
- $c = $trusted ? '#F0FFF0' : '#FFFFCC';
- $s .= '&#160;&#160;&#160;<span style="background-color: ' . $c .
- '"><strong>XFF</strong>: ';
- $s .= $this->getSelfLink( $set[1], [ 'user' => $client . '/xff' ] ) .
- '</span>';
- }
- $s .= "</li>\n";
+ // Only load the script for users in the configured global(local) group(s) or
+ // for local user with globalblock permission if there is no WikiMap
+ if ( count( array_intersect( $globalBlockingToollink['groups'], $gbUserGroups ) ) ) {
+ $s .= ' ' . $this->msg( 'parentheses' )->rawParams( $linkGB )->escaped();
}
- $s .= '</ol><br /><ol>';
- // List out each agent for this username
- for ( $i = ( count( $users_agentsets[$name] ) - 1 ); $i >= 0; $i-- ) {
- $agent = $users_agentsets[$name][$i];
- $s .= '<li><i>' . htmlspecialchars( $agent ) . "</i></li>\n";
+ }
+ // Show edit time range
+ $s .= ' ' . $this->getTimeRangeString( $users_first[$name], $users_last[$name] ) . ' ';
+ // Total edit count
+ // @todo FIXME: i18n issue: Hard coded brackets.
+ $s .= ' [<strong>' . htmlspecialchars( $count ) . '</strong>]<br />';
+ // Check if this user or IP is blocked. If so, give a link to the block log...
+ $flags = $this->userBlockFlags( $ip, $users_ids[$name], $user );
+ $s .= implode( ' ', $flags );
+ $s .= '<ol>';
+ // List out each IP/XFF combo for this username
+ for ( $i = ( count( $users_infosets[$name] ) - 1 ); $i >= 0; $i-- ) {
+ // users_infosets[$name][$i] is array of [ $row->cuc_ip, XFF ];
+ list( $clientIP, $xffString ) = $users_infosets[$name][$i];
+ // IP link
+ $s .= '<li>';
+ $s .= $this->getSelfLink( $clientIP, [ 'user' => $clientIP ] );
+ // XFF string, link to /xff search
+ if ( $xffString ) {
+ // Flag our trusted proxies
+ list( $client ) = CheckUserHooks::getClientIPfromXFF( $xffString );
+ // XFF was trusted if client came from it
+ $trusted = ( $client === $clientIP );
+ $c = $trusted ? '#F0FFF0' : '#FFFFCC';
+ $s .= '&#160;&#160;&#160;<span style="background-color: ' . $c .
+ '"><strong>XFF</strong>: ';
+ $s .= $this->getSelfLink( $xffString, [ 'user' => $client . '/xff' ] ) .
+ '</span>';
}
- $s .= '</ol>';
- $s .= '</li>';
+ $s .= "</li>\n";
}
- $s .= "</ul></div>\n";
- if ( $this->getUser()->isAllowed( 'block' ) && !$this->getUser()->isBlocked() ) {
- // FIXME: The block <form> is currently added for users without 'block' right
- // - only the user-visible form is shown appropriately
- $s .= $this->getBlockForm( $tag, $talkTag );
- $s .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
+ $s .= '</ol><br /><ol>';
+ // List out each agent for this username
+ for ( $i = ( count( $users_agentsets[$name] ) - 1 ); $i >= 0; $i-- ) {
+ $agent = $users_agentsets[$name][$i];
+ $s .= '<li><i dir="ltr">' . htmlspecialchars( $agent ) . "</i></li>\n";
}
- $s .= "</form>\n";
+ $s .= '</ol>';
+ $s .= '</li>';
+ }
+ $s .= "</ul></div>\n";
+ if ( $permissionManager->userHasRight( $this->getUser(), 'block' )
+ && !$this->getUser()->getBlock()
+ ) {
+ // FIXME: The block <form> is currently added for users without 'block' right
+ // - only the user-visible form is shown appropriately
+ $s .= $this->getBlockForm( $tag, $talkTag );
+ $s .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
}
+ $s .= "</form>\n";
+ // @phan-suppress-next-line SecurityCheck-XSS False positive
$out->addHTML( $s );
}
@@ -1307,7 +1593,6 @@ class SpecialCheckUser extends SpecialPage {
// Only load the script for users in the configured global group(s)
if ( count( array_intersect( $checkUserCAMultiLock['groups'], $caUserGroups ) ) ) {
$out = $this->getOutput();
- $out->addModules( 'ext.checkUser.caMultiLock' );
$centralMLUrl = WikiMap::getForeignURL(
$checkUserCAMultiLock['centralDB'],
// Use canonical name instead of local name so that it works
@@ -1320,6 +1605,7 @@ class SpecialCheckUser extends SpecialPage {
);
}
$out->addJsConfigVars( 'wgCUCAMultiLockCentral', $centralMLUrl );
+ $out->addModules( 'ext.checkUser' );
}
}
@@ -1328,30 +1614,33 @@ class SpecialCheckUser extends SpecialPage {
$s .= $this->msg( 'checkuser-massblock-text' )->parseAsBlock() . "\n";
$s .= '<table><tr>' .
'<td>' . Xml::check( 'usetag', false, [ 'id' => 'usetag' ] ) . '</td>' .
- '<td>' . Xml::label( $this->msg( 'checkuser-blocktag' )->escaped(), 'usetag' ) .
+ '<td>' . Xml::label( $this->msg( 'checkuser-blocktag' )->text(), 'usetag' ) .
'</td>' .
'<td>' . Xml::input( 'tag', 46, $tag, [ 'id' => 'blocktag' ] ) . '</td>' .
'</tr><tr>' .
'<td>' . Xml::check( 'usettag', false, [ 'id' => 'usettag' ] ) . '</td>' .
- '<td>' . Xml::label( $this->msg( 'checkuser-blocktag-talk' )->escaped(), 'usettag' ) .
+ '<td>' . Xml::label( $this->msg( 'checkuser-blocktag-talk' )->text(), 'usettag' ) .
'</td>' .
'<td>' . Xml::input( 'talktag', 46, $talkTag, [ 'id' => 'talktag' ] ) . '</td>';
if ( $config->get( 'BlockAllowsUTEdit' ) ) {
$s .= '</tr><tr>' .
'<td>' . Xml::check( 'blocktalk', false, [ 'id' => 'blocktalk' ] ) . '</td>' .
- '<td>' . Xml::label( $this->msg( 'checkuser-blocktalk' )->escaped(), 'blocktalk' ) .
+ '<td>' . Xml::label( $this->msg( 'checkuser-blocktalk' )->text(), 'blocktalk' ) .
'</td>';
}
if ( SpecialBlock::canBlockEmail( $this->getUser() ) ) {
$s .= '</tr><tr>' .
'<td>' . Xml::check( 'blockemail', false, [ 'id' => 'blockemail' ] ) . '</td>' .
- '<td>' . Xml::label( $this->msg( 'checkuser-blockemail' )->escaped(), 'blockemail' )
+ '<td>' . Xml::label( $this->msg( 'checkuser-blockemail' )->text(), 'blockemail' )
. '</td>';
}
+ $s .= '<tr><td>' . Xml::check( 'reblock', false, [ 'id' => 'reblock' ] ) . '</td>';
+ $s .= '<td>' . Xml::label( $this->msg( 'checkuser-reblock' )->text(), 'reblock' )
+ . '</td></tr>';
$s .= '</tr></table>';
$s .= '<p>' . $this->msg( 'checkuser-reason' )->escaped() . '&#160;';
$s .= Xml::input( 'blockreason', 46, '', [ 'maxlength' => '150', 'id' => 'blockreason' ] );
- $s .= '&#160;' . Xml::submitButton( $this->msg( 'checkuser-massblock-commit' )->escaped(),
+ $s .= '&#160;' . Xml::submitButton( $this->msg( 'checkuser-massblock-commit' )->text(),
[ 'id' => 'checkuserblocksubmit', 'name' => 'checkuserblock' ] ) . "</p>\n";
$s .= "</fieldset>\n";
@@ -1372,7 +1661,7 @@ class SpecialCheckUser extends SpecialPage {
}
return $this->getLinkRenderer()->makeKnownLink(
$title,
- $text,
+ new HtmlArmor( '<bdi>' . htmlspecialchars( $text ) . '</bdi>' ),
[],
$params
);
@@ -1387,8 +1676,8 @@ class SpecialCheckUser extends SpecialPage {
protected function userBlockFlags( $ip, $userId, $user ) {
$flags = [];
- $block = Block::newFromTarget( $user, $ip, false );
- if ( $block instanceof Block ) {
+ $block = DatabaseBlock::newFromTarget( $user, $ip, false );
+ if ( $block instanceof DatabaseBlock ) {
// Locally blocked
$flags[] = $this->getBlockFlag( $block );
} elseif ( $ip == $user->getName() && $user->isBlockedGlobally( $ip ) ) {
@@ -1442,20 +1731,19 @@ class SpecialCheckUser extends SpecialPage {
* Get a streamlined recent changes line with IP data
*
* @param stdClass $row
- * @param string $reason
* @return string
*/
- protected function CUChangesLine( $row, $reason ) {
- static $flagCache;
+ protected function CUChangesLine( $row ) {
+ static $flagCache = [];
$line = '';
// Add date headers as needed
$date = htmlspecialchars(
- $this->getLanguage()->date( wfTimestamp( TS_MW, $row->cuc_timestamp ), true, true )
+ $this->getLanguage()->userDate( wfTimestamp( TS_MW, $row->cuc_timestamp ), $this->getUser() )
);
- if ( !isset( $this->lastdate ) ) {
+ if ( $this->lastdate === null ) {
$this->lastdate = $date;
$line .= "\n<h4>$date</h4>\n<ul class=\"special\">";
- } elseif ( $date != $this->lastdate ) {
+ } elseif ( $date !== $this->lastdate ) {
$line .= "</ul>\n<h4>$date</h4>\n<ul class=\"special\">";
$this->lastdate = $date;
}
@@ -1464,17 +1752,17 @@ class SpecialCheckUser extends SpecialPage {
$line .= $this->getLinksFromRow( $row );
// Show date
$line .= ' . . ' . htmlspecialchars(
- $this->getLanguage()->time( wfTimestamp( TS_MW, $row->cuc_timestamp ), true, true )
+ $this->getLanguage()->userTime( wfTimestamp( TS_MW, $row->cuc_timestamp ), $this->getUser() )
) . ' . . ';
// Userlinks
$user = User::newFromId( $row->cuc_user );
- if ( !IP::isIPAddress( $row->cuc_user_text ) ) {
+ if ( !IPUtils::isIPAddress( $row->cuc_user_text ) ) {
$idforlinknfn = -1;
} else {
$idforlinknfn = $row->cuc_user;
}
$classnouser = false;
- if ( IP::isIPAddress( $row->cuc_user_text ) !== IP::isIPAddress( $user ) ) {
+ if ( IPUtils::isIPAddress( $row->cuc_user_text ) !== IPUtils::isIPAddress( $user ) ) {
// User does not exist
$idforlink = -1;
$classnouser = true;
@@ -1489,13 +1777,18 @@ class SpecialCheckUser extends SpecialPage {
$line .= Linker::userLink(
$idforlinknfn, $row->cuc_user_text, $row->cuc_user_text ) . '</span>';
$line .= Linker::userToolLinksRedContribs(
- $idforlink, $row->cuc_user_text, $user->getEditCount() );
+ $idforlink,
+ $row->cuc_user_text,
+ $user->getEditCount(),
+ // don't render parentheses in HTML markup (CSS will provide)
+ false
+ );
// Get block info
if ( isset( $flagCache[$row->cuc_user_text] ) ) {
$flags = $flagCache[$row->cuc_user_text];
} else {
$user = User::newFromName( $row->cuc_user_text, false );
- $ip = IP::isIPAddress( $row->cuc_user_text ) ? $row->cuc_user_text : '';
+ $ip = IPUtils::isIPAddress( $row->cuc_user_text ) ? $row->cuc_user_text : '';
$flags = $this->userBlockFlags( $ip, $row->cuc_user, $user );
$flagCache[$row->cuc_user_text] = $flags;
}
@@ -1508,14 +1801,63 @@ class SpecialCheckUser extends SpecialPage {
$line .= ' ' . Linker::formatComment( $row->cuc_actiontext ) . ' ';
}
// Comment
- $line .= Linker::commentBlock( $row->cuc_comment );
+ if ( $row->cuc_type == RC_EDIT || $row->cuc_type == RC_NEW ) {
+ $revRecord = MediaWikiServices::getInstance()
+ ->getRevisionLookup()
+ ->getRevisionById( $row->cuc_this_oldid );
+ if ( !$revRecord ) {
+ // Assume revision is deleted
+ $dbr = wfGetDB( DB_REPLICA );
+ $queryInfo = MediaWikiServices::getInstance()
+ ->getRevisionStore()
+ ->getArchiveQueryInfo();
+ $tmp = $dbr->selectRow(
+ $queryInfo['tables'],
+ $queryInfo['fields'],
+ [ 'ar_rev_id' => $row->cuc_this_oldid ],
+ __METHOD__,
+ [],
+ $queryInfo['joins']
+ );
+ if ( $tmp ) {
+ $revRecord = MediaWikiServices::getInstance()
+ ->getRevisionFactory()
+ ->newRevisionFromArchiveRow( $tmp );
+ }
+
+ if ( !$revRecord ) {
+ // This shouldn't happen, CheckUser points to a revision
+ // that isn't in revision nor archive table?
+ throw new Exception(
+ "Couldn't fetch revision cu_changes table links to (cuc_this_oldid {$row->cuc_this_oldid})"
+ );
+ }
+ }
+ if ( RevisionRecord::userCanBitfield(
+ $revRecord->getVisibility(),
+ RevisionRecord::DELETED_COMMENT,
+ $this->getUser()
+ ) ) {
+ $line .= Linker::commentBlock( $row->cuc_comment );
+ } else {
+ $line .= Linker::commentBlock(
+ $this->msg( 'rev-deleted-comment' )->text(),
+ null,
+ false,
+ null,
+ false
+ );
+ }
+ } else {
+ $line .= Linker::commentBlock( $row->cuc_comment );
+ }
$line .= '<br />&#160; &#160; &#160; &#160; <small>';
// IP
$line .= ' <strong>IP</strong>: ';
$line .= $this->getSelfLink( $row->cuc_ip,
[
'user' => $row->cuc_ip,
- 'reason' => $reason
+ 'reason' => $this->reason
]
);
// XFF
@@ -1530,7 +1872,7 @@ class SpecialCheckUser extends SpecialPage {
$line .= $this->getSelfLink( $row->cuc_xff,
[
'user' => $client . '/xff',
- 'reason' => $reason
+ 'reason' => $this->reason
]
);
$line .= '</span>';
@@ -1559,7 +1901,7 @@ class SpecialCheckUser extends SpecialPage {
$s .= ' -- ';
$s .= $this->getFormattedTimestamp( $last );
}
- return $this->msg( 'parentheses' )->rawParams( $s )->escaped();
+ return $this->msg( 'parentheses' )->params( $s )->escaped();
}
/**
@@ -1570,8 +1912,8 @@ class SpecialCheckUser extends SpecialPage {
* @return string
*/
protected function getFormattedTimestamp( $timestamp ) {
- return $this->getLanguage()->timeanddate(
- wfTimestamp( TS_MW, $timestamp ), true
+ return $this->getLanguage()->userTimeAndDate(
+ wfTimestamp( TS_MW, $timestamp ), $this->getUser()
);
}
@@ -1617,7 +1959,7 @@ class SpecialCheckUser extends SpecialPage {
new HtmlArmor( $this->message['hist'] ),
[],
[
- 'curid' => $row->cuc_page_id,
+ 'curid' => $title->exists() ? $row->cuc_page_id : null,
'action' => 'history'
]
) . ') . . ';
@@ -1635,6 +1977,7 @@ class SpecialCheckUser extends SpecialPage {
}
Hooks::run( 'SpecialCheckUserGetLinksFromRow', [ $this, $row, &$links ] );
+ // @phan-suppress-next-line PhanRedundantCondition May set by hook
if ( is_array( $links ) ) {
return implode( ' ', $links );
} else {
@@ -1656,7 +1999,8 @@ class SpecialCheckUser extends SpecialPage {
'log_title' => $userpage->getDBkey()
],
__METHOD__,
- [ 'USE INDEX' => 'page_time' ] );
+ [ 'USE INDEX' => 'page_time' ]
+ );
}
/**
@@ -1677,32 +2021,49 @@ class SpecialCheckUser extends SpecialPage {
}
/**
+ * @param string $target an IP address or CIDR range
+ * @return bool
+ */
+ public static function isValidRange( $target ) {
+ $CIDRLimit = \RequestContext::getMain()->getConfig()->get( 'CheckUserCIDRLimit' );
+ if ( IPUtils::isValidRange( $target ) ) {
+ list( $ip, $range ) = explode( '/', $target, 2 );
+ if ( ( IPUtils::isIPv4( $ip ) && $range < $CIDRLimit['IPv4'] ) ||
+ ( IPUtils::isIPv6( $ip ) && $range < $CIDRLimit['IPv6'] ) ) {
+ return false; // range is too wide
+ }
+ return true;
+ }
+
+ return IPUtils::isValid( $target );
+ }
+
+ /**
* @param IDatabase $db
* @param string $target an IP address or CIDR range
* @param string|bool $xfor
* @return array|false array for valid conditions, false if invalid
*/
public static function getIpConds( IDatabase $db, $target, $xfor = false ) {
- global $wgCheckUserCIDRLimit;
$type = $xfor ? 'xff' : 'ip';
- if ( IP::isValidRange( $target ) ) {
- list( $ip, $range ) = explode( '/', $target, 2 );
- list( $start, $end ) = IP::parseRange( $target );
- if ( ( IP::isIPv4( $ip ) && $range < $wgCheckUserCIDRLimit['IPv4'] ) ||
- ( IP::isIPv6( $ip ) && $range < $wgCheckUserCIDRLimit['IPv6'] ) ) {
- return false; // range is too wide
- }
+
+ if ( !self::isValidRange( $target ) ) {
+ return false;
+ }
+
+ if ( IPUtils::isValidRange( $target ) ) {
+ list( $start, $end ) = IPUtils::parseRange( $target );
return [ 'cuc_' . $type . '_hex BETWEEN ' . $db->addQuotes( $start ) .
' AND ' . $db->addQuotes( $end ) ];
- } elseif ( IP::isValid( $target ) ) {
- return [ "cuc_{$type}_hex" => IP::toHex( $target ) ];
+ } elseif ( IPUtils::isValid( $target ) ) {
+ return [ "cuc_{$type}_hex" => IPUtils::toHex( $target ) ];
}
return false; // invalid IP
}
protected function getTimeConds( $period ) {
if ( !$period ) {
- return '1 = 1';
+ return false;
}
$dbr = wfGetDB( DB_REPLICA );
$cutoff_unixtime = time() - ( $period * 24 * 3600 );
@@ -1715,7 +2076,7 @@ class SpecialCheckUser extends SpecialPage {
$user = RequestContext::getMain()->getUser();
if ( $targetType == 'ip' ) {
- list( $rangeStart, $rangeEnd ) = IP::parseRange( $target );
+ list( $rangeStart, $rangeEnd ) = IPUtils::parseRange( $target );
$targetHex = $rangeStart;
if ( $rangeStart == $rangeEnd ) {
$rangeStart = $rangeEnd = '';
diff --git a/CheckUser/includes/specials/SpecialCheckUserLog.php b/CheckUser/includes/specials/SpecialCheckUserLog.php
index 81be07f5..e8ccf646 100644
--- a/CheckUser/includes/specials/SpecialCheckUserLog.php
+++ b/CheckUser/includes/specials/SpecialCheckUserLog.php
@@ -1,24 +1,40 @@
<?php
+use MediaWiki\Cache\LinkBatchFactory;
+use MediaWiki\MediaWikiServices;
+use Wikimedia\IPUtils;
+
class SpecialCheckUserLog extends SpecialPage {
/**
- * @var string $target
+ * @var string
*/
protected $target;
- public function __construct() {
+ /** @var LinkBatchFactory */
+ private $linkBatchFactory;
+
+ public function __construct( LinkBatchFactory $linkBatchFactory ) {
parent::__construct( 'CheckUserLog', 'checkuser-log' );
+ $this->linkBatchFactory = $linkBatchFactory;
}
public function execute( $par ) {
$this->setHeaders();
+ $this->addHelpLink( 'Extension:CheckUser' );
$this->checkPermissions();
+ // Blocked users are not allowed to run checkuser queries (bug T157883)
+ $block = $this->getUser()->getBlock();
+ if ( $block && $block->isSitewide() ) {
+ throw new UserBlockedError( $block );
+ }
+
$out = $this->getOutput();
$request = $this->getRequest();
$this->target = trim( $request->getVal( 'cuSearch', $par ) );
+ $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
- if ( $this->getUser()->isAllowed( 'checkuser' ) ) {
+ if ( $permissionManager->userHasRight( $this->getUser(), 'checkuser' ) ) {
$subtitleLink = $this->getLinkRenderer()->makeKnownLink(
SpecialPage::getTitleFor( 'CheckUser' ),
$this->msg( 'checkuser-showmain' )->text()
@@ -57,7 +73,8 @@ class SpecialCheckUserLog extends SpecialPage {
'queryConds' => $searchConds,
'year' => $request->getInt( 'year' ),
'month' => $request->getInt( 'month' ),
- ]
+ ],
+ $this->linkBatchFactory
);
$out->addHTML(
@@ -130,7 +147,7 @@ class SpecialCheckUserLog extends SpecialPage {
* @return array|null array if valid target, null if invalid target given
*/
protected function getTargetSearchConds() {
- list( $start, $end ) = IP::parseRange( $this->target );
+ list( $start, $end ) = IPUtils::parseRange( $this->target );
$conds = null;
if ( $start !== false ) {
diff --git a/CheckUser/maintenance/importCheckUserLogs.php b/CheckUser/maintenance/importCheckUserLogs.php
index 1c821abf..e15429bb 100644
--- a/CheckUser/maintenance/importCheckUserLogs.php
+++ b/CheckUser/maintenance/importCheckUserLogs.php
@@ -1,5 +1,7 @@
<?php
+use Wikimedia\IPUtils;
+
$IP = getenv( 'MW_INSTALL_PATH' );
if ( $IP === false ) {
$IP = __DIR__ . '/../../..';
@@ -65,12 +67,12 @@ class ImportCheckUserLogs extends Maintenance {
];
foreach ( $regexes as $type => $regex ) {
- $m = false;
+ $m = [];
if ( preg_match( $regex, $line, $m ) ) {
$data = [
'timestamp' => strtotime( $m['timestamp'] ),
'user' => $m['user'],
- 'reason' => isset( $m['reason'] ) ? $m['reason'] : '',
+ 'reason' => $m['reason'] ?? '',
'type' => $type,
'wiki' => $m['wiki'],
'target' => $m['target'] ];
@@ -99,7 +101,7 @@ class ImportCheckUserLogs extends Maintenance {
// Local wiki lookups...
$user = User::newFromName( $data['user'] );
- list( $start, $end ) = IP::parseRange( $data['target'] );
+ list( $start, $end ) = IPUtils::parseRange( $data['target'] );
if ( $start === false ) {
$targetUser = User::newFromName( $data['target'] );
$targetID = $targetUser ? $targetUser->getId() : 0;
@@ -131,7 +133,7 @@ class ImportCheckUserLogs extends Maintenance {
$matched++;
}
- $unmatched ++;
+ $unmatched++;
}
$this->output(
@@ -163,5 +165,5 @@ class ImportCheckUserLogs extends Maintenance {
}
}
-$maintClass = 'ImportCheckUserLogs';
+$maintClass = ImportCheckUserLogs::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/CheckUser/maintenance/populateCheckUserTable.php b/CheckUser/maintenance/populateCheckUserTable.php
index 613e4b3f..d0f81713 100644
--- a/CheckUser/maintenance/populateCheckUserTable.php
+++ b/CheckUser/maintenance/populateCheckUserTable.php
@@ -1,5 +1,8 @@
<?php
+use MediaWiki\MediaWikiServices;
+use Wikimedia\IPUtils;
+
$IP = getenv( 'MW_INSTALL_PATH' );
if ( $IP === false ) {
$IP = __DIR__ . '/../../..';
@@ -30,7 +33,7 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance {
$db = $this->getDB( DB_MASTER );
// Check if the table is empty
- $rcRows = $db->selectField( 'recentchanges', 'COUNT(*)', false, __METHOD__ );
+ $rcRows = $db->selectField( 'recentchanges', 'COUNT(*)', [], __METHOD__ );
if ( !$rcRows ) {
$this->output( "recentchanges is empty; nothing to add.\n" );
return true;
@@ -51,8 +54,8 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance {
$cutoffCond = "";
}
- $start = (int)$db->selectField( 'recentchanges', 'MIN(rc_id)', false, __METHOD__ );
- $end = (int)$db->selectField( 'recentchanges', 'MAX(rc_id)', false, __METHOD__ );
+ $start = (int)$db->selectField( 'recentchanges', 'MIN(rc_id)', [], __METHOD__ );
+ $end = (int)$db->selectField( 'recentchanges', 'MAX(rc_id)', [], __METHOD__ );
// Do remaining chunk
$end += $this->mBatchSize - 1;
$blockStart = $start;
@@ -62,6 +65,8 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance {
"Starting poulation of cu_changes with recentchanges rc_id from $start to $end\n"
);
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+
$commentStore = CommentStore::getStore();
$rcQuery = RecentChange::getQueryInfo();
@@ -80,7 +85,7 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance {
foreach ( $res as $row ) {
$batch[] = [
'cuc_timestamp' => $row->rc_timestamp,
- 'cuc_user' => $row->rc_user,
+ 'cuc_user' => $row->rc_user ?? 0,
'cuc_user_text' => $row->rc_user_text,
'cuc_namespace' => $row->rc_namespace,
'cuc_title' => $row->rc_title,
@@ -91,7 +96,7 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance {
'cuc_last_oldid' => $row->rc_last_oldid,
'cuc_type' => $row->rc_type,
'cuc_ip' => $row->rc_ip,
- 'cuc_ip_hex' => IP::toHex( $row->rc_ip ),
+ 'cuc_ip_hex' => IPUtils::toHex( $row->rc_ip ),
];
}
if ( count( $batch ) ) {
@@ -99,7 +104,7 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance {
}
$blockStart += $this->mBatchSize - 1;
$blockEnd += $this->mBatchSize - 1;
- wfWaitForSlaves( 5 );
+ $lbFactory->waitForReplication( [ 'ifWritesSince' => 5 ] );
}
$this->output( "...cu_changes table has been populated.\n" );
@@ -107,5 +112,5 @@ class PopulateCheckUserTable extends LoggedUpdateMaintenance {
}
}
-$maintClass = 'PopulateCheckUserTable';
+$maintClass = PopulateCheckUserTable::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/CheckUser/maintenance/purgeOldData.php b/CheckUser/maintenance/purgeOldData.php
index 33a0a9d2..7046ac9e 100644
--- a/CheckUser/maintenance/purgeOldData.php
+++ b/CheckUser/maintenance/purgeOldData.php
@@ -1,4 +1,7 @@
<?php
+
+use MediaWiki\MediaWikiServices;
+
if ( getenv( 'MW_INSTALL_PATH' ) ) {
$IP = getenv( 'MW_INSTALL_PATH' );
} else {
@@ -9,7 +12,7 @@ require_once "$IP/maintenance/Maintenance.php";
class PurgeOldData extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Purge expired rows in CheckUser and RecentChanges";
+ $this->addDescription( 'Purge expired rows in CheckUser and RecentChanges' );
$this->setBatchSize( 200 );
$this->requireExtension( 'CheckUser' );
@@ -34,6 +37,8 @@ class PurgeOldData extends Maintenance {
protected function prune( $table, $ts_column, $maxAge ) {
$dbw = wfGetDB( DB_MASTER );
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+
$expiredCond = "$ts_column < " . $dbw->addQuotes( $dbw->timestamp( time() - $maxAge ) );
$count = 0;
@@ -60,12 +65,12 @@ class PurgeOldData extends Maintenance {
$count += $dbw->affectedRows();
$this->commitTransaction( $dbw, __METHOD__ );
- wfWaitForSlaves();
+ $lbFactory->waitForReplication();
}
return $count;
}
}
-$maintClass = "PurgeOldData";
+$maintClass = PurgeOldData::class;
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/CheckUser/modules/ext.checkUser.investigate.styles/investigate.less b/CheckUser/modules/ext.checkUser.investigate.styles/investigate.less
new file mode 100644
index 00000000..af8429e6
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser.investigate.styles/investigate.less
@@ -0,0 +1,234 @@
+@import 'mediawiki.ui/variables.less';
+@import 'mediawiki.mixins.less';
+
+// OOUIHTMLForm specifics
+@ooui-font-size-browser: 16; // Assumed browser default of `16px`.
+@ooui-font-size-base: 0.875em; // Equals `14px` at browser default of `16px`.
+@font-size-small: 13 / @ooui-font-size-browser / @ooui-font-size-base;
+@transition-base: 100ms;
+
+.mw-datatable {
+ &.ext-checkuser-investigate-table td {
+ vertical-align: top;
+ }
+
+ &.ext-checkuser-investigate-table tr:hover td {
+ background-color: @background-color-base;
+ }
+
+ &.ext-checkuser-investigate-table th {
+ background-color: @colorGray14;
+ border-bottom-width: 2px;
+ }
+
+ .ext-checkuser-compare-table-cell-target {
+ width: 200px;
+
+ a,
+ .ext-checkuser-compare-table-cell-ip {
+ font-weight: bold;
+ }
+ }
+
+ .ext-checkuser-compare-table-cell-target,
+ tr:hover,
+ tr:focus-within {
+ td.ext-checkuser-compare-table-cell-target {
+ background: @colorGray14;
+ }
+ }
+
+ .ext-checkuser-investigate-table-cell-interactive {
+ // Leave horizontal space for buttons before they are appended
+ padding-right: 4.5em;
+
+ .ext-checkuser-investigate-table-select {
+ visibility: hidden;
+ }
+
+ &:hover,
+ &:focus,
+ &:focus-within {
+ .ext-checkuser-investigate-table-select {
+ visibility: visible;
+ }
+ }
+ }
+
+ .ext-checkuser-compare-table-cell-user-agent {
+ border-right-width: 0;
+ font-size: @font-size-small;
+ }
+
+ .ext-checkuser-compare-table-cell-activity {
+ border-left-width: 0;
+ text-align: right;
+ }
+}
+
+// Leave vertical space for buttons before they are appended
+.ext-checkuser-investigate-table-cell-interactive:before {
+ content: '';
+ float: right;
+ width: 0;
+
+ .ext-checkuser-investigate-table-preliminary-check & {
+ min-height: 2.5em;
+ }
+
+ .ext-checkuser-investigate-table-compare & {
+ min-height: 5em;
+ }
+}
+
+.ext-checkuser-investigate-table-options-container {
+ float: right;
+ width: 3em;
+ margin-right: -4em;
+ text-align: center;
+
+ .oo-ui-menuSelectWidget {
+ text-align: left;
+ }
+}
+
+.ext-checkuser-investigate-table-select.oo-ui-buttonElement.oo-ui-iconElement:first-child {
+ margin-left: 5px;
+}
+
+.ext-checkuser-investigate-table-button-pin.oo-ui-buttonElement,
+.ext-checkuser-investigate-table-select.oo-ui-buttonElement {
+ visibility: hidden;
+}
+
+.ext-checkuser-investigate-table.mw-datatable.ext-checkuser-investigate-table-pinned {
+ .ext-checkuser-investigate-table-row-pinned td,
+ .ext-checkuser-investigate-table-row-pinned-data-match td {
+ .transition( background-color @transition-base );
+ background-color: #fef6e7;
+
+ &.ext-checkuser-investigate-table-cell-pinned,
+ &.ext-checkuser-investigate-table-cell-pinned-data-match {
+ .transition( background-color @transition-base );
+ background-color: #fc3;
+ }
+
+ &:hover,
+ &:focus,
+ &:focus-within {
+ .ext-checkuser-investigate-table-select {
+ visibility: visible;
+ }
+
+ &.ext-checkuser-investigate-table-cell-pinned {
+ .ext-checkuser-investigate-table-button-pin {
+ visibility: visible;
+ }
+ }
+ }
+ }
+}
+
+/* stylelint-disable no-descending-specificity */
+.ext-checkuser-investigate-table.mw-datatable:not( .ext-checkuser-investigate-table-pinned ) {
+ tr {
+ td.ext-checkuser-investigate-active,
+ td:hover,
+ td:focus,
+ td:focus-within {
+ .ext-checkuser-investigate-table-select,
+ .ext-checkuser-investigate-table-button-pin {
+ visibility: visible;
+ }
+ }
+
+ td.ext-checkuser-investigate-table-cell-hover-data-match,
+ td:hover.ext-checkuser-investigate-table-cell-pinnable,
+ td:focus.ext-checkuser-investigate-table-cell-pinnable,
+ td:focus-within.ext-checkuser-investigate-table-cell-pinnable {
+ background-color: #fc3;
+ }
+ }
+
+ .ext-checkuser-investigate-table-row-hover-data-match,
+ tr:hover,
+ tr:focus-within {
+ td {
+ background-color: #fef6e7;
+ }
+ }
+}
+/* stylelint-enable no-descending-specificity */
+
+.ext-checkuser-investigate-copy-message {
+ max-width: none;
+
+ &.oo-ui-messageWidget.oo-ui-messageWidget-block.oo-ui-flaggedElement-notice {
+ background-color: #eaf3ff;
+ border-color: #36c;
+ }
+
+ .mw-widget-copyTextLayout.oo-ui-actionFieldLayout.oo-ui-fieldLayout-align-top,
+ .mw-widget-copyTextLayout > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+ .oo-ui-textInputWidget {
+ max-width: none;
+ }
+
+ &.oo-ui-messageWidget .oo-ui-labelElement-label {
+ display: inline-block;
+ }
+
+ .oo-ui-buttonWidget {
+ float: right;
+ margin-right: 0;
+ margin-top: -5px;
+ }
+}
+
+.mw-special-Investigate {
+ .ext-checkuser-investigate-indicators.oo-ui-buttonGroupWidget {
+ top: -2px;
+ margin-right: 4px;
+ }
+
+ .ext-checkuser-investigate-subtitle-fieldset {
+ background-color: #eaf3ff;
+ padding: 10px;
+
+ .oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-header,
+ .oo-ui-tagMultiselectWidget {
+ max-width: none;
+ }
+ }
+
+ .ext-checkuser-investigate-subtitle-block-button,
+ .ext-checkuser-investigate-subtitle-continue-button,
+ .ext-checkuser-investigate-subtitle-cancel-button, {
+ float: right;
+ margin-left: 10px;
+ }
+
+ // Apply the text colors to the links.
+ .oo-ui-tabOptionWidget a {
+ color: inherit;
+
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ }
+ }
+
+ // Seperate the tabs from the table
+ .oo-ui-menuLayout-menu {
+ margin-bottom: 1em;
+ }
+
+ .oo-ui-messageWidget {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ }
+
+ .guider_overlay { /* stylelint-disable-line selector-class-pattern */
+ opacity: 0.2;
+ }
+}
diff --git a/CheckUser/modules/ext.checkUser.investigate/blockform.js b/CheckUser/modules/ext.checkUser.investigate/blockform.js
new file mode 100644
index 00000000..76783576
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser.investigate/blockform.js
@@ -0,0 +1,74 @@
+module.exports = function addBlockForm() {
+ // Attributes used for pinnable highlighting
+ var blockButton = OO.ui.infuse( $( '.ext-checkuser-investigate-subtitle-block-button' ) ),
+ $placeholderWidget = $( '.ext-checkuser-investigate-subtitle-placeholder-widget' ),
+ targets = mw.config.get( 'wgCheckUserInvestigateTargets' ),
+ excludeTargets = mw.config.get( 'wgCheckUserInvestigateExcludeTargets' ),
+ targetsWidget = new OO.ui.MenuTagMultiselectWidget( {
+ options: excludeTargets.map( function ( target ) {
+ return {
+ data: target,
+ label: target
+ };
+ } ),
+ selected: targets.filter( function ( target ) {
+ return excludeTargets.indexOf( target ) === -1;
+ } )
+ } ),
+ continueButton = new OO.ui.ButtonWidget( {
+ label: mw.msg( 'checkuser-investigate-subtitle-continue-button-label' ),
+ flags: [ 'primary', 'progressive' ],
+ classes: [
+ 'ext-checkuser-investigate-subtitle-continue-button'
+ ]
+ } ),
+ cancelButton = new OO.ui.ButtonWidget( {
+ label: mw.msg( 'checkuser-investigate-subtitle-cancel-button-label' ),
+ flags: [ 'progressive' ],
+ framed: false,
+ classes: [
+ 'ext-checkuser-investigate-subtitle-cancel-button'
+ ]
+ } );
+
+ function toggleBlockFromButtons( showBlockForm ) {
+ blockButton.toggle( !showBlockForm );
+ continueButton.toggle( showBlockForm );
+ cancelButton.toggle( showBlockForm );
+ targetsWidget.toggle( showBlockForm );
+ }
+
+ $placeholderWidget.replaceWith( targetsWidget.$element );
+ blockButton.$element.parent().prepend(
+ continueButton.$element,
+ cancelButton.$element
+ );
+
+ toggleBlockFromButtons( false );
+ blockButton.on( 'click', toggleBlockFromButtons.bind( null, true ) );
+ cancelButton.on( 'click', toggleBlockFromButtons.bind( null, false ) );
+
+ continueButton.on( 'click', function () {
+ var $form, params, key;
+
+ $form = $( '<form>' ).attr( {
+ action: new mw.Title( 'Special:InvestigateBlock' ).getUrl(),
+ method: 'post',
+ target: '_blank'
+ } ).addClass( 'oo-ui-element-hidden' );
+
+ params = {
+ wpTargets: targetsWidget.getValue().join( '\n' ),
+ allowedTargets: targets
+ };
+ for ( key in params ) {
+ $form.append( $( '<input>' ).attr( {
+ type: 'hidden',
+ name: key,
+ value: params[ key ]
+ } ) );
+ }
+
+ $form.appendTo( 'body' ).trigger( 'submit' );
+ } );
+};
diff --git a/CheckUser/modules/ext.checkUser.investigate/copy.js b/CheckUser/modules/ext.checkUser.investigate/copy.js
new file mode 100644
index 00000000..647bd0a7
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser.investigate/copy.js
@@ -0,0 +1,83 @@
+/**
+ * Feature for copying wikitext version of the Compare results table (T251361).
+ * This feature is available for wikis that have Parsoid/RESTBase.
+ */
+module.exports = function addCopyFeature() {
+ var copyTextLayout, messageWidget, wikitextButton;
+
+ function onWikitextButtonClick() {
+ var url, html;
+
+ function getSanitizedHtml( $table ) {
+ $table = $table.clone();
+
+ $table.find( '.oo-ui-widget, .ext-checkuser-investigate-table-options-container' ).remove();
+ $table.find( '.mw-userlink' )
+ .attr( 'rel', 'mw:WikiLink' )
+ .attr( 'href', function () {
+ return new mw.Uri( $( this ).attr( 'href' ) ).toString();
+ } );
+
+ $table.find( '[class]' ).addBack( '[class]' ).removeAttr( 'class' );
+ $table.addClass( 'mw-datatable' );
+
+ $table.find( 'tr, td' ).each( function ( i, element ) {
+ Object.keys( element.dataset ).forEach( function ( key ) {
+ element.removeAttribute( 'data-' + key );
+ } );
+ } );
+
+ return $table[ 0 ].outerHTML;
+ }
+
+ wikitextButton.setDisabled( true );
+ copyTextLayout.textInput.pushPending();
+ copyTextLayout.toggle( true );
+
+ url = mw.config.get( 'wgVisualEditorConfig' ).fullRestbaseUrl + 'v1/transform/html/to/wikitext/';
+ html = getSanitizedHtml( $( '.ext-checkuser-investigate-table-compare' ) );
+
+ $.ajax( url, { data: { html: html }, type: 'POST' } ).then( function ( data ) {
+ copyTextLayout.textInput.popPending();
+ copyTextLayout.textInput.setValue( data );
+ } );
+ }
+
+ messageWidget = new OO.ui.MessageWidget( {
+ type: 'notice',
+ label: mw.msg( 'checkuser-investigate-compare-copy-message-label' ),
+ classes: [ 'ext-checkuser-investigate-copy-message' ]
+ } );
+ messageWidget.setIcon( 'table' );
+
+ wikitextButton = new OO.ui.ButtonWidget( {
+ label: mw.msg( 'checkuser-investigate-compare-copy-button-label' ),
+ classes: [
+ 'ext-checkuser-investigate-copy-button'
+ ],
+ flags: [ 'primary', 'progressive' ]
+ } );
+ wikitextButton.on( 'click', onWikitextButtonClick );
+
+ copyTextLayout = new mw.widgets.CopyTextLayout( {
+ multiline: true,
+ align: 'top',
+ textInput: {
+ autosize: true,
+ // The following classes are used here:
+ // * mw-editfont-monospace
+ // * mw-editfont-sans-serif
+ // * mw-editfont-serif
+ classes: [ 'mw-editfont-' + mw.user.options.get( 'editfont' ) ]
+ }
+ } );
+ copyTextLayout.toggle( false );
+
+ $( '.ext-checkuser-investigate-tabs-indexLayout .oo-ui-indexLayout-stackLayout' )
+ .append(
+ messageWidget.$element.append(
+ wikitextButton.$element,
+ copyTextLayout.$element
+ )
+ );
+};
diff --git a/CheckUser/modules/ext.checkUser.investigate/init.js b/CheckUser/modules/ext.checkUser.investigate/init.js
new file mode 100644
index 00000000..d92c3440
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser.investigate/init.js
@@ -0,0 +1,20 @@
+( function () {
+ var addBlockForm = require( './blockform.js' ),
+ setupTables = require( './tables.js' ),
+ addCopyFeature = require( './copy.js' );
+
+ if ( $( '.ext-checkuser-investigate-subtitle-block-button' ).length > 0 ) {
+ addBlockForm();
+ }
+
+ setupTables();
+
+ if (
+ $( '.ext-checkuser-investigate-table-compare' ).length > 0 &&
+ mw.config.get( 'wgVisualEditorConfig' ) &&
+ mw.config.get( 'wgVisualEditorConfig' ).fullRestbaseUrl
+ ) {
+ addCopyFeature();
+ }
+
+}() );
diff --git a/CheckUser/modules/ext.checkUser.investigate/tables.js b/CheckUser/modules/ext.checkUser.investigate/tables.js
new file mode 100644
index 00000000..6f7fa464
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser.investigate/tables.js
@@ -0,0 +1,283 @@
+/**
+ * Add highlight pinning capability and tool links to tables.
+ */
+module.exports = function setupTables() {
+ // Attributes used for pinnable highlighting
+ var highlightData = mw.storage.session.get( 'checkuser-investigate-highlight' ),
+ toggleButtons = {};
+
+ // The message 'checkuser-toollinks' was parsed in PHP, since translations
+ // may contain wikitext that is too complex for the JS parser:
+ // https://www.mediawiki.org/wiki/Manual:Messages_API#Feature_support_in_JavaScript
+ mw.messages.set( require( './message.json' ) );
+
+ function logEvent( data ) {
+ mw.track( 'event.SpecialInvestigate', data );
+ }
+
+ function getDataKey( $element ) {
+ return JSON.stringify( [
+ $element.data( 'field' ),
+ $element.data( 'value' )
+ ] );
+ }
+
+ function updateMatchingElements( $target, value, classSuffix ) {
+ var $matches,
+ dataField = $target.data( 'field' ),
+ dataValue = $target.data( 'value' ),
+ cellClass = 'ext-checkuser-investigate-table-cell-' + classSuffix,
+ rowClass = 'ext-checkuser-investigate-table-row-' + classSuffix;
+
+ $matches = $( 'td[data-field="' + dataField + '"][data-value="' + dataValue + '"]' );
+ // The following messages can be passed here:
+ // * ext-checkuser-investigate-table-cell-hover-data-match
+ // * ext-checkuser-investigate-table-cell-pinned-data-match
+ $matches.toggleClass( cellClass, value );
+
+ // Rows should be highlighted iff they contain highlighted cells
+ $matches.closest( 'tr' ).each( function () {
+ // The following messages can be passed here:
+ // * ext-checkuser-investigate-table-row-hover-data-match
+ // * ext-checkuser-investigate-table-row-pinned-data-match
+ $( this ).toggleClass(
+ rowClass,
+ value
+ );
+ } );
+ }
+
+ function onPinnableCellHover( event ) {
+ // Toggle on for mouseover, off for mouseout
+ updateMatchingElements( $( this ), event.type === 'mouseover' || event.type === 'focusin', 'hover-data-match' );
+ }
+
+ function onToggleButtonChange( $tableCell, value ) {
+ $( '.ext-checkuser-investigate-table' ).toggleClass( 'ext-checkuser-investigate-table-pinned', value );
+ $tableCell.toggleClass( 'ext-checkuser-investigate-table-cell-pinned', value );
+
+ toggleButtons[ getDataKey( $tableCell ) ].forEach( function ( button ) {
+ button.setValue( value );
+ button.setFlags( { progressive: value } );
+ } );
+ updateMatchingElements( $tableCell, value, 'pinned-data-match' );
+
+ if ( value ) {
+ mw.storage.session.set( 'checkuser-investigate-highlight', getDataKey( $tableCell ) );
+ } else {
+ mw.storage.session.remove( 'checkuser-investigate-highlight' );
+ }
+ }
+
+ function filterValue( $tableCell ) {
+ $( 'textarea[name=exclude-targets]' ).val( function () {
+ return this.value + '\n' + $tableCell.data( 'value' );
+ } );
+ $( '.mw-htmlform' ).trigger( 'submit' );
+ }
+
+ function addTargets( $tableCell ) {
+ $( 'input[name=targets]' ).val( $tableCell.data( 'value' ) );
+ $( '.mw-htmlform' ).trigger( 'submit' );
+ }
+
+ function appendButtons( $tableCell, buttonTypes ) {
+ // eslint-disable-next-line no-jquery/no-class-state
+ var isTarget = $tableCell.hasClass( 'ext-checkuser-compare-table-cell-target' ),
+ $optionsContainer = $( '<div>' ).addClass( 'ext-checkuser-investigate-table-options-container' ),
+ key = getDataKey( $tableCell ),
+ options = [],
+ selectWidget,
+ toggleButton,
+ message,
+ $links;
+
+ $tableCell.prepend( $optionsContainer );
+
+ if ( buttonTypes.filter ) {
+ options.push( new OO.ui.MenuOptionWidget( {
+ icon: 'funnel',
+ classes: [
+ 'ext-checkuser-investigate-button-filter-ip'
+ ],
+ label: mw.msg( 'checkuser-investigate-compare-table-button-filter-label' ),
+ data: { type: 'filter' }
+ } ) );
+ }
+
+ if ( buttonTypes.addUsers ) {
+ options.push( new OO.ui.MenuOptionWidget( {
+ disabled: isTarget,
+ icon: 'add',
+ classes: [
+ 'ext-checkuser-investigate-button-add-user-targets'
+ ],
+ label: $tableCell.data( 'edits' ) === $tableCell.data( 'all-edits' ) ?
+ mw.msg( 'checkuser-investigate-compare-table-button-add-user-targets-log-label' ) :
+ mw.msg( 'checkuser-investigate-compare-table-button-add-user-targets-label' ),
+ data: { type: 'addUsers' }
+ } ) );
+ }
+
+ if ( buttonTypes.addIps ) {
+ options.push( new OO.ui.MenuOptionWidget( {
+ disabled: isTarget,
+ icon: 'add',
+ label: mw.msg( 'checkuser-investigate-compare-table-button-add-ip-targets-label' ),
+ data: { type: 'addIps' }
+ } ) );
+ }
+
+ if ( buttonTypes.contribs ) {
+ options.push( new OO.ui.MenuOptionWidget( {
+ icon: 'userContributions',
+ label: mw.msg( 'checkuser-investigate-compare-table-button-contribs-label' ),
+ data: {
+ type: 'toolLinks',
+ href: new mw.Title( 'Special:Contributions' ).getUrl( {
+ target: $tableCell.data( 'value' )
+ } ),
+ tool: 'Special:Contributions'
+ }
+ } ) );
+ }
+
+ if ( buttonTypes.checks ) {
+ options.push( new OO.ui.MenuOptionWidget( {
+ icon: 'check',
+ label: mw.msg( 'checkuser-investigate-compare-table-button-checks-label' ),
+ data: {
+ type: 'toolLinks',
+ // TODO: Filter the log by the target, after T259791
+ href: new mw.Title( 'Special:InvestigateLog' ).getUrl(),
+ tool: 'Special:InvestigateLog'
+ }
+ } ) );
+ }
+
+ if ( buttonTypes.toolLinks ) {
+ message = mw.msg( 'checkuser-investigate-compare-toollinks', $tableCell.data( 'value' ) );
+ $links = $( '<div>' ).html( message ).find( 'a' );
+ $links.each( function ( i, $link ) {
+ var label = $link.text,
+ href = $link.getAttribute( 'href' );
+ options.push( new OO.ui.MenuOptionWidget( {
+ icon: 'linkExternal',
+ label: label,
+ data: {
+ type: 'toolLinks',
+ href: href,
+ tool: new mw.Uri( href ).host
+ }
+ } ) );
+ } );
+ }
+
+ if ( options.length > 0 ) {
+ selectWidget = new OO.ui.ButtonMenuSelectWidget( {
+ icon: 'ellipsis',
+ framed: false,
+ classes: [ 'ext-checkuser-investigate-table-select' ],
+ menu: {
+ horizontalPosition: 'end',
+ items: options
+ }
+ } );
+
+ selectWidget.getMenu().on( 'choose', function ( item ) {
+ var data = item.getData();
+ switch ( data.type ) {
+ case 'filter':
+ filterValue( $tableCell );
+ break;
+ case 'addIps':
+ addTargets( $tableCell );
+ break;
+ case 'addUsers':
+ addTargets( $tableCell );
+ break;
+ case 'toolLinks':
+ logEvent( {
+ action: 'tool',
+ tool: data.tool
+ } );
+ window.open( data.href, '_blank' );
+ break;
+ }
+ } );
+
+ $optionsContainer.append( selectWidget.$element );
+ }
+
+ if ( buttonTypes.toggle ) {
+ toggleButton = new OO.ui.ToggleButtonWidget( {
+ icon: 'pushPin',
+ framed: false,
+ classes: [ 'ext-checkuser-investigate-table-button-pin' ]
+ } );
+ toggleButtons[ key ] = toggleButtons[ key ] || [];
+ toggleButtons[ key ].push( toggleButton );
+ toggleButton.on( 'change', onToggleButtonChange.bind( null, $tableCell ) );
+ // Log the click not the change, since clicking on one button
+ // can lead to several other buttons changing
+ toggleButton.on( 'click', function () {
+ if ( toggleButton.getValue() ) {
+ logEvent( { action: 'pin' } );
+ }
+ } );
+ $optionsContainer.append( toggleButton.$element );
+ }
+ }
+
+ $( 'td.ext-checkuser-investigate-table-cell-pinnable' ).on( 'mouseover mouseout focusin focusout', onPinnableCellHover );
+
+ // Prevent the user from putting a table cell into focus.
+ $( '.ext-checkuser-investigate-table td' ).on( 'mousedown', function ( e ) {
+ e.preventDefault();
+ } );
+
+ $( '.ext-checkuser-investigate-table-preliminary-check td.ext-checkuser-investigate-table-cell-pinnable' )
+ .each( function () {
+ appendButtons( $( this ), {
+ toggle: true
+ } );
+ } );
+
+ $( '.ext-checkuser-investigate-table-compare .ext-checkuser-compare-table-cell-user-agent' )
+ .each( function () {
+ appendButtons( $( this ), {
+ toggle: true
+ } );
+ } );
+
+ $( '.ext-checkuser-investigate-table-compare .ext-checkuser-compare-table-cell-ip-target' )
+ .each( function () {
+ appendButtons( $( this ), {
+ toggle: true,
+ filter: true,
+ addUsers: true,
+ contribs: true,
+ checks: true,
+ toolLinks: true
+ } );
+ } );
+
+ $( 'td.ext-checkuser-compare-table-cell-user-target' )
+ .each( function () {
+ appendButtons( $( this ), {
+ filter: true,
+ addIps: true,
+ contribs: true,
+ checks: true
+ } );
+ } );
+
+ // Persist highlights across paginated tabs
+ if (
+ highlightData !== null &&
+ toggleButtons[ highlightData ] &&
+ toggleButtons[ highlightData ].length > 0
+ ) {
+ toggleButtons[ highlightData ][ 0 ].setValue( true );
+ }
+};
diff --git a/CheckUser/modules/ext.checkUser.investigateblock.styles/investigateblock.less b/CheckUser/modules/ext.checkUser.investigateblock.styles/investigateblock.less
new file mode 100644
index 00000000..bbb6fd57
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser.investigateblock.styles/investigateblock.less
@@ -0,0 +1,24 @@
+/*!
+ * Styles for Special:InvestigateBlock
+ */
+
+// OOUIHTMLForm specifics
+@ooui-font-size-browser: 16; // Assumed browser default of `16px`.
+@ooui-font-size-base: 0.875em; // Equals `14px` at browser default of `16px`.
+
+@ooui-spacing-radio-label: 26 / @ooui-font-size-browser / @ooui-font-size-base; // Equals `1.85714286em`≈`26px`.
+
+.ext-checkuser-investigate-block-notice.oo-ui-fieldLayout {
+ margin-left: @ooui-spacing-radio-label;
+ max-width: 50em - @ooui-spacing-radio-label;
+}
+
+.mw-special-InvestigateBlock .mw-htmlform {
+ > .oo-ui-panelLayout-framed {
+ border: 0;
+ }
+
+ > .oo-ui-panelLayout-padded {
+ padding: 0;
+ }
+}
diff --git a/CheckUser/modules/ext.checkUser.investigateblock/investigateblock.js b/CheckUser/modules/ext.checkUser.investigateblock/investigateblock.js
new file mode 100644
index 00000000..ddb8c505
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser.investigateblock/investigateblock.js
@@ -0,0 +1,33 @@
+( function () {
+ var userPageWidget,
+ userPagePositionWidget,
+ userPageTextWidget,
+ talkPageWidget,
+ talkPagePositionWidget,
+ talkPageTextWidget;
+
+ function updateNoticeOptions() {
+ var isUserPageChecked = userPageWidget.isSelected(),
+ isTalkPageChecked = talkPageWidget.isSelected();
+
+ userPagePositionWidget.setDisabled( !isUserPageChecked );
+ userPageTextWidget.setDisabled( !isUserPageChecked );
+
+ talkPagePositionWidget.setDisabled( !isTalkPageChecked );
+ talkPageTextWidget.setDisabled( !isTalkPageChecked );
+ }
+
+ if ( $( '#mw-htmlform-options' ).length > 0 ) {
+ userPageWidget = OO.ui.infuse( '#mw-input-wpUserPageNotice' );
+ userPagePositionWidget = OO.ui.infuse( '#mw-input-wpUserPageNoticePosition' );
+ userPageTextWidget = OO.ui.infuse( '#mw-input-wpUserPageNoticeText' );
+ talkPageWidget = OO.ui.infuse( '#mw-input-wpTalkPageNotice' );
+ talkPagePositionWidget = OO.ui.infuse( '#mw-input-wpTalkPageNoticePosition' );
+ talkPageTextWidget = OO.ui.infuse( '#mw-input-wpTalkPageNoticeText' );
+
+ userPageWidget.on( 'change', updateNoticeOptions );
+ talkPageWidget.on( 'change', updateNoticeOptions );
+
+ updateNoticeOptions();
+ }
+}() );
diff --git a/CheckUser/modules/ext.checkUser/caMultiLock.js b/CheckUser/modules/ext.checkUser/caMultiLock.js
new file mode 100644
index 00000000..8050d815
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser/caMultiLock.js
@@ -0,0 +1,42 @@
+/**
+ * Enhance Special:CheckUser's block form with a link to CentralAuth's
+ * Special:MultiLock (if installed)
+ */
+( function () {
+ var $userCheckboxes,
+ centralURL = mw.config.get( 'wgCUCAMultiLockCentral' );
+
+ if ( !centralURL ) {
+ // Ignore. Either this isn't a block form, or CentralAuth isn't setup.
+ return;
+ }
+
+ // Initialize the link
+ $( '#checkuserblock fieldset' ).append(
+ $( '<a>' ).attr( {
+ id: 'cacu-multilock-link',
+ href: centralURL
+ } ).text( mw.msg( 'checkuser-centralauth-multilock' ) )
+ );
+
+ // Change the URL of the link when a checkbox's state is changed
+ $userCheckboxes = $( '#checkuserresults li [type=checkbox]' );
+ $userCheckboxes.on( 'change', function () {
+ var names = [];
+ $userCheckboxes.serializeArray().forEach( function ( obj ) {
+ if ( obj.name && obj.name === 'users[]' ) {
+ // Only registered accounts (not IPs) can be locked
+ if ( !mw.util.isIPAddress( obj.value ) ) {
+ names.push( obj.value );
+ }
+ }
+ } );
+
+ // Update the href of the link with the latest change
+ $( '#cacu-multilock-link' ).prop(
+ 'href',
+ centralURL + '?wpTarget=' + encodeURIComponent( names.join( '\n' ) )
+ );
+ } );
+
+}() );
diff --git a/CheckUser/modules/ext.checkUser/cidr.js b/CheckUser/modules/ext.checkUser/cidr.js
new file mode 100644
index 00000000..8de64478
--- /dev/null
+++ b/CheckUser/modules/ext.checkUser/cidr.js
@@ -0,0 +1,226 @@
+/* eslint-disable one-var, vars-on-top */
+/* -- (c) Aaron Schulz 2009 */
+( function () {
+ var showResults = function ( size, cidr ) {
+ $( '#mw-checkuser-cidr-res' ).val( cidr );
+ $( '#mw-checkuser-ipnote' ).text( size );
+ };
+
+ /**
+ * This function calculates the common range of a list of
+ * IPs. It should be set to update on keyUp.
+ */
+ function updateCIDRresult() {
+ var form = document.getElementById( 'mw-checkuser-cidrform' );
+ if ( !form ) {
+ return; // no JS form
+ }
+ form.style.display = 'inline'; // unhide form (JS active)
+ var iplist = document.getElementById( 'mw-checkuser-iplist' );
+ if ( !iplist ) {
+ return; // no JS form
+ }
+ var text = iplist.value, ips;
+ // Each line should have one IP or range
+ if ( text.indexOf( '\n' ) !== -1 ) {
+ ips = text.split( '\n' );
+ // Try some other delimiters too...
+ } else if ( text.indexOf( '\t' ) !== -1 ) {
+ ips = text.split( '\t' );
+ } else if ( text.indexOf( ',' ) !== -1 ) {
+ ips = text.split( ',' );
+ } else if ( text.indexOf( ' - ' ) !== -1 ) {
+ ips = text.split( ' - ' );
+ } else if ( text.indexOf( '-' ) !== -1 ) {
+ ips = text.split( '-' );
+ } else if ( text.indexOf( ' ' ) !== -1 ) {
+ ips = text.split( ' ' );
+ } else {
+ ips = text.split( ';' );
+ }
+ var binPrefix = 0;
+ var prefixCidr = 0;
+ var prefix = '';
+ var foundV4 = false;
+ var foundV6 = false;
+ var ipCount;
+ var blocs;
+ // Go through each IP in the list, get its binary form, and
+ // track the largest binary prefix among them...
+ for ( var i = 0; i < ips.length; i++ ) {
+ // ...in the spirit of mediawiki.special.block.js, call this "addy"
+ var addy = ips[ i ].replace( /^\s*|\s*$/, '' ); // trim
+ // Match the first IP in each list (ignore other garbage)
+ var ipV4 = mw.util.isIPv4Address( addy, true );
+ var ipV6 = mw.util.isIPv6Address( addy, true );
+ var ipCidr = addy.match( /^(.*)(?:\/(\d+))?$/ );
+ // Binary form
+ var bin = '';
+ var x = 0, z = 0, start = 0, end = 0, ip, cidr, bloc, binBlock;
+ // Convert the IP to binary form: IPv4
+ if ( ipV4 ) {
+ foundV4 = true;
+ if ( foundV6 ) { // disjoint address space
+ prefix = '';
+ break;
+ }
+ ip = ipCidr[ 1 ];
+ cidr = ipCidr[ 2 ] ? ipCidr[ 2 ] : null; // CIDR, if it exists
+ // Get each quad integer
+ blocs = ip.split( '.' );
+ for ( x = 0; x < blocs.length; x++ ) {
+ bloc = parseInt( blocs[ x ], 10 );
+ binBlock = bloc.toString( 2 ); // concat bin with binary form of bloc
+ while ( binBlock.length < 8 ) {
+ binBlock = '0' + binBlock; // pad out as needed
+ }
+ bin += binBlock;
+ }
+ prefix = ''; // Rebuild formatted binPrefix for each IP
+ // Apply any valid CIDRs
+ if ( cidr ) {
+ bin = bin.substring( 0, cidr ); // truncate bin
+ }
+ // Init binPrefix
+ if ( binPrefix === 0 ) {
+ binPrefix = bin;
+ // Get largest common binPrefix
+ } else {
+ for ( x = 0; x < binPrefix.length; x++ ) {
+ // binPrefix always smaller than bin unless a CIDR was used on bin
+ if ( bin[ x ] === undefined || binPrefix[ x ] !== bin[ x ] ) {
+ binPrefix = binPrefix.substring( 0, x ); // shorten binPrefix
+ break;
+ }
+ }
+ }
+ // Build the IP in CIDR form
+ prefixCidr = binPrefix.length;
+ // CIDR too small?
+ if ( prefixCidr < 16 ) {
+ showResults( '!', '>' + Math.pow( 2, 32 - prefixCidr ) );
+ return; // too big
+ }
+ // Build the IP in dotted-quad form
+ for ( z = 0; z <= 3; z++ ) {
+ bloc = 0;
+ start = z * 8;
+ end = start + 7;
+ for ( x = start; x <= end; x++ ) {
+ if ( binPrefix[ x ] === undefined ) {
+ break;
+ }
+ bloc += parseInt( binPrefix[ x ], 10 ) * Math.pow( 2, end - x );
+ }
+ prefix += ( z === 3 ) ? bloc : bloc + '.';
+ }
+ // Get IPs affected
+ ipCount = Math.pow( 2, 32 - prefixCidr );
+ // Is the CIDR meaningful?
+ if ( prefixCidr === 32 ) {
+ prefixCidr = false;
+ }
+ // Convert the IP to binary form: IPv6
+ } else if ( ipV6 ) {
+ foundV6 = true;
+ if ( foundV4 ) { // disjoint address space
+ prefix = '';
+ break;
+ }
+ ip = ipCidr[ 1 ];
+ cidr = ipCidr[ 2 ] ? ipCidr[ 2 ] : null; // CIDR, if it exists
+ // Expand out "::"s
+ var abbrevs = ip.match( /::/g );
+ if ( abbrevs && abbrevs.length > 0 ) {
+ var colons = ip.match( /:/g );
+ var needed = 7 - ( colons.length - 2 ); // 2 from "::"
+ var insert = '';
+ while ( needed > 1 ) {
+ insert += ':0';
+ needed--;
+ }
+ ip = ip.replace( '::', insert + ':' );
+ // For IPs that start with "::", correct the final IP
+ // so that it starts with '0' and not ':'
+ if ( ip[ 0 ] === ':' ) {
+ ip = '0' + ip;
+ }
+ }
+ // Get each hex octant
+ blocs = ip.split( ':' );
+ for ( x = 0; x <= 7; x++ ) {
+ bloc = blocs[ x ] ? blocs[ x ] : '0';
+ var intBlock = parseInt( bloc, 16 ); // convert hex -> int
+ binBlock = intBlock.toString( 2 ); // concat bin with binary form of bloc
+ while ( binBlock.length < 16 ) {
+ binBlock = '0' + binBlock; // pad out as needed
+ }
+ bin += binBlock;
+ }
+ prefix = ''; // Rebuild formatted binPrefix for each IP
+ // Apply any valid CIDRs
+ if ( cidr ) {
+ bin = bin.substring( 0, cidr ); // truncate bin
+ }
+ // Init binPrefix
+ if ( binPrefix === 0 ) {
+ binPrefix = bin;
+ // Get largest common binPrefix
+ } else {
+ for ( x = 0; x < binPrefix.length; x++ ) {
+ // binPrefix always smaller than bin unless a CIDR was used on bin
+ if ( bin[ x ] === undefined || binPrefix[ x ] !== bin[ x ] ) {
+ binPrefix = binPrefix.substring( 0, x ); // shorten binPrefix
+ break;
+ }
+ }
+ }
+ // Build the IP in CIDR form
+ prefixCidr = binPrefix.length;
+ // CIDR too small?
+ if ( prefixCidr < 32 ) {
+ showResults( '!', '>' + Math.pow( 2, 128 - prefixCidr ) );
+ return; // too big
+ }
+ // Build the IP in dotted-quad form
+ for ( z = 0; z <= 7; z++ ) {
+ bloc = 0;
+ start = z * 16;
+ end = start + 15;
+ for ( x = start; x <= end; x++ ) {
+ if ( binPrefix[ x ] === undefined ) {
+ break;
+ }
+ bloc += parseInt( binPrefix[ x ], 10 ) * Math.pow( 2, end - x );
+ }
+ bloc = bloc.toString( 16 ); // convert to hex
+ prefix += ( z === 7 ) ? bloc : bloc + ':';
+ }
+ // Get IPs affected
+ ipCount = Math.pow( 2, 128 - prefixCidr );
+ // Is the CIDR meaningful?
+ if ( prefixCidr === 128 ) {
+ prefixCidr = false;
+ }
+ }
+ }
+ // Update form
+ if ( prefix !== '' ) {
+ var full = prefix;
+ if ( prefixCidr !== false ) {
+ full += '/' + prefixCidr;
+ }
+ showResults( '~' + ipCount, full );
+ } else {
+ showResults( '?', '' );
+ }
+
+ }
+
+ $( function () {
+ updateCIDRresult();
+ $( '#mw-checkuser-iplist' ).on( 'keyup click', function () {
+ updateCIDRresult();
+ } );
+ } );
+}() );
diff --git a/CheckUser/modules/ext.checkuser.caMultiLock.js b/CheckUser/modules/ext.checkuser.caMultiLock.js
deleted file mode 100644
index fc9598ee..00000000
--- a/CheckUser/modules/ext.checkuser.caMultiLock.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Adds a link to Special:MultiLock on a central wiki if $wgCheckUserCAMultiLock
- * is configured on the Special:CheckUser's block form
- */
-( function ( mw, $ ) {
- var centralURL = mw.config.get( 'wgCUCAMultiLockCentral' ),
- $userCheckboxes = $( '#checkuserresults li :checkbox' );
-
- // Initialize the link
- $( '#checkuserblock fieldset' ).append(
- $( '<a>', {
- id: 'cacu-multilock-link',
- text: mw.msg( 'checkuser-centralauth-multilock' ),
- href: centralURL
- } )
- );
-
- // Change the URL of the link when a checkbox's state is changed
- $userCheckboxes.on( 'change', function () {
- var names = [];
- $.each( $userCheckboxes.serializeArray(), function ( i, obj ) {
- if ( obj.name && obj.name === 'users[]' ) {
- // Only registered accounts (not IPs) can be locked
- if ( !mw.util.isIPAddress( obj.value ) ) {
- names.push( obj.value );
- }
- }
- } );
-
- var mlHref = centralURL + '?wpTarget=' + encodeURIComponent( names.join( '\n' ) );
- // Update the href of the link with the latest change
- $( '#cacu-multilock-link' ).prop( 'href', mlHref );
- } );
-
-}( mediaWiki, jQuery ) );
diff --git a/CheckUser/modules/ext.checkuser.cidr.js b/CheckUser/modules/ext.checkuser.cidr.js
deleted file mode 100644
index f07bfd15..00000000
--- a/CheckUser/modules/ext.checkuser.cidr.js
+++ /dev/null
@@ -1,259 +0,0 @@
-/* -- (c) Aaron Schulz 2009 */
-( function ( mw, $ ) {
-var showResults = function ( size, cidr ) {
- $( '#mw-checkuser-cidr-res' ).val( cidr );
- $( '#mw-checkuser-ipnote' ).text( size );
-};
-
-/*
-* This function calculates the common range of a list of
-* IPs. It should be set to update on keyUp.
-*/
-var updateCIDRresult = function () {
- var form = document.getElementById( 'mw-checkuser-cidrform' );
- if ( !form ) {
- return; // no JS form
- }
- form.style.display = 'inline'; // unhide form (JS active)
- var iplist = document.getElementById( 'mw-checkuser-iplist' );
- if ( !iplist ) {
- return; // no JS form
- }
- var text = iplist.value, ips;
- // Each line should have one IP or range
- if ( text.indexOf( '\n' ) !== -1 ) {
- ips = text.split( '\n' );
- // Try some other delimiters too...
- } else if ( text.indexOf( '\t' ) !== -1 ) {
- ips = text.split( '\t' );
- } else if ( text.indexOf( ',' ) !== -1 ) {
- ips = text.split( ',' );
- } else if ( text.indexOf( ' - ' ) !== -1 ) {
- ips = text.split( ' - ' );
- } else if ( text.indexOf( '-' ) !== -1 ) {
- ips = text.split( '-' );
- } else if ( text.indexOf( ' ' ) !== -1 ) {
- ips = text.split( ' ' );
- } else {
- ips = text.split( ';' );
- }
- var binPrefix = 0;
- var prefixCidr = 0;
- var prefix = '';
- var foundV4 = false;
- var foundV6 = false;
- var ipCount;
- var blocs;
- // Go through each IP in the list, get its binary form, and
- // track the largest binary prefix among them...
- for ( var i = 0; i < ips.length; i++ ) {
- // ...in the spirit of mediawiki.special.block.js, call this "addy"
- var addy = ips[i].replace( /^\s*|\s*$/, '' ); // trim
- // Match the first IP in each list (ignore other garbage)
- var ipV4 = mw.util.isIPv4Address( addy, true );
- var ipV6 = mw.util.isIPv6Address( addy, true );
- var ipCidr = addy.match( /^(.*)(?:\/(\d+))?$/ );
- // Binary form
- var bin = '';
- var x = 0, z = 0, start = 0, end = 0, ip, cidr, bloc, binBlock;
- // Convert the IP to binary form: IPv4
- if ( ipV4 ) {
- foundV4 = true;
- if ( foundV6 ) { // disjoint address space
- prefix = '';
- break;
- }
- ip = ipCidr[1];
- cidr = ipCidr[2] ? ipCidr[2] : null; // CIDR, if it exists
- // Get each quad integer
- blocs = ip.split( '.' );
- for ( x = 0; x < blocs.length; x++ ) {
- bloc = parseInt( blocs[x], 10 );
- binBlock = bloc.toString( 2 ); // concat bin with binary form of bloc
- while ( binBlock.length < 8 ) {
- binBlock = '0' + binBlock; // pad out as needed
- }
- bin += binBlock;
- }
- prefix = ''; // Rebuild formatted binPrefix for each IP
- // Apply any valid CIDRs
- if ( cidr ) {
- bin = bin.substring( 0, cidr ); // truncate bin
- }
- // Init binPrefix
- if ( binPrefix === 0 ) {
- binPrefix = bin;
- // Get largest common binPrefix
- } else {
- for ( x = 0; x < binPrefix.length; x++ ) {
- // binPrefix always smaller than bin unless a CIDR was used on bin
- if ( bin[x] === undefined || binPrefix[x] !== bin[x] ) {
- binPrefix = binPrefix.substring( 0, x ); // shorten binPrefix
- break;
- }
- }
- }
- // Build the IP in CIDR form
- prefixCidr = binPrefix.length;
- // CIDR too small?
- if ( prefixCidr < 16 ) {
- showResults( '!', '>' + Math.pow( 2, 32 - prefixCidr ) );
- return; // too big
- }
- // Build the IP in dotted-quad form
- for ( z = 0; z <= 3; z++ ) {
- bloc = 0;
- start = z * 8;
- end = start + 7;
- for ( x = start; x <= end; x++ ) {
- if ( binPrefix[x] === undefined ) {
- break;
- }
- bloc += parseInt( binPrefix[x], 10 ) * Math.pow( 2, end - x );
- }
- prefix += ( z === 3 ) ? bloc : bloc + '.';
- }
- // Get IPs affected
- ipCount = Math.pow( 2, 32 - prefixCidr );
- // Is the CIDR meaningful?
- if ( prefixCidr === 32 ) {
- prefixCidr = false;
- }
- // Convert the IP to binary form: IPv6
- } else if ( ipV6 ) {
- foundV6 = true;
- if ( foundV4 ) { // disjoint address space
- prefix = '';
- break;
- }
- ip = ipCidr[1];
- cidr = ipCidr[2] ? ipCidr[2] : null; // CIDR, if it exists
- // Expand out "::"s
- var abbrevs = ip.match( /::/g );
- if ( abbrevs && abbrevs.length > 0 ) {
- var colons = ip.match( /:/g );
- var needed = 7 - ( colons.length - 2 ); // 2 from "::"
- var insert = '';
- while ( needed > 1 ) {
- insert += ':0';
- needed--;
- }
- ip = ip.replace( '::', insert + ':' );
- // For IPs that start with "::", correct the final IP
- // so that it starts with '0' and not ':'
- if ( ip[0] === ':' ) {
- ip = '0' + ip;
- }
- }
- // Get each hex octant
- blocs = ip.split( ':' );
- for ( x = 0; x <= 7; x++ ) {
- bloc = blocs[x] ? blocs[x] : '0';
- var intBlock = hex2int( bloc ); // convert hex -> int
- binBlock = intBlock.toString( 2 ); // concat bin with binary form of bloc
- while ( binBlock.length < 16 ) {
- binBlock = '0' + binBlock; // pad out as needed
- }
- bin += binBlock;
- }
- prefix = ''; // Rebuild formatted binPrefix for each IP
- // Apply any valid CIDRs
- if ( cidr ) {
- bin = bin.substring( 0, cidr ); // truncate bin
- }
- // Init binPrefix
- if ( binPrefix === 0 ) {
- binPrefix = bin;
- // Get largest common binPrefix
- } else {
- for ( x = 0; x < binPrefix.length; x++ ) {
- // binPrefix always smaller than bin unless a CIDR was used on bin
- if ( bin[x] === undefined || binPrefix[x] !== bin[x] ) {
- binPrefix = binPrefix.substring( 0, x ); // shorten binPrefix
- break;
- }
- }
- }
- // Build the IP in CIDR form
- prefixCidr = binPrefix.length;
- // CIDR too small?
- if ( prefixCidr < 32 ) {
- showResults( '!', '>' + Math.pow( 2, 128 - prefixCidr ) );
- return; // too big
- }
- // Build the IP in dotted-quad form
- for ( z = 0; z <= 7; z++ ) {
- bloc = 0;
- start = z*16;
- end = start + 15;
- for ( x = start; x <= end; x++ ) {
- if ( binPrefix[x] === undefined ) {
- break;
- }
- bloc += parseInt( binPrefix[x], 10 ) * Math.pow( 2, end - x );
- }
- bloc = bloc.toString( 16 ); // convert to hex
- prefix += ( z === 7 ) ? bloc : bloc + ':';
- }
- // Get IPs affected
- ipCount = Math.pow( 2, 128 - prefixCidr );
- // Is the CIDR meaningful?
- if ( prefixCidr === 128 ) {
- prefixCidr = false;
- }
- }
- }
- // Update form
- if ( prefix !== '' ) {
- var full = prefix;
- if ( prefixCidr !== false ) {
- full += '/' + prefixCidr;
- }
- showResults( '~' + ipCount, full );
- } else {
- showResults( '?', '' );
- }
-
-};
-
-// Utility function to convert hex to integers
-var hex2int = function ( hex ) {
- hex = hex.toLowerCase();
- var intform = 0;
- for ( var i = 0; i < hex.length; i++ ) {
- var digit = 0;
- switch ( hex[i] ) {
- case 'a':
- digit = 10;
- break;
- case 'b':
- digit = 11;
- break;
- case 'c':
- digit = 12;
- break;
- case 'd':
- digit = 13;
- break;
- case 'e':
- digit = 14;
- break;
- case 'f':
- digit = 15;
- break;
- default:
- digit = parseInt( hex[i], 10 );
- break;
- }
- intform += digit * Math.pow( 16, hex.length - 1 - i );
- }
- return intform;
-};
-
-$( function () {
- updateCIDRresult();
- $( '#mw-checkuser-iplist' ).on( 'keyup click', function () {
- updateCIDRresult();
- } );
-} );
-} )( mediaWiki, jQuery );
diff --git a/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js b/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js
new file mode 100644
index 00000000..e15a42bb
--- /dev/null
+++ b/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigate/checkuserinvestigate.js
@@ -0,0 +1,127 @@
+/*
+ * Special:Invesitgate guided tour
+ */
+( function ( gt ) {
+ var tour;
+
+ if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Investigate' ) {
+ return;
+ }
+
+ if ( $( '.ext-checkuser-investigate-table-compare' ).length === 0 ) {
+ return;
+ }
+
+ tour = new gt.TourBuilder( {
+ name: 'checkuserinvestigate',
+ shouldLog: true,
+ isSinglePage: false
+ } );
+
+ tour.firstStep( {
+ name: 'useragents',
+ titlemsg: 'checkuser-investigate-tour-useragents-title',
+ descriptionmsg: 'checkuser-investigate-tour-useragents-desc',
+ attachTo: '.ext-checkuser-compare-table-cell-user-agent',
+ position: 'left',
+ closeOnClickOutside: false,
+ overlay: true,
+ onShow: function () {
+ $( this.attachTo ).first().trigger( 'mouseover' );
+ },
+ onHide: function () {
+ $( this.attachTo ).first().trigger( 'mouseout' );
+
+ // Api.saveOption will save a string instead of a bool. :(
+ ( new mw.Api() ).saveOption( 'checkuser-investigate-tour-seen', 1 );
+ }
+ } )
+ .next( 'addusertargets' );
+
+ function handleIpTargetOnShow() {
+ var $cell = $( '.ext-checkuser-compare-table-cell-ip-target' ).first();
+
+ $cell.trigger( 'mouseover' );
+ $cell.addClass( 'ext-checkuser-investigate-active' );
+ // @TODO This causes a flicker between steps, maybe there is a way to force it to stay open?
+ $( '.ext-checkuser-investigate-table-select .oo-ui-buttonElement-button', $cell ).first().trigger(
+ $.Event( 'click', { which: OO.ui.MouseButtons.LEFT } )
+ );
+ }
+
+ function handleIpTargetOnHide() {
+ $( '.ext-checkuser-compare-table-cell-ip-target' ).first().trigger( 'mouseout' );
+ $( '.ext-checkuser-compare-table-cell-ip-target' ).first().removeClass( 'ext-checkuser-investigate-active' );
+ }
+
+ tour.step( {
+ name: 'addusertargets',
+ titlemsg: 'checkuser-investigate-tour-addusertargets-title',
+ descriptionmsg: 'checkuser-investigate-tour-addusertargets-desc',
+ attachTo: '.ext-checkuser-investigate-button-add-user-targets',
+ position: 'right',
+ closeOnClickOutside: false,
+ autoFocus: false,
+ overlay: true,
+ onShow: handleIpTargetOnShow,
+ onHide: handleIpTargetOnHide
+ } )
+ .back( 'useragents' )
+ .next( 'filterip' );
+
+ tour.step( {
+ name: 'filterip',
+ titlemsg: 'checkuser-investigate-tour-filterip-title',
+ descriptionmsg: 'checkuser-investigate-tour-filterip-desc',
+ attachTo: '.ext-checkuser-investigate-button-filter-ip',
+ position: 'right',
+ closeOnClickOutside: false,
+ autoFocus: false,
+ overlay: true,
+ onShow: handleIpTargetOnShow,
+ onHide: handleIpTargetOnHide
+ } )
+ .back( 'addusertargets' )
+ .next( 'block' );
+
+ tour.step( {
+ name: 'block',
+ titlemsg: 'checkuser-investigate-tour-block-title',
+ descriptionmsg: 'checkuser-investigate-tour-block-desc',
+ attachTo: '.ext-checkuser-investigate-subtitle-block-button',
+ position: 'bottomLeft',
+ closeOnClickOutside: false,
+ overlay: true,
+ buttons: [
+ {
+ action: 'back'
+ },
+ {
+ // If the copy button is not present, end the tour.
+ action: $( '.ext-checkuser-investigate-copy-button' ).length ? 'next' : 'end'
+ }
+ ]
+ } )
+ .back( 'filterip' )
+ .next( 'copywikitext' );
+
+ tour.step( {
+ name: 'copywikitext',
+ titlemsg: 'checkuser-investigate-tour-copywikitext-title',
+ descriptionmsg: 'checkuser-investigate-tour-copywikitext-desc',
+ attachTo: '.ext-checkuser-investigate-copy-button',
+ position: 'topLeft',
+ closeOnClickOutside: false,
+ overlay: true,
+ buttons: [
+ {
+ action: 'back'
+ },
+ {
+ action: 'end'
+ }
+ ]
+ } )
+ .back( 'block' );
+
+}( mw.guidedTour ) );
diff --git a/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigateform/checkuserinvestigateform.js b/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigateform/checkuserinvestigateform.js
new file mode 100644
index 00000000..d1a0e54a
--- /dev/null
+++ b/CheckUser/modules/ext.guidedTour.tour.checkuserinvestigateform/checkuserinvestigateform.js
@@ -0,0 +1,40 @@
+/*
+ * Special:Invesitgate form guided tour
+ */
+( function ( gt ) {
+ var tour;
+
+ if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Investigate' ) {
+ return;
+ }
+
+ if ( $( '#targets' ).length === 0 ) {
+ return;
+ }
+
+ tour = new gt.TourBuilder( {
+ name: 'checkuserinvestigateform',
+ shouldLog: true,
+ isSinglePage: false
+ } );
+
+ tour.firstStep( {
+ name: 'targets',
+ titlemsg: 'checkuser-investigate-tour-targets-title',
+ description: mw.message( 'checkuser-investigate-tour-targets-desc', mw.config.get( 'wgCheckUserInvestigateMaxTargets' ) ).parse(),
+ attachTo: '#targets',
+ position: 'bottom',
+ closeOnClickOutside: false,
+ overlay: true,
+ onHide: function () {
+ // Api.saveOption will save a string instead of a bool. :(
+ ( new mw.Api() ).saveOption( 'checkuser-investigate-form-tour-seen', 1 );
+ },
+ buttons: [
+ {
+ action: 'end'
+ }
+ ]
+ } );
+
+}( mw.guidedTour ) );
diff --git a/CheckUser/package-lock.json b/CheckUser/package-lock.json
new file mode 100644
index 00000000..3a52fe0d
--- /dev/null
+++ b/CheckUser/package-lock.json
@@ -0,0 +1,5151 @@
+{
+ "name": "checkuser",
+ "version": "0.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
+ "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
+ "requires": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "@babel/core": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz",
+ "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.9.0",
+ "@babel/helper-module-transforms": "^7.9.0",
+ "@babel/helpers": "^7.9.0",
+ "@babel/parser": "^7.9.0",
+ "@babel/template": "^7.8.6",
+ "@babel/traverse": "^7.9.0",
+ "@babel/types": "^7.9.0",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.1",
+ "json5": "^2.1.2",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+ "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.8.3"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
+ "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.0",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@babel/generator": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz",
+ "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.9.5",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
+ "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.9.5"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
+ "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-member-expression-to-functions": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz",
+ "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz",
+ "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-module-transforms": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz",
+ "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.8.3",
+ "@babel/helper-replace-supers": "^7.8.6",
+ "@babel/helper-simple-access": "^7.8.3",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/template": "^7.8.6",
+ "@babel/types": "^7.9.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/helper-optimise-call-expression": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz",
+ "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-replace-supers": {
+ "version": "7.8.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz",
+ "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-member-expression-to-functions": "^7.8.3",
+ "@babel/helper-optimise-call-expression": "^7.8.3",
+ "@babel/traverse": "^7.8.6",
+ "@babel/types": "^7.8.6"
+ }
+ },
+ "@babel/helper-simple-access": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz",
+ "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
+ "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
+ "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
+ "dev": true
+ },
+ "@babel/helpers": {
+ "version": "7.9.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz",
+ "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.9.0",
+ "@babel/types": "^7.9.0"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
+ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.9.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz",
+ "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==",
+ "dev": true
+ },
+ "@babel/runtime": {
+ "version": "7.9.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz",
+ "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==",
+ "dev": true,
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "@babel/template": {
+ "version": "7.8.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
+ "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.6",
+ "@babel/types": "^7.8.6"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+ "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.8.3"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
+ "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.0",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz",
+ "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.9.5",
+ "@babel/helper-function-name": "^7.9.5",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.9.0",
+ "@babel/types": "^7.9.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+ "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.8.3"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
+ "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.0",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@babel/types": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz",
+ "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.5",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "@eslint/eslintrc": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
+ "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
+ "requires": {
+ "ajv": "^6.12.4",
+ "debug": "^4.1.1",
+ "espree": "^7.3.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^3.13.1",
+ "lodash": "^4.17.19",
+ "minimatch": "^3.0.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
+ "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w=="
+ },
+ "ajv": {
+ "version": "6.12.4",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
+ "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
+ },
+ "espree": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz",
+ "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==",
+ "requires": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.2.0",
+ "eslint-visitor-keys": "^1.3.0"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "globals": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+ "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+ "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
+ }
+ }
+ },
+ "@nodelib/fs.scandir": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
+ "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "2.0.3",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
+ "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
+ "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.3",
+ "fastq": "^1.6.0"
+ }
+ },
+ "@stylelint/postcss-css-in-js": {
+ "version": "0.37.1",
+ "resolved": "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.1.tgz",
+ "integrity": "sha512-UMf2Rni3JGKi3ZwYRGMYJ5ipOA5ENJSKMtYA/pE1ZLURwdh7B5+z2r73RmWvub+N0UuH1Lo+TGfCgYwPvqpXNw==",
+ "dev": true,
+ "requires": {
+ "@babel/core": ">=7.9.0"
+ }
+ },
+ "@stylelint/postcss-markdown": {
+ "version": "0.36.1",
+ "resolved": "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.1.tgz",
+ "integrity": "sha512-iDxMBWk9nB2BPi1VFQ+Dc5+XpvODBHw2n3tYpaBZuEAFQlbtF9If0Qh5LTTwSi/XwdbJ2jt+0dis3i8omyggpw==",
+ "dev": true,
+ "requires": {
+ "remark": "^12.0.0",
+ "unist-util-find-all-after": "^3.0.1"
+ }
+ },
+ "@types/color-name": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
+ },
+ "@types/minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=",
+ "dev": true
+ },
+ "@types/normalize-package-data": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
+ "dev": true
+ },
+ "@types/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+ "dev": true
+ },
+ "@types/unist": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
+ "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==",
+ "dev": true
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "acorn": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz",
+ "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
+ "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ=="
+ },
+ "ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
+ },
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true
+ },
+ "array-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=",
+ "dev": true
+ },
+ "array-slice": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+ "dev": true
+ },
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+ "dev": true
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true
+ },
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
+ },
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true
+ },
+ "autoprefixer": {
+ "version": "9.7.6",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.6.tgz",
+ "integrity": "sha512-F7cYpbN7uVVhACZTeeIeealwdGM6wMtfWARVLTy5xmKtgVdBNJvbDRoCK3YO1orcs7gv/KwYlb3iXwu9Ug9BkQ==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.11.1",
+ "caniuse-lite": "^1.0.30001039",
+ "chalk": "^2.4.2",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.27",
+ "postcss-value-parser": "^4.0.3"
+ }
+ },
+ "bail": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+ "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "browserslist": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz",
+ "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30001043",
+ "electron-to-chromium": "^1.3.413",
+ "node-releases": "^1.1.53",
+ "pkg-up": "^2.0.0"
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001045",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001045.tgz",
+ "integrity": "sha512-Y8o2Iz1KPcD6FjySbk1sPpvJqchgxk/iow0DABpGyzA1UeQAuxh63Xh0Enj5/BrsYbXtCN32JmR4ZxQTCQ6E6A==",
+ "dev": true
+ },
+ "ccount": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz",
+ "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "character-entities": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "dev": true
+ },
+ "character-entities-html4": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+ "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+ "dev": true
+ },
+ "character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "dev": true
+ },
+ "character-reference-invalid": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+ "dev": true
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "clone-regexp": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
+ "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
+ "dev": true,
+ "requires": {
+ "is-regexp": "^2.0.0"
+ }
+ },
+ "collapse-white-space": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+ "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+ "dev": true
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ },
+ "colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true
+ },
+ "comment-parser": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.7.6.tgz",
+ "integrity": "sha512-GKNxVA7/iuTnAqGADlTWX4tkhzxZKXp5fLJqKTlQLHkE65XDUKutZ3BHaJC5IGcper2tT3QRD1xr4o3jNpgXXg==",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "convert-source-map": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+ "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true
+ },
+ "cosmiconfig": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
+ "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
+ "dev": true,
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.1.0",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.7.2"
+ },
+ "dependencies": {
+ "parse-json": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
+ "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ }
+ }
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "dependencies": {
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true
+ },
+ "dateformat": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
+ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "decamelize-keys": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+ "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
+ "dev": true,
+ "requires": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ }
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+ "dev": true
+ },
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ },
+ "dependencies": {
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ }
+ }
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "dom-serializer": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+ "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ },
+ "dependencies": {
+ "domelementtype": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
+ "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==",
+ "dev": true
+ },
+ "entities": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
+ "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==",
+ "dev": true
+ }
+ }
+ },
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "domutils": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+ "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "electron-to-chromium": {
+ "version": "1.3.414",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.414.tgz",
+ "integrity": "sha512-UfxhIvED++qLwWrAq9uYVcqF8FdeV9sU2S7qhiHYFODxzXRrd1GZRl/PjITHsTEejgibcWDraD8TQqoHb1aCBQ==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+ "requires": {
+ "ansi-colors": "^4.1.1"
+ }
+ },
+ "entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "eslint": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz",
+ "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@eslint/eslintrc": "^0.1.3",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "eslint-scope": "^5.1.0",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^1.3.0",
+ "espree": "^7.3.0",
+ "esquery": "^1.2.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash": "^4.17.19",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+ },
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
+ },
+ "globals": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+ "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "eslint-config-wikimedia": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.17.0.tgz",
+ "integrity": "sha512-zxTlSJkNvKNfWRBGxXoFbI4jCKFMDLdclPQZyvlCC4z35xPh81SuhIW1CfYoTmL4DvJEj+2X7wVXlHs5E/WaxQ==",
+ "dev": true,
+ "requires": {
+ "eslint": "^7.6.0",
+ "eslint-plugin-es": "^3.0.1",
+ "eslint-plugin-jsdoc": "^30.2.1",
+ "eslint-plugin-json": "^2.1.2",
+ "eslint-plugin-mediawiki": "^0.2.5",
+ "eslint-plugin-mocha": "^8.0.0",
+ "eslint-plugin-no-jquery": "^2.5.0",
+ "eslint-plugin-node": "^11.1.0",
+ "eslint-plugin-qunit": "^4.3.0",
+ "eslint-plugin-vue": "^6.2.2",
+ "eslint-plugin-wdio": "^6.0.12"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
+ "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "eslint": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz",
+ "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@eslint/eslintrc": "^0.1.3",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "eslint-scope": "^5.1.0",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^1.3.0",
+ "espree": "^7.3.0",
+ "esquery": "^1.2.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash": "^4.17.19",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ }
+ },
+ "eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ },
+ "espree": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz",
+ "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==",
+ "dev": true,
+ "requires": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.2.0",
+ "eslint-visitor-keys": "^1.3.0"
+ }
+ },
+ "globals": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+ "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "eslint-plugin-es": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz",
+ "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==",
+ "dev": true,
+ "requires": {
+ "eslint-utils": "^2.0.0",
+ "regexpp": "^3.0.0"
+ }
+ },
+ "eslint-plugin-jsdoc": {
+ "version": "30.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.3.1.tgz",
+ "integrity": "sha512-185ARou6Wj/68DP0g9kLLBnvmVwgg6/E/7Z8Z7Dz7Z63WgvRNaSvOLQiXkzIOEwstQfwI9PCuFPh4qBJov907A==",
+ "dev": true,
+ "requires": {
+ "comment-parser": "^0.7.6",
+ "debug": "^4.1.1",
+ "jsdoctypeparser": "^9.0.0",
+ "lodash": "^4.17.20",
+ "regextras": "^0.7.1",
+ "semver": "^7.3.2",
+ "spdx-expression-parse": "^3.0.1"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ }
+ }
+ },
+ "eslint-plugin-json": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-2.1.2.tgz",
+ "integrity": "sha512-isM/fsUxS4wN1+nLsWoV5T4gLgBQnsql3nMTr8u+cEls1bL8rRQO5CP5GtxJxaOfbcKqnz401styw+H/P+e78Q==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.19",
+ "vscode-json-languageservice": "^3.7.0"
+ }
+ },
+ "eslint-plugin-mediawiki": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mediawiki/-/eslint-plugin-mediawiki-0.2.5.tgz",
+ "integrity": "sha512-Xs5G4f1EnS6+9gFWkk28nWA9xcOEPx7YZEGsMYGLelZRAF+2DmV/PigF5N5VqoOkNBpwcbXqLD8wLfkg29aF8w==",
+ "dev": true,
+ "requires": {
+ "eslint-plugin-vue": "^6.2.2",
+ "upath": "^1.2.0"
+ }
+ },
+ "eslint-plugin-mocha": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-8.0.0.tgz",
+ "integrity": "sha512-n67etbWDz6NQM+HnTwZHyBwz/bLlYPOxUbw7bPuCyFujv7ZpaT/Vn6KTAbT02gf7nRljtYIjWcTxK/n8a57rQQ==",
+ "dev": true,
+ "requires": {
+ "eslint-utils": "^2.1.0",
+ "ramda": "^0.27.1"
+ },
+ "dependencies": {
+ "eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ }
+ }
+ },
+ "eslint-plugin-no-jquery": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.5.0.tgz",
+ "integrity": "sha512-RrQ380mUJJKdjgpQ/tZAJ3B3W1n3LbVmULooS2Pv5pUDcc5uVHVSJMTdUlsbvQyfo6hWP2LJ4FbOoDzENWcF7A==",
+ "dev": true
+ },
+ "eslint-plugin-node": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz",
+ "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==",
+ "dev": true,
+ "requires": {
+ "eslint-plugin-es": "^3.0.0",
+ "eslint-utils": "^2.0.0",
+ "ignore": "^5.1.1",
+ "minimatch": "^3.0.4",
+ "resolve": "^1.10.1",
+ "semver": "^6.1.0"
+ },
+ "dependencies": {
+ "ignore": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
+ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
+ "dev": true
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-plugin-qunit": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-4.3.0.tgz",
+ "integrity": "sha512-xyQtwoDHWDuIqH5cp8SV0N++gFGwxfMKwRyumsBnJ3INM6Mz/qWUhrCTastOvvAc98aoieu2X5Ht4LgaZ3a75Q==",
+ "dev": true
+ },
+ "eslint-plugin-vue": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-6.2.2.tgz",
+ "integrity": "sha512-Nhc+oVAHm0uz/PkJAWscwIT4ijTrK5fqNqz9QB1D35SbbuMG1uB6Yr5AJpvPSWg+WOw7nYNswerYh0kOk64gqQ==",
+ "dev": true,
+ "requires": {
+ "natural-compare": "^1.4.0",
+ "semver": "^5.6.0",
+ "vue-eslint-parser": "^7.0.0"
+ }
+ },
+ "eslint-plugin-wdio": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wdio/-/eslint-plugin-wdio-6.0.12.tgz",
+ "integrity": "sha512-qZqcU1Z0bqrqhYM1MbwIvKQxcQEGIOEclOjcveavvLZAN4ezpXb1Ogw3xu+UK13iArregJOMI6uUt+JkFmER1A==",
+ "dev": true
+ },
+ "eslint-scope": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
+ "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz",
+ "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz",
+ "integrity": "sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==",
+ "dev": true
+ },
+ "espree": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz",
+ "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==",
+ "requires": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.2.0",
+ "eslint-visitor-keys": "^1.3.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
+ "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w=="
+ },
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
+ }
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ },
+ "esquery": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
+ "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz",
+ "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw=="
+ }
+ }
+ },
+ "esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "requires": {
+ "estraverse": "^4.1.0"
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+ },
+ "eventemitter2": {
+ "version": "0.4.14",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+ "dev": true
+ },
+ "execall": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz",
+ "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==",
+ "dev": true,
+ "requires": {
+ "clone-regexp": "^2.1.0"
+ }
+ },
+ "exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "dev": true
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "fast-glob": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz",
+ "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ }
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "fastq": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.7.0.tgz",
+ "integrity": "sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ==",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "file-entry-cache": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+ "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "requires": {
+ "flat-cache": "^2.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "findup-sync": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
+ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
+ "dev": true,
+ "requires": {
+ "glob": "~5.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "fined": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
+ "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "is-plain-object": "^2.0.3",
+ "object.defaults": "^1.1.0",
+ "object.pick": "^1.2.0",
+ "parse-filepath": "^1.0.1"
+ }
+ },
+ "flagged-respawn": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
+ "dev": true
+ },
+ "flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "requires": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ }
+ },
+ "flatted": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
+ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg=="
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+ },
+ "gensync": {
+ "version": "1.0.0-beta.1",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
+ "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==",
+ "dev": true
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "getobject": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
+ "dev": true
+ },
+ "glob": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+ "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
+ "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "global-modules": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
+ "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^3.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
+ "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.5",
+ "kind-of": "^6.0.2",
+ "which": "^1.3.1"
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true
+ },
+ "globby": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz",
+ "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ },
+ "dependencies": {
+ "ignore": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
+ "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
+ "dev": true
+ }
+ }
+ },
+ "globjoin": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
+ "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=",
+ "dev": true
+ },
+ "gonzales-pe": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz",
+ "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "grunt": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.3.0.tgz",
+ "integrity": "sha512-6ILlMXv11/4cxuhSMfSU+SfvbxrPuqZrAtLN64+tZpQ3DAKfSQPQHRbTjSbdtxfyQhGZPtN0bDZJ/LdCM5WXXA==",
+ "dev": true,
+ "requires": {
+ "dateformat": "~3.0.3",
+ "eventemitter2": "~0.4.13",
+ "exit": "~0.1.2",
+ "findup-sync": "~0.3.0",
+ "glob": "~7.1.6",
+ "grunt-cli": "~1.3.2",
+ "grunt-known-options": "~1.1.0",
+ "grunt-legacy-log": "~3.0.0",
+ "grunt-legacy-util": "~2.0.0",
+ "iconv-lite": "~0.4.13",
+ "js-yaml": "~3.14.0",
+ "minimatch": "~3.0.4",
+ "mkdirp": "~1.0.4",
+ "nopt": "~3.0.6",
+ "rimraf": "~3.0.2"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "grunt-cli": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.3.2.tgz",
+ "integrity": "sha512-8OHDiZZkcptxVXtMfDxJvmN7MVJNE8L/yIcPb4HB7TlyFD1kDvjHrb62uhySsU14wJx9ORMnTuhRMQ40lH/orQ==",
+ "dev": true,
+ "requires": {
+ "grunt-known-options": "~1.1.0",
+ "interpret": "~1.1.0",
+ "liftoff": "~2.5.0",
+ "nopt": "~4.0.1",
+ "v8flags": "~3.1.1"
+ },
+ "dependencies": {
+ "nopt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
+ "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
+ "dev": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ }
+ }
+ },
+ "js-yaml": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+ "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "grunt-banana-checker": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/grunt-banana-checker/-/grunt-banana-checker-0.9.0.tgz",
+ "integrity": "sha512-SqPiB6OazWqR8USL0NymtuT5Br3mD9WBBsM1rHC/3wIi2SrZNM6/+j9CIeuEM5oCn+AtO2Y0+rzzFyOdC9afAg==",
+ "dev": true
+ },
+ "grunt-eslint": {
+ "version": "23.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-eslint/-/grunt-eslint-23.0.0.tgz",
+ "integrity": "sha512-QqHSAiGF08EVD7YlD4OSRWuLRaDvpsRdTptwy9WaxUXE+03mCLVA/lEaR6SHWehF7oUwIqCEjaNONeeeWlB4LQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^4.0.0",
+ "eslint": "^7.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
+ "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "grunt-known-options": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz",
+ "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==",
+ "dev": true
+ },
+ "grunt-legacy-log": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz",
+ "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==",
+ "dev": true,
+ "requires": {
+ "colors": "~1.1.2",
+ "grunt-legacy-log-utils": "~2.1.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.19"
+ }
+ },
+ "grunt-legacy-log-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz",
+ "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==",
+ "dev": true,
+ "requires": {
+ "chalk": "~4.1.0",
+ "lodash": "~4.17.19"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "grunt-legacy-util": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.0.tgz",
+ "integrity": "sha512-ZEmYFB44bblwPE2oz3q3ygfF6hseQja9tx8I3UZIwbUik32FMWewA+d1qSFicMFB+8dNXDkh35HcDCWlpRsGlA==",
+ "dev": true,
+ "requires": {
+ "async": "~1.5.2",
+ "exit": "~0.1.1",
+ "getobject": "~0.1.0",
+ "hooker": "~0.2.3",
+ "lodash": "~4.17.20",
+ "underscore.string": "~3.3.5",
+ "which": "~1.3.0"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ }
+ }
+ },
+ "grunt-stylelint": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/grunt-stylelint/-/grunt-stylelint-0.15.0.tgz",
+ "integrity": "sha512-1G5kbT3Y6OtAqgIv/XErtI6ai1t1UdtQWXxUV5Gd900PQoEzu/WrBYhGNAXdb/9nAsNWNjFHQjtdXQtZcDmobA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "hard-rejection": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+ "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "hooker": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+ "dev": true
+ },
+ "hosted-git-info": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
+ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+ "dev": true
+ },
+ "html-tags": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
+ "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
+ "dev": true
+ },
+ "htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
+ },
+ "import-fresh": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz",
+ "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==",
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
+ "import-lazy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+ "dev": true
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+ },
+ "indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true
+ },
+ "interpret": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
+ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
+ "dev": true
+ },
+ "is-absolute": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+ "dev": true,
+ "requires": {
+ "is-relative": "^1.0.0",
+ "is-windows": "^1.0.1"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-alphabetical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+ "dev": true
+ },
+ "is-alphanumeric": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+ "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=",
+ "dev": true
+ },
+ "is-alphanumerical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+ "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+ "dev": true,
+ "requires": {
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0"
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-buffer": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
+ "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
+ "dev": true
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-decimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+ "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "dev": true
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-hexadecimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-regexp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
+ "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==",
+ "dev": true
+ },
+ "is-relative": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+ "dev": true,
+ "requires": {
+ "is-unc-path": "^1.0.0"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "is-unc-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+ "dev": true,
+ "requires": {
+ "unc-path-regex": "^0.1.2"
+ }
+ },
+ "is-whitespace-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+ "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+ "dev": true
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "is-word-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+ "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsdoctypeparser": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz",
+ "integrity": "sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==",
+ "dev": true
+ },
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
+ },
+ "json5": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
+ "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "jsonc-parser": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.0.tgz",
+ "integrity": "sha512-b0EBt8SWFNnixVdvoR2ZtEGa9ZqLhbJnOjezn+WP+8kspFm+PFYDN8Z4Bc7pRlDjvuVcADSUkroIuTWWn/YiIA==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ },
+ "known-css-properties": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.18.0.tgz",
+ "integrity": "sha512-69AgJ1rQa7VvUsd2kpvVq+VeObDuo3zrj0CzM5Slmf6yduQFAI2kXPDQJR2IE/u6MSAUOJrwSzjg5vlz8qcMiw==",
+ "dev": true
+ },
+ "leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true
+ },
+ "levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "requires": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ }
+ },
+ "liftoff": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
+ "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=",
+ "dev": true,
+ "requires": {
+ "extend": "^3.0.0",
+ "findup-sync": "^2.0.0",
+ "fined": "^1.0.1",
+ "flagged-respawn": "^1.0.0",
+ "is-plain-object": "^2.0.4",
+ "object.map": "^1.0.0",
+ "rechoir": "^0.6.2",
+ "resolve": "^1.1.7"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "findup-sync": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+ "dev": true,
+ "requires": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^3.1.0",
+ "micromatch": "^3.0.4",
+ "resolve-dir": "^1.0.1"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ }
+ }
+ },
+ "lines-and-columns": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "dependencies": {
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ }
+ }
+ },
+ "lodash": {
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
+ },
+ "log-symbols": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
+ "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2"
+ }
+ },
+ "longest-streak": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+ "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+ "dev": true
+ },
+ "make-iterator": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.2"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+ "dev": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "markdown-escapes": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+ "dev": true
+ },
+ "markdown-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+ "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+ "dev": true,
+ "requires": {
+ "repeat-string": "^1.0.0"
+ }
+ },
+ "mathml-tag-names": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
+ "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
+ "dev": true
+ },
+ "mdast-util-compact": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz",
+ "integrity": "sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "merge2": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz",
+ "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
+ "min-indent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz",
+ "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ },
+ "minimist-options": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.0.2.tgz",
+ "integrity": "sha512-seq4hpWkYSUh1y7NXxzucwAN9yVlBc3Upgdjz8vLCP97jG8kaOmzYrVH/m7tQ1NYD1wdtZbSLfdy4zFmRWuc/w==",
+ "dev": true,
+ "requires": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0"
+ },
+ "dependencies": {
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+ "dev": true
+ }
+ }
+ },
+ "mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
+ "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
+ },
+ "node-releases": {
+ "version": "1.1.53",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz",
+ "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==",
+ "dev": true
+ },
+ "nopt": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+ "dev": true
+ },
+ "normalize-selector": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
+ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
+ "dev": true
+ },
+ "num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+ "dev": true
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.defaults": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
+ "dev": true,
+ "requires": {
+ "array-each": "^1.0.1",
+ "array-slice": "^1.0.0",
+ "for-own": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
+ "dev": true,
+ "requires": {
+ "for-own": "^1.0.0",
+ "make-iterator": "^1.0.0"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "requires": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "dev": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
+ "parse-entities": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
+ "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
+ "dev": true,
+ "requires": {
+ "character-entities": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "character-reference-invalid": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-hexadecimal": "^1.0.0"
+ }
+ },
+ "parse-filepath": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
+ "dev": true,
+ "requires": {
+ "is-absolute": "^1.0.0",
+ "map-cache": "^0.2.0",
+ "path-root": "^0.1.1"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+ "dev": true
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-root": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+ "dev": true,
+ "requires": {
+ "path-root-regex": "^0.1.0"
+ }
+ },
+ "path-root-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "dev": true
+ },
+ "pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
+ "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.1.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ }
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true
+ },
+ "postcss": {
+ "version": "7.0.27",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz",
+ "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "postcss-html": {
+ "version": "0.36.0",
+ "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz",
+ "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==",
+ "dev": true,
+ "requires": {
+ "htmlparser2": "^3.10.0"
+ }
+ },
+ "postcss-less": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz",
+ "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.14"
+ }
+ },
+ "postcss-media-query-parser": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+ "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=",
+ "dev": true
+ },
+ "postcss-reporter": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz",
+ "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "lodash": "^4.17.11",
+ "log-symbols": "^2.2.0",
+ "postcss": "^7.0.7"
+ },
+ "dependencies": {
+ "log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.1"
+ }
+ }
+ }
+ },
+ "postcss-resolve-nested-selector": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
+ "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
+ "dev": true
+ },
+ "postcss-safe-parser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz",
+ "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.26"
+ }
+ },
+ "postcss-sass": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.4.tgz",
+ "integrity": "sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg==",
+ "dev": true,
+ "requires": {
+ "gonzales-pe": "^4.3.0",
+ "postcss": "^7.0.21"
+ }
+ },
+ "postcss-scss": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.0.0.tgz",
+ "integrity": "sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.0"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz",
+ "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "postcss-syntax": {
+ "version": "0.36.2",
+ "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz",
+ "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==",
+ "dev": true
+ },
+ "postcss-value-parser": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz",
+ "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
+ },
+ "progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "quick-lru": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+ "dev": true
+ },
+ "ramda": {
+ "version": "0.27.1",
+ "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz",
+ "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "rechoir": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+ "dev": true,
+ "requires": {
+ "resolve": "^1.1.6"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.5",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
+ "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
+ "dev": true
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "regexpp": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
+ "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q=="
+ },
+ "regextras": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.7.1.tgz",
+ "integrity": "sha512-9YXf6xtW+qzQ+hcMQXx95MOvfqXFgsKDZodX3qZB0x2n5Z94ioetIITsBtvJbiOyxa/6s9AtyweBLCdPmPko/w==",
+ "dev": true
+ },
+ "remark": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/remark/-/remark-12.0.0.tgz",
+ "integrity": "sha512-oX4lMIS0csgk8AEbzY0h2jdR0ngiCHOpwwpxjmRa5TqAkeknY+tkhjRJGZqnCmvyuWh55/0SW5WY3R3nn3PH9A==",
+ "dev": true,
+ "requires": {
+ "remark-parse": "^8.0.0",
+ "remark-stringify": "^8.0.0",
+ "unified": "^9.0.0"
+ }
+ },
+ "remark-parse": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.1.tgz",
+ "integrity": "sha512-Ye/5W57tdQZWsfkuVyRq9SUWRgECHnDsMuyUMzdSKpTbNPkZeGtoYfsrkeSi4+Xyl0mhcPPddHITXPcCPHrl3w==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "collapse-white-space": "^1.0.2",
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "is-word-character": "^1.0.0",
+ "markdown-escapes": "^1.0.0",
+ "parse-entities": "^2.0.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "trim": "0.0.1",
+ "trim-trailing-lines": "^1.0.0",
+ "unherit": "^1.0.4",
+ "unist-util-remove-position": "^2.0.0",
+ "vfile-location": "^3.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "remark-stringify": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-8.0.0.tgz",
+ "integrity": "sha512-cABVYVloFH+2ZI5bdqzoOmemcz/ZuhQSH6W6ZNYnLojAUUn3xtX7u+6BpnYp35qHoGr2NFBsERV14t4vCIeW8w==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "is-alphanumeric": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "longest-streak": "^2.0.1",
+ "markdown-escapes": "^1.0.0",
+ "markdown-table": "^2.0.0",
+ "mdast-util-compact": "^2.0.0",
+ "parse-entities": "^2.0.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "stringify-entities": "^3.0.0",
+ "unherit": "^1.0.4",
+ "xtend": "^4.0.1"
+ }
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "replace-ext": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz",
+ "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ },
+ "dependencies": {
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "dev": true,
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ }
+ }
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "run-parallel": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
+ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+ "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+ "dev": true
+ },
+ "set-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "dev": true
+ },
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ },
+ "dependencies": {
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ }
+ }
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-resolve": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+ "dev": true,
+ "requires": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": true
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz",
+ "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==",
+ "dev": true
+ },
+ "specificity": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz",
+ "integrity": "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==",
+ "dev": true
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
+ "state-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+ "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+ "dev": true
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
+ "dev": true
+ }
+ }
+ },
+ "stringify-entities": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.0.0.tgz",
+ "integrity": "sha512-h7NJJIssprqlyjHT2eQt2W1F+MCcNmwPGlKb0bWEdET/3N44QN3QbUF/ueKCgAssyKRZ3Br9rQ7FcXjHr0qLHw==",
+ "dev": true,
+ "requires": {
+ "character-entities-html4": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.2",
+ "is-hexadecimal": "^1.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz",
+ "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w=="
+ },
+ "style-search": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
+ "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=",
+ "dev": true
+ },
+ "stylelint": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.3.2.tgz",
+ "integrity": "sha512-kpO3/Gz2ZY40EWUwFYYkgpzhf8ZDUyKpcui5+pS0XKJBj/EMYmZpOJoL8IFAz2yApYeg91NVy5yAjE39hDzWvQ==",
+ "dev": true,
+ "requires": {
+ "@stylelint/postcss-css-in-js": "^0.37.1",
+ "@stylelint/postcss-markdown": "^0.36.1",
+ "autoprefixer": "^9.7.6",
+ "balanced-match": "^1.0.0",
+ "chalk": "^4.0.0",
+ "cosmiconfig": "^6.0.0",
+ "debug": "^4.1.1",
+ "execall": "^2.0.0",
+ "file-entry-cache": "^5.0.1",
+ "get-stdin": "^7.0.0",
+ "global-modules": "^2.0.0",
+ "globby": "^11.0.0",
+ "globjoin": "^0.1.4",
+ "html-tags": "^3.1.0",
+ "ignore": "^5.1.4",
+ "import-lazy": "^4.0.0",
+ "imurmurhash": "^0.1.4",
+ "known-css-properties": "^0.18.0",
+ "leven": "^3.1.0",
+ "lodash": "^4.17.15",
+ "log-symbols": "^3.0.0",
+ "mathml-tag-names": "^2.1.3",
+ "meow": "^6.1.0",
+ "micromatch": "^4.0.2",
+ "normalize-selector": "^0.2.0",
+ "postcss": "^7.0.27",
+ "postcss-html": "^0.36.0",
+ "postcss-less": "^3.1.4",
+ "postcss-media-query-parser": "^0.2.3",
+ "postcss-reporter": "^6.0.1",
+ "postcss-resolve-nested-selector": "^0.1.1",
+ "postcss-safe-parser": "^4.0.2",
+ "postcss-sass": "^0.4.4",
+ "postcss-scss": "^2.0.0",
+ "postcss-selector-parser": "^6.0.2",
+ "postcss-syntax": "^0.36.2",
+ "postcss-value-parser": "^4.0.3",
+ "resolve-from": "^5.0.0",
+ "slash": "^3.0.0",
+ "specificity": "^0.4.1",
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "style-search": "^0.1.0",
+ "sugarss": "^2.0.0",
+ "svg-tags": "^1.0.0",
+ "table": "^5.4.6",
+ "v8-compile-cache": "^2.1.0",
+ "write-file-atomic": "^3.0.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "camelcase-keys": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+ "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.3.1",
+ "map-obj": "^4.0.0",
+ "quick-lru": "^4.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
+ "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "get-stdin": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
+ "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "ignore": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
+ "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "map-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz",
+ "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==",
+ "dev": true
+ },
+ "meow": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.0.tgz",
+ "integrity": "sha512-iIAoeI01v6pmSfObAAWFoITAA4GgiT45m4SmJgoxtZfvI0fyZwhV4d0lTwiUXvAKIPlma05Feb2Xngl52Mj5Cg==",
+ "dev": true,
+ "requires": {
+ "@types/minimist": "^1.2.0",
+ "camelcase-keys": "^6.1.1",
+ "decamelize-keys": "^1.1.0",
+ "hard-rejection": "^2.0.0",
+ "minimist-options": "^4.0.1",
+ "normalize-package-data": "^2.5.0",
+ "read-pkg-up": "^7.0.0",
+ "redent": "^3.0.0",
+ "trim-newlines": "^3.0.0",
+ "type-fest": "^0.8.1",
+ "yargs-parser": "^18.1.1"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "parse-json": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
+ "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dev": true,
+ "requires": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "dev": true
+ }
+ }
+ },
+ "read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ }
+ },
+ "redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dev": true,
+ "requires": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "requires": {
+ "min-indent": "^1.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "trim-newlines": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz",
+ "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==",
+ "dev": true
+ }
+ }
+ },
+ "stylelint-config-wikimedia": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/stylelint-config-wikimedia/-/stylelint-config-wikimedia-0.10.1.tgz",
+ "integrity": "sha512-R/E7xVKwDyneKmVwkNi+TqJlXZjnL5IH+bQPmfHrgwwyAekNx5GdYZ+tVjx7VBXdv/pjOr0HevVpXSQe86ZfVQ==",
+ "dev": true,
+ "requires": {
+ "stylelint": "13.3.2"
+ }
+ },
+ "sugarss": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz",
+ "integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.2"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "svg-tags": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
+ "dev": true
+ },
+ "table": {
+ "version": "5.4.6",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+ "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "requires": {
+ "ajv": "^6.10.2",
+ "lodash": "^4.17.14",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ },
+ "dependencies": {
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ }
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+ },
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "dev": true
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "trim": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+ "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=",
+ "dev": true
+ },
+ "trim-trailing-lines": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
+ "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==",
+ "dev": true
+ },
+ "trough": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "requires": {
+ "prelude-ls": "^1.2.1"
+ }
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
+ },
+ "typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "dev": true,
+ "requires": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "unc-path-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
+ "dev": true
+ },
+ "underscore.string": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
+ "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "^1.0.3",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "unherit": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+ "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "unified": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-9.0.0.tgz",
+ "integrity": "sha512-ssFo33gljU3PdlWLjNp15Inqb77d6JnJSfyplGJPT/a+fNRNyCBeveBAYJdO5khKdF6WVHa/yYCC7Xl6BDwZUQ==",
+ "dev": true,
+ "requires": {
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-buffer": "^2.0.0",
+ "is-plain-obj": "^2.0.0",
+ "trough": "^1.0.0",
+ "vfile": "^4.0.0"
+ }
+ },
+ "union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ }
+ },
+ "uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+ "dev": true
+ },
+ "unist-util-find-all-after": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.1.tgz",
+ "integrity": "sha512-0GICgc++sRJesLwEYDjFVJPJttBpVQaTNgc6Jw0Jhzvfs+jtKePEMu+uD+PqkRUrAvGQqwhpDwLGWo1PK8PDEw==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^4.0.0"
+ }
+ },
+ "unist-util-is": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz",
+ "integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==",
+ "dev": true
+ },
+ "unist-util-remove-position": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz",
+ "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "unist-util-stringify-position": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+ "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.2"
+ }
+ },
+ "unist-util-visit": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.2.tgz",
+ "integrity": "sha512-HoHNhGnKj6y+Sq+7ASo2zpVdfdRifhTgX2KTU3B/sO/TTlZchp7E3S4vjRzDJ7L60KmrCPsQkVK3lEF3cz36XQ==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^4.0.0",
+ "unist-util-visit-parents": "^3.0.0"
+ }
+ },
+ "unist-util-visit-parents": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.0.2.tgz",
+ "integrity": "sha512-yJEfuZtzFpQmg1OSCyS9M5NJRrln/9FbYosH3iW0MG402QbdbaB8ZESwUv9RO6nRfLAKvWcMxCwdLWOov36x/g==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^4.0.0"
+ }
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true
+ }
+ }
+ },
+ "upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "v8-compile-cache": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
+ "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g=="
+ },
+ "v8flags": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz",
+ "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==",
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "vfile": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.1.0.tgz",
+ "integrity": "sha512-BaTPalregj++64xbGK6uIlsurN3BCRNM/P2Pg8HezlGzKd1O9PrwIac6bd9Pdx2uTb0QHoioZ+rXKolbVXEgJg==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "is-buffer": "^2.0.0",
+ "replace-ext": "1.0.0",
+ "unist-util-stringify-position": "^2.0.0",
+ "vfile-message": "^2.0.0"
+ }
+ },
+ "vfile-location": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.0.1.tgz",
+ "integrity": "sha512-yYBO06eeN/Ki6Kh1QAkgzYpWT1d3Qln+ZCtSbJqFExPl1S3y2qqotJQXoh6qEvl/jDlgpUJolBn3PItVnnZRqQ==",
+ "dev": true
+ },
+ "vfile-message": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+ "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-stringify-position": "^2.0.0"
+ }
+ },
+ "vscode-json-languageservice": {
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-3.8.3.tgz",
+ "integrity": "sha512-8yPag/NQHCuTthahyaTtzK0DHT0FKM/xBU0mFBQ8nMo8C1i2P+FCyIVqICoNoHkRI2BTGlXKomPUpsqjSz0TnQ==",
+ "dev": true,
+ "requires": {
+ "jsonc-parser": "^2.2.1",
+ "vscode-languageserver-textdocument": "^1.0.1",
+ "vscode-languageserver-types": "^3.15.1",
+ "vscode-nls": "^4.1.2",
+ "vscode-uri": "^2.1.2"
+ }
+ },
+ "vscode-languageserver-textdocument": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.1.tgz",
+ "integrity": "sha512-UIcJDjX7IFkck7cSkNNyzIz5FyvpQfY7sdzVy+wkKN/BLaD4DQ0ppXQrKePomCxTS7RrolK1I0pey0bG9eh8dA==",
+ "dev": true
+ },
+ "vscode-languageserver-types": {
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz",
+ "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==",
+ "dev": true
+ },
+ "vscode-nls": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-4.1.2.tgz",
+ "integrity": "sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==",
+ "dev": true
+ },
+ "vscode-uri": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz",
+ "integrity": "sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==",
+ "dev": true
+ },
+ "vue-eslint-parser": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.1.0.tgz",
+ "integrity": "sha512-Kr21uPfthDc63nDl27AGQEhtt9VrZ9nkYk/NTftJ2ws9XiJwzJJCnCr3AITQ2jpRMA0XPGDECxYH8E027qMK9Q==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "eslint-scope": "^5.0.0",
+ "eslint-visitor-keys": "^1.1.0",
+ "espree": "^6.2.1",
+ "esquery": "^1.0.1",
+ "lodash": "^4.17.15"
+ },
+ "dependencies": {
+ "espree": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
+ "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+ "dev": true,
+ "requires": {
+ "acorn": "^7.1.1",
+ "acorn-jsx": "^5.2.0",
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ }
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "write-file-atomic": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+ "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "dev": true,
+ "requires": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
+ "yaml": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.9.2.tgz",
+ "integrity": "sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ }
+ }
+ }
+ }
+}
diff --git a/CheckUser/package.json b/CheckUser/package.json
index 050b19b5..bd882af1 100644
--- a/CheckUser/package.json
+++ b/CheckUser/package.json
@@ -7,10 +7,11 @@
"test": "grunt test"
},
"devDependencies": {
- "eslint-config-wikimedia": "0.5.0",
- "grunt": "1.0.3",
- "grunt-banana-checker": "0.6.0",
- "grunt-eslint": "20.1.0",
- "grunt-jsonlint": "1.1.0"
+ "eslint-config-wikimedia": "0.17.0",
+ "grunt": "1.3.0",
+ "grunt-banana-checker": "0.9.0",
+ "grunt-eslint": "23.0.0",
+ "grunt-stylelint": "0.15.0",
+ "stylelint-config-wikimedia": "0.10.1"
}
}
diff --git a/CheckUser/src/ChangeService.php b/CheckUser/src/ChangeService.php
new file mode 100644
index 00000000..19b904e2
--- /dev/null
+++ b/CheckUser/src/ChangeService.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Wikimedia\IPUtils;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+abstract class ChangeService {
+ /** @var ILoadBalancer */
+ protected $loadBalancer;
+
+ /** @var UserManager */
+ protected $userManager;
+
+ /**
+ * @param ILoadBalancer $loadBalancer
+ * @param UserManager $userManager
+ */
+ public function __construct(
+ ILoadBalancer $loadBalancer,
+ UserManager $userManager
+ ) {
+ $this->loadBalancer = $loadBalancer;
+ $this->userManager = $userManager;
+ }
+
+ /**
+ * Builds a query predicate depending on what type of
+ * target is passed in
+ *
+ * @param string[] $targets
+ * @return string[]
+ */
+ protected function buildTargetCondsMultiple( array $targets ) : array {
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+
+ $condSet = array_map( function ( $target ) {
+ return $this->buildTargetConds( $target );
+ }, $targets );
+
+ if ( !$condSet ) {
+ return [
+ $db->addQuotes( false )
+ ];
+ }
+
+ $conds = array_merge_recursive( ...$condSet );
+
+ if ( !$conds ) {
+ return [
+ $db->addQuotes( false )
+ ];
+ }
+
+ return [
+ $db->makeList( $conds, IDatabase::LIST_OR ),
+ ];
+ }
+
+ /**
+ * Builds a query predicate depending on what type of
+ * target is passed in
+ *
+ * @param string $target
+ * @return string[]
+ */
+ protected function buildTargetConds( $target ) : array {
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+ $conds = [];
+
+ if ( IPUtils::isIpAddress( $target ) ) {
+ if ( IPUtils::isValid( $target ) ) {
+ $conds['cuc_ip_hex'] = IPUtils::toHex( $target );
+ } elseif ( IPUtils::isValidRange( $target ) ) {
+ $range = IPUtils::parseRange( $target );
+ $conds[] = $db->makeList( [
+ 'cuc_ip_hex >= ' . $db->addQuotes( $range[0] ),
+ 'cuc_ip_hex <= ' . $db->addQuotes( $range[1] )
+ ], IDatabase::LIST_AND );
+ }
+ } else {
+ // TODO: This may filter out invalid values, changing the number of
+ // targets. The per-target limit should change too (T246393).
+ $userId = $this->userManager->idFromName( $target );
+ if ( $userId ) {
+ $conds['cuc_user'] = $userId;
+ }
+ }
+
+ return $conds;
+ }
+
+ /**
+ * @param string[] $targets
+ * @return array
+ */
+ protected function buildExcludeTargetsConds( array $targets ) : array {
+ $conds = [];
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+
+ $ipTargets = [];
+ $userTargets = [];
+
+ foreach ( $targets as $target ) {
+ if ( IPUtils::isIpAddress( $target ) ) {
+ $ipTargets[] = IPUtils::toHex( $target );
+ } else {
+ $userId = $this->userManager->idFromName( $target );
+ if ( $userId ) {
+ $userTargets[] = $userId;
+ }
+ }
+ }
+
+ if ( count( $ipTargets ) > 0 ) {
+ $conds[] = 'cuc_ip_hex NOT IN (' . $db->makeList( $ipTargets ) . ')';
+ }
+ if ( count( $userTargets ) > 0 ) {
+ $conds[] = 'cuc_user NOT IN (' . $db->makeList( $userTargets ) . ')';
+ }
+
+ return $conds;
+ }
+
+ /**
+ * Build conditions for the start timeestamp.
+ *
+ * @param string $start timestamp
+ * @return array conditions
+ */
+ protected function buildStartConds( string $start ) : array {
+ if ( $start === '' ) {
+ return [];
+ }
+
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+ return [
+ 'cuc_timestamp >= ' . $db->addQuotes( $start ),
+ ];
+ }
+}
diff --git a/CheckUser/src/ComparePager.php b/CheckUser/src/ComparePager.php
new file mode 100644
index 00000000..e3de207c
--- /dev/null
+++ b/CheckUser/src/ComparePager.php
@@ -0,0 +1,337 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+namespace MediaWiki\CheckUser;
+
+use DateTime;
+use Html;
+use IContextSource;
+use Linker;
+use MediaWiki\Linker\LinkRenderer;
+use TablePager;
+use Wikimedia\IPUtils;
+use Wikimedia\Rdbms\FakeResultWrapper;
+
+class ComparePager extends TablePager {
+ /** @var CompareService */
+ private $compareService;
+
+ /** @var TokenQueryManager */
+ private $tokenQueryManager;
+
+ /** @var array */
+ private $fieldNames;
+
+ /**
+ * Holds a cache of iphex => edit-count to avoid
+ * recurring queries to the database for the same ip
+ *
+ * @var array
+ */
+ private $ipTotalEdits;
+
+ /**
+ * Targets whose results should not be included in the investigation.
+ * Targets in this list may or may not also be in the $targets list.
+ * Either way, no activity related to these targets will appear in the
+ * results.
+ *
+ * @var string[]
+ */
+ private $excludeTargets;
+
+ /**
+ * Targets that have been added to the investigation but that are not
+ * present in $excludeTargets. These are the targets that will actually
+ * be investigated.
+ *
+ * @var string[]
+ */
+ private $filteredTargets;
+
+ /** @var string */
+ private $start;
+
+ public function __construct(
+ IContextSource $context,
+ LinkRenderer $linkRenderer,
+ TokenQueryManager $tokenQueryManager,
+ DurationManager $durationManager,
+ CompareService $compareService
+ ) {
+ parent::__construct( $context, $linkRenderer );
+ $this->compareService = $compareService;
+ $this->tokenQueryManager = $tokenQueryManager;
+
+ $tokenData = $tokenQueryManager->getDataFromRequest( $context->getRequest() );
+ $this->mOffset = $tokenData['offset'] ?? '';
+
+ $this->excludeTargets = $tokenData['exclude-targets'] ?? [];
+ $this->filteredTargets = array_diff(
+ $tokenData['targets'] ?? [],
+ $this->excludeTargets
+ );
+
+ $this->start = $durationManager->getTimestampFromRequest( $context->getRequest() );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getTableClass() {
+ $sortableClass = $this->mIsFirst && $this->mIsLast ? 'sortable' : '';
+ return implode( ' ', [
+ parent::getTableClass(),
+ $sortableClass,
+ 'ext-checkuser-investigate-table',
+ 'ext-checkuser-investigate-table-compare'
+ ] );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getCellAttrs( $field, $value ) {
+ $attributes = parent::getCellAttrs( $field, $value );
+ $attributes['class'] = $attributes['class'] ?? '';
+
+ $row = $this->mCurrentRow;
+ switch ( $field ) {
+ case 'cuc_ip':
+ foreach ( $this->filteredTargets as $target ) {
+ if ( !IPUtils::isIPAddress( $target ) ) {
+ continue;
+ }
+
+ if ( IPUtils::isValidRange( $target ) && IPUtils::isInRange( $value, $target ) ) {
+ $attributes['class'] .= ' ext-checkuser-compare-table-cell-target';
+ break;
+ } elseif ( IPUtils::toHex( $target ) === $row->cuc_ip_hex ) {
+ $attributes['class'] .= ' ext-checkuser-compare-table-cell-target';
+ break;
+ }
+ }
+ $ipHex = IPUtils::toHex( $value );
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-interactive';
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-pinnable';
+ $attributes['class'] .= ' ext-checkuser-compare-table-cell-ip-target';
+ $attributes['data-field'] = $field;
+ $attributes['data-value'] = $value;
+ $attributes['data-sort-value'] = $ipHex;
+ $attributes['data-edits'] = $row->total_edits;
+ $attributes['data-all-edits'] = $this->ipTotalEdits[$ipHex];
+ break;
+ case 'cuc_user_text':
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-interactive';
+ if ( !IPUtils::isIpAddress( $value ) ) {
+ $attributes['class'] .= ' ext-checkuser-compare-table-cell-user-target';
+ if ( in_array( $value, $this->filteredTargets ) ) {
+ $attributes['class'] .= ' ext-checkuser-compare-table-cell-target';
+ }
+ $attributes['data-field'] = $field;
+ $attributes['data-value'] = $value;
+ }
+ // Store the sort value as an attribute, to avoid using the table cell contents
+ // as the sort value, since UI elements are added to the table cell.
+ $attributes['data-sort-value'] = $value;
+ break;
+ case 'cuc_agent':
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-interactive';
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-pinnable';
+ $attributes['class'] .= ' ext-checkuser-compare-table-cell-user-agent';
+ $attributes['data-field'] = $field;
+ $attributes['data-value'] = $value;
+ // Store the sort value as an attribute, to avoid using the table cell contents
+ // as the sort value, since UI elements are added to the table cell.
+ $attributes['data-sort-value'] = $value;
+ break;
+ case 'activity':
+ $attributes['class'] .= ' ext-checkuser-compare-table-cell-activity';
+ $start = new DateTime( $row->first_edit );
+ $end = new DateTime( $row->last_edit );
+ $attributes['data-sort-value'] = $start->format( 'Ymd' ) . $end->format( 'Ymd' );
+ break;
+ }
+
+ // Add each cell to the tab index.
+ $attributes['tabindex'] = 0;
+
+ return $attributes;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ * @return string
+ */
+ public function formatValue( $name, $value ) {
+ $language = $this->getLanguage();
+ $row = $this->mCurrentRow;
+
+ switch ( $name ) {
+ case 'cuc_user_text':
+ if ( IPUtils::isValid( $value ) ) {
+ $formatted = $this->msg( 'checkuser-investigate-compare-table-cell-unregistered' );
+ } else {
+ $formatted = Linker::userLink( $row->cuc_user, $value );
+ }
+ break;
+ case 'cuc_ip':
+ $formatted = Html::rawElement(
+ 'span',
+ [ 'class' => "ext-checkuser-compare-table-cell-ip" ],
+ htmlspecialchars( $value )
+ );
+
+ // get other edits
+ $otherEdits = '';
+ $ipHex = $row->cuc_ip_hex;
+ if ( !isset( $this->ipTotalEdits[$ipHex] ) ) {
+ $this->ipTotalEdits[$ipHex] = $this->compareService->getTotalEditsFromIp( $ipHex );
+ }
+
+ if ( $this->ipTotalEdits[$ipHex] ) {
+ $otherEdits = Html::rawElement(
+ 'span',
+ [],
+ $this->msg(
+ 'checkuser-investigate-compare-table-cell-other-edits',
+ $this->ipTotalEdits[$ipHex]
+ )->parse()
+ );
+ }
+
+ $formatted .= Html::rawElement(
+ 'div',
+ [],
+ $this->msg(
+ 'checkuser-investigate-compare-table-cell-edits',
+ $row->total_edits
+ )->parse() . $otherEdits
+ );
+
+ break;
+ case 'cuc_agent':
+ $formatted = htmlspecialchars( $value );
+ break;
+ case 'activity':
+ $firstEdit = $language->userDate( $row->first_edit, $this->getUser() );
+ $lastEdit = $language->userDate( $row->last_edit, $this->getUser() );
+ $formatted = htmlspecialchars( $firstEdit . ' - ' . $lastEdit );
+ break;
+ default:
+ $formatted = '';
+ }
+
+ return $formatted;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getIndexField() {
+ return [ [ 'cuc_user_text', 'cuc_ip_hex', 'cuc_agent' ] ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFieldNames() {
+ if ( $this->fieldNames === null ) {
+ $this->fieldNames = [
+ 'cuc_user_text' => 'checkuser-investigate-compare-table-header-username',
+ 'cuc_ip' => 'checkuser-investigate-compare-table-header-ip',
+ 'cuc_agent' => 'checkuser-investigate-compare-table-header-useragent',
+ 'activity' => 'checkuser-investigate-compare-table-header-activity',
+ ];
+ foreach ( $this->fieldNames as $key => $val ) {
+ $this->fieldNames[$key] = $this->msg( $val )->text();
+ }
+ }
+ return $this->fieldNames;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Handle special case where all targets are filtered.
+ */
+ public function doQuery() {
+ // If there are no targets, there is no need to run the query and an empty result can be used.
+ if ( $this->filteredTargets === [] ) {
+ $this->mResult = new FakeResultWrapper( [] );
+ $this->mQueryDone = true;
+ return $this->mResult;
+ }
+
+ return parent::doQuery();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getQueryInfo() {
+ return $this->compareService->getQueryInfo(
+ $this->filteredTargets,
+ $this->excludeTargets,
+ $this->start
+ );
+ }
+
+ /**
+ * Check if we have incomplete data for any of the targets.
+ *
+ * @return string[] Targets whose limits were exceeded (if any)
+ */
+ public function getTargetsOverLimit() : array {
+ return $this->compareService->getTargetsOverLimit(
+ $this->filteredTargets,
+ $this->excludeTargets,
+ $this->start
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isFieldSortable( $field ) {
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDefaultSort() {
+ return '';
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Conceal the offset which may reveal private data.
+ */
+ public function getPagingQueries() {
+ return $this->tokenQueryManager->getPagingQueries(
+ $this->getRequest(), parent::getPagingQueries()
+ );
+ }
+}
diff --git a/CheckUser/src/ComparePagerFactory.php b/CheckUser/src/ComparePagerFactory.php
new file mode 100644
index 00000000..78cf28cc
--- /dev/null
+++ b/CheckUser/src/ComparePagerFactory.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use MediaWiki\Linker\LinkRenderer;
+
+class ComparePagerFactory implements PagerFactory {
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ /** @var TokenQueryManager */
+ private $tokenQueryManager;
+
+ /** @var DurationManager */
+ private $durationManager;
+
+ /** @var CompareService */
+ private $compare;
+
+ /**
+ * @param LinkRenderer $linkRenderer
+ * @param TokenQueryManager $tokenQueryManager
+ * @param DurationManager $durationManager
+ * @param CompareService $compare
+ */
+ public function __construct(
+ LinkRenderer $linkRenderer,
+ TokenQueryManager $tokenQueryManager,
+ DurationManager $durationManager,
+ CompareService $compare
+ ) {
+ $this->linkRenderer = $linkRenderer;
+ $this->tokenQueryManager = $tokenQueryManager;
+ $this->durationManager = $durationManager;
+ $this->compare = $compare;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function createPager( \IContextSource $context ) : ComparePager {
+ return new ComparePager(
+ $context,
+ $this->linkRenderer,
+ $this->tokenQueryManager,
+ $this->durationManager,
+ $this->compare
+ );
+ }
+}
diff --git a/CheckUser/src/CompareService.php b/CheckUser/src/CompareService.php
new file mode 100644
index 00000000..f1ab687e
--- /dev/null
+++ b/CheckUser/src/CompareService.php
@@ -0,0 +1,220 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Wikimedia\Rdbms\ILoadBalancer;
+use Wikimedia\Rdbms\Subquery;
+
+class CompareService extends ChangeService {
+ /** @var int */
+ private $limit;
+
+ /**
+ * @param ILoadBalancer $loadBalancer
+ * @param UserManager $userManager
+ * @param int $limit Maximum number of rows to access (T245499)
+ */
+ public function __construct(
+ ILoadBalancer $loadBalancer,
+ UserManager $userManager,
+ $limit = 100000
+ ) {
+ parent::__construct( $loadBalancer, $userManager );
+ $this->limit = $limit;
+ }
+
+ /**
+ * Get edits made from an ip
+ *
+ * @param string $ipHex
+ * @param string|null $excludeUser
+ * @return int
+ */
+ public function getTotalEditsFromIp(
+ string $ipHex,
+ string $excludeUser = null
+ ) : int {
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+ $conds = [
+ 'cuc_ip_hex' => $ipHex,
+ 'cuc_type' => [ RC_EDIT, RC_NEW ],
+ ];
+
+ if ( $excludeUser ) {
+ $conds[] = 'cuc_user_text != ' . $db->addQuotes( $excludeUser );
+ }
+
+ return $db->selectRowCount( 'cu_changes', '*', $conds, __METHOD__ );
+ }
+
+ /**
+ * Get the compare query info
+ *
+ * @param string[] $targets
+ * @param string[] $excludeTargets
+ * @param string $start
+ * @return array
+ */
+ public function getQueryInfo( array $targets, array $excludeTargets, string $start ): array {
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+
+ if ( $targets === [] ) {
+ throw new \LogicException( 'Cannot get query info when $targets is empty.' );
+ }
+ $limit = (int)( $this->limit / count( $targets ) );
+
+ $sqlText = [];
+ foreach ( $targets as $target ) {
+ $info = $this->getQueryInfoForSingleTarget( $target, $excludeTargets, $start, $limit );
+ if ( $info !== null ) {
+ if ( !$db->unionSupportsOrderAndLimit() ) {
+ unset( $info['options']['ORDER BY'], $info['options']['LIMIT'] );
+ }
+
+ $sqlText[] = $db->selectSQLText(
+ $info['tables'],
+ $info['fields'],
+ $info['conds'],
+ __METHOD__,
+ $info['options']
+ );
+ }
+ }
+
+ $derivedTable = $db->unionQueries( $sqlText, $db::UNION_DISTINCT );
+
+ return [
+ 'tables' => [ 'a' => new Subquery( $derivedTable ) ],
+ 'fields' => [
+ 'cuc_user' => 'a.cuc_user',
+ 'cuc_user_text' => 'a.cuc_user_text',
+ 'cuc_ip' => 'a.cuc_ip',
+ 'cuc_ip_hex' => 'a.cuc_ip_hex',
+ 'cuc_agent' => 'a.cuc_agent',
+ 'first_edit' => 'MIN(a.cuc_timestamp)',
+ 'last_edit' => 'MAX(a.cuc_timestamp)',
+ 'total_edits' => 'count(*)',
+ ],
+ 'options' => [
+ 'GROUP BY' => [
+ 'cuc_user_text',
+ 'cuc_ip_hex',
+ 'cuc_agent',
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Get the query info for a single target.
+ *
+ * For the main investigation, this becomes a subquery that contributes to a derived
+ * table, used by getQueryInfo.
+ *
+ * For a limit check, this query is used to check whether the number of results for
+ * the target exceed the limit-per-target in getQueryInfo.
+ *
+ * @param string $target
+ * @param string[] $excludeTargets
+ * @param string $start
+ * @param int $limitPerTarget
+ * @param bool $limitCheck
+ * @return array|null Return null for invalid target
+ */
+ public function getQueryInfoForSingleTarget(
+ string $target,
+ array $excludeTargets,
+ string $start,
+ int $limitPerTarget,
+ $limitCheck = false
+ ) : ?array {
+ if ( $limitCheck ) {
+ $orderBy = null;
+ $offset = $limitPerTarget;
+ $limit = 1;
+ } else {
+ $orderBy = 'cuc_timestamp DESC';
+ $offset = null;
+ $limit = $limitPerTarget;
+ }
+
+ $conds = $this->buildTargetConds( $target );
+ if ( $conds === [] ) {
+ return null;
+ }
+
+ $conds = array_merge(
+ $conds,
+ $this->buildExcludeTargetsConds( $excludeTargets ),
+ $this->buildStartConds( $start )
+ );
+
+ $conds['cuc_type'] = [ RC_EDIT, RC_NEW ];
+
+ return [
+ 'tables' => 'cu_changes',
+ 'fields' => [
+ 'cuc_id',
+ 'cuc_user',
+ 'cuc_user_text',
+ 'cuc_ip',
+ 'cuc_ip_hex',
+ 'cuc_agent',
+ 'cuc_timestamp',
+ ],
+ 'conds' => $conds,
+ 'options' => [
+ 'ORDER BY' => $orderBy,
+ 'LIMIT' => $limit,
+ 'OFFSET' => $offset,
+ ],
+ ];
+ }
+
+ /**
+ * Check if we have incomplete data for any of the targets.
+ *
+ * @param string[] $targets
+ * @param string[] $excludeTargets
+ * @param string $start
+ * @return string[]
+ */
+ public function getTargetsOverLimit(
+ array $targets,
+ array $excludeTargets,
+ string $start
+ ) : array {
+ if ( $targets === [] ) {
+ return $targets;
+ }
+
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+
+ // If the database does not support order and limit on a UNION
+ // then none of the targets can be over the limit.
+ if ( !$db->unionSupportsOrderAndLimit() ) {
+ return [];
+ }
+
+ $targetsOverLimit = [];
+ $offset = (int)( $this->limit / count( $targets ) );
+
+ foreach ( $targets as $target ) {
+ $info = $this->getQueryInfoForSingleTarget( $target, $excludeTargets, $start, $offset, true );
+ if ( $info !== null ) {
+ $limitCheck = $db->select(
+ $info['tables'],
+ $info['fields'],
+ $info['conds'],
+ __METHOD__,
+ $info['options']
+ );
+ if ( $limitCheck->numRows() > 0 ) {
+ $targetsOverLimit[] = $target;
+ }
+ }
+ }
+
+ return $targetsOverLimit;
+ }
+}
diff --git a/CheckUser/src/DurationManager.php b/CheckUser/src/DurationManager.php
new file mode 100644
index 00000000..8755bb98
--- /dev/null
+++ b/CheckUser/src/DurationManager.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+class DurationManager {
+
+ /**
+ * Retrieves a valid duration from the request.
+ *
+ * @param \WebRequest $request
+ * @return string
+ */
+ public function getFromRequest( \WebRequest $request ) : string {
+ $value = $request->getVal( 'duration', '' );
+
+ if ( !$this->isValid( $value ) ) {
+ return '';
+ }
+
+ return $value;
+ }
+
+ /**
+ * Return the timestamp from the duration.
+ *
+ * @param \WebRequest $request
+ * @return string
+ */
+ public function getTimestampFromRequest( \WebRequest $request ) : string {
+ $duration = $this->getFromRequest( $request );
+ if ( $duration === '' ) {
+ return $duration;
+ }
+
+ try {
+ $interval = new \DateInterval( $duration );
+ $now = \DateTime::createFromFormat( 'U', (string)\MWTimestamp::time() );
+ return \MWTimestamp::convert( TS_MW, $now->sub( $interval ) );
+ } catch ( \Exception $e ) {
+ return '';
+ }
+ }
+
+ /**
+ * Determine if duration is valid.
+ *
+ * @param string $value
+ * @return bool
+ */
+ public function isValid( string $value ) : bool {
+ // No value implies "all"
+ if ( $value === '' ) {
+ return true;
+ }
+
+ try {
+ $interval = new \DateInterval( $value );
+ return true;
+ } catch ( \Exception $e ) {
+ return false;
+ }
+ }
+}
diff --git a/CheckUser/src/EventLogger.php b/CheckUser/src/EventLogger.php
new file mode 100644
index 00000000..d94d9855
--- /dev/null
+++ b/CheckUser/src/EventLogger.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use EventLogging;
+use ExtensionRegistry;
+
+class EventLogger {
+ /** @var ExtensionRegistry */
+ private $extensionRegistry;
+
+ /**
+ * @param ExtensionRegistry $extensionRegistry
+ */
+ public function __construct(
+ ExtensionRegistry $extensionRegistry
+ ) {
+ $this->extensionRegistry = $extensionRegistry;
+ }
+
+ /**
+ * Log an event using the SpecialInvestigate schema.
+ *
+ * @param array $event
+ */
+ public function logEvent( $event ) : void {
+ if ( $this->extensionRegistry->isLoaded( 'EventLogging' ) ) {
+ EventLogging::logEvent(
+ 'SpecialInvestigate',
+ // Revision ID of the schema - keep this in sync with extension.json
+ 20261100,
+ $event
+ );
+ }
+ }
+
+ /**
+ * Get a timestamp in milliseconds.
+ *
+ * @return int
+ */
+ public function getTime() : int {
+ return (int)round( microtime( true ) * 1000 );
+ }
+}
diff --git a/CheckUser/src/GuidedTour/TourLauncher.php b/CheckUser/src/GuidedTour/TourLauncher.php
new file mode 100644
index 00000000..bd7ff068
--- /dev/null
+++ b/CheckUser/src/GuidedTour/TourLauncher.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace MediaWiki\CheckUser\GuidedTour;
+
+use ExtensionRegistry;
+use GuidedTourLauncher;
+use HtmlArmor;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkTarget;
+
+class TourLauncher {
+ /** @var ExtensionRegistry */
+ private $extensionRegistry;
+
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ /**
+ * @param ExtensionRegistry $extensionRegistry
+ * @param LinkRenderer $linkRenderer
+ */
+ public function __construct(
+ ExtensionRegistry $extensionRegistry,
+ LinkRenderer $linkRenderer
+ ) {
+ $this->extensionRegistry = $extensionRegistry;
+ $this->linkRenderer = $linkRenderer;
+ }
+
+ /**
+ * Launch a Guided Tour if the extension is loaded.
+ *
+ * @see GuidedTourLauncher::launchTour
+ *
+ * @param string $tourName
+ * @param string $step
+ */
+ public function launchTour( string $tourName, string $step ) : void {
+ if ( !$this->extensionRegistry->isLoaded( 'GuidedTour' ) ) {
+ return;
+ }
+
+ GuidedTourLauncher::launchTour( $tourName, $step );
+ }
+
+ /**
+ * @param string $tourName
+ * @param LinkTarget $target
+ * @param string|HtmlArmor|null $text
+ * @param array $extraAttribs
+ * @param array $query
+ * @return string HTML
+ */
+ public function makeTourLink(
+ string $tourName,
+ LinkTarget $target,
+ $text = null,
+ array $extraAttribs = [],
+ array $query = []
+ ) : string {
+ if ( !$this->extensionRegistry->isLoaded( 'GuidedTour' ) ) {
+ return '';
+ }
+
+ return $this->linkRenderer->makeLink(
+ $target,
+ $text,
+ $extraAttribs,
+ array_merge( $query, [
+ 'tour' => $tourName,
+ ] )
+ );
+ }
+}
diff --git a/CheckUser/src/Hook/CheckUserFormatRowHook.php b/CheckUser/src/Hook/CheckUserFormatRowHook.php
new file mode 100644
index 00000000..064bc043
--- /dev/null
+++ b/CheckUser/src/Hook/CheckUserFormatRowHook.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace MediaWiki\CheckUser\Hook;
+
+use IContextSource;
+
+interface CheckUserFormatRowHook {
+ /**
+ * Use this hook to modify a row in the Timeline pager for Special:Investigate.
+ *
+ * @since 1.35
+ *
+ * @param IContextSource $context
+ * @param \stdClass $row
+ * @param array &$rowItems
+ */
+ public function onCheckUserFormatRow(
+ IContextSource $context,
+ \stdClass $row,
+ array &$rowItems
+ );
+}
diff --git a/CheckUser/src/Hook/CheckUserSubtitleLinksHook.php b/CheckUser/src/Hook/CheckUserSubtitleLinksHook.php
new file mode 100644
index 00000000..b4bb48c6
--- /dev/null
+++ b/CheckUser/src/Hook/CheckUserSubtitleLinksHook.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace MediaWiki\CheckUser\Hook;
+
+use IContextSource;
+
+interface CheckUserSubtitleLinksHook {
+ /**
+ * Use this hook to modify the subtitle links on Special:Investigate.
+ *
+ * @since 1.36
+ *
+ * @param IContextSource $context
+ * @param array &$links
+ */
+ public function onCheckUserSubtitleLinks(
+ IContextSource $context,
+ array &$links
+ );
+}
diff --git a/CheckUser/src/Hook/HookRunner.php b/CheckUser/src/Hook/HookRunner.php
new file mode 100644
index 00000000..d2e4327f
--- /dev/null
+++ b/CheckUser/src/Hook/HookRunner.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace MediaWiki\CheckUser\Hook;
+
+use IContextSource;
+use MediaWiki\HookContainer\HookContainer;
+
+class HookRunner implements CheckUserFormatRowHook, CheckUserSubtitleLinksHook {
+ /** @var HookContainer */
+ private $container;
+
+ public function __construct( HookContainer $container ) {
+ $this->container = $container;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function onCheckUserFormatRow(
+ IContextSource $context,
+ \stdClass $row,
+ array &$rowItems
+ ) {
+ $this->container->run(
+ 'CheckUserFormatRow',
+ [ $context, $row, &$rowItems ]
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function onCheckUserSubtitleLinks(
+ IContextSource $context,
+ array &$links
+ ) {
+ $this->container->run(
+ 'CheckUserSubtitleLinks',
+ [ $context, &$links ]
+ );
+ }
+}
diff --git a/CheckUser/src/HookHandler/Preferences.php b/CheckUser/src/HookHandler/Preferences.php
new file mode 100644
index 00000000..2dccd619
--- /dev/null
+++ b/CheckUser/src/HookHandler/Preferences.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace MediaWiki\CheckUser\HookHandler;
+
+use MediaWiki\Preferences\Hook\GetPreferencesHook;
+
+class Preferences implements GetPreferencesHook {
+
+ /** @var string */
+ public const INVESTIGATE_TOUR_SEEN = 'checkuser-investigate-tour-seen';
+
+ /** @var string */
+ public const INVESTIGATE_FORM_TOUR_SEEN = 'checkuser-investigate-form-tour-seen';
+
+ /**
+ * @inheritDoc
+ */
+ public function onGetPreferences( $user, &$preferences ) {
+ $preferences[self::INVESTIGATE_TOUR_SEEN] = [
+ 'type' => 'api',
+ ];
+
+ $preferences[self::INVESTIGATE_FORM_TOUR_SEEN] = [
+ 'type' => 'api',
+ ];
+ }
+
+}
diff --git a/CheckUser/src/InvestigateLogPager.php b/CheckUser/src/InvestigateLogPager.php
new file mode 100644
index 00000000..c1ef047e
--- /dev/null
+++ b/CheckUser/src/InvestigateLogPager.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+namespace MediaWiki\CheckUser;
+
+use Html;
+use Linker;
+use ReverseChronologicalPager;
+
+class InvestigateLogPager extends ReverseChronologicalPager {
+ /**
+ * @inheritDoc
+ */
+ public function getIndexField() {
+ return 'cul_timestamp';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getQueryInfo() {
+ return [
+ 'tables' => [ 'cu_log', 'user' ],
+ 'fields' => [
+ 'cul_timestamp', 'cul_user', 'cul_reason',
+ 'cul_target_id', 'cul_target_text', 'user_name',
+ ],
+ 'conds' => [
+ 'cul_type' => 'investigate',
+ ],
+ 'join_conds' => [
+ 'user' => [ 'JOIN', 'cul_user = user_id' ],
+ ],
+ ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function formatRow( $row ) {
+ $checkUser = Linker::userLink( $row->cul_user, $row->user_name );
+
+ // build target links
+ $target = Linker::userLink( $row->cul_target_id, $row->cul_target_text );
+ $target .= Linker::userToolLinks( $row->cul_target_id, $row->cul_target_text );
+
+ $reason = Linker::commentBlock( $row->cul_reason );
+
+ $language = $this->getLanguage();
+ $user = $this->getUser();
+ $message = $this->msg(
+ 'checkuser-investigate-log-entry',
+ $checkUser,
+ $target,
+ $language->userTimeAndDate( wfTimestamp( TS_MW, $row->cul_timestamp ), $user ),
+ $reason
+ )->text();
+
+ return Html::rawElement( 'li', [], $message );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getStartBody() {
+ return $this->getNumRows() ? '<ul>' : '';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEndBody() {
+ return $this->getNumRows() ? '</ul>' : '';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEmptyBody() {
+ return Html::rawElement( 'p', [], $this->msg( 'checkuser-investigate-log-empty' )->text() );
+ }
+}
diff --git a/CheckUser/src/InvestigateLogPagerFactory.php b/CheckUser/src/InvestigateLogPagerFactory.php
new file mode 100644
index 00000000..2f5e5121
--- /dev/null
+++ b/CheckUser/src/InvestigateLogPagerFactory.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+namespace MediaWiki\CheckUser;
+
+use IContextSource;
+use MediaWiki\Linker\LinkRenderer;
+
+class InvestigateLogPagerFactory implements PagerFactory {
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ public function __construct( LinkRenderer $linkRenderer ) {
+ $this->linkRenderer = $linkRenderer;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function createPager( IContextSource $context ) : InvestigateLogPager {
+ return new InvestigateLogPager( $context, $this->linkRenderer );
+ }
+}
diff --git a/CheckUser/src/PagerFactory.php b/CheckUser/src/PagerFactory.php
new file mode 100644
index 00000000..c5fa56c3
--- /dev/null
+++ b/CheckUser/src/PagerFactory.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+interface PagerFactory {
+ /**
+ * Factory to create the pager
+ *
+ * @param \IContextSource $context
+ */
+ public function createPager( \IContextSource $context );
+}
diff --git a/CheckUser/src/PreliminaryCheckPager.php b/CheckUser/src/PreliminaryCheckPager.php
new file mode 100644
index 00000000..30a3c58e
--- /dev/null
+++ b/CheckUser/src/PreliminaryCheckPager.php
@@ -0,0 +1,308 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+namespace MediaWiki\CheckUser;
+
+use CentralAuthUtils;
+use ExtensionRegistry;
+use Html;
+use IContextSource;
+use MediaWiki\Linker\LinkRenderer;
+use NamespaceInfo;
+use TablePager;
+use WikiMap;
+use Wikimedia\Rdbms\FakeResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * @ingroup Pager
+ */
+class PreliminaryCheckPager extends TablePager {
+ /** @var NamespaceInfo */
+ private $namespaceInfo;
+
+ /** @var ExtensionRegistry */
+ private $extensionRegistry;
+
+ /** @var array */
+ protected $tokenData;
+
+ /** @var TokenQueryManager */
+ private $tokenQueryManager;
+
+ /** @var PreliminaryCheckService */
+ private $preliminaryCheckService;
+
+ /** @var string[] Array of column name to translated table header message */
+ private $fieldNames;
+
+ /**
+ * @param IContextSource $context
+ * @param LinkRenderer $linkRenderer
+ * @param NamespaceInfo $namespaceInfo
+ * @param TokenQueryManager $tokenQueryManager
+ * @param ExtensionRegistry $extensionRegistry
+ * @param PreliminaryCheckService $preliminaryCheckService
+ */
+ public function __construct(
+ IContextSource $context,
+ LinkRenderer $linkRenderer,
+ NamespaceInfo $namespaceInfo,
+ TokenQueryManager $tokenQueryManager,
+ ExtensionRegistry $extensionRegistry,
+ PreliminaryCheckService $preliminaryCheckService
+ ) {
+ // This must be done before getIndexField is called by the TablePager constructor
+ $this->extensionRegistry = $extensionRegistry;
+ if ( $this->isGlobalCheck() ) {
+ // @phan-suppress-next-line PhanPossiblyNullTypeMismatchProperty
+ $this->mDb = $this->getCentralReplicaDB();
+ }
+
+ parent::__construct( $context, $linkRenderer );
+ $this->namespaceInfo = $namespaceInfo;
+ $this->preliminaryCheckService = $preliminaryCheckService;
+ $this->tokenQueryManager = $tokenQueryManager;
+
+ $this->tokenData = $tokenQueryManager->getDataFromRequest( $context->getRequest() );
+ $this->mOffset = $this->tokenData['offset'] ?? '';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getTableClass() {
+ return parent::getTableClass() .
+ ' ext-checkuser-investigate-table' .
+ ' ext-checkuser-investigate-table-preliminary-check';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getCellAttrs( $field, $value ) {
+ $attributes = parent::getCellAttrs( $field, $value );
+ $attributes['class'] = $attributes['class'] ?? '';
+
+ switch ( $field ) {
+ case 'wiki':
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-interactive';
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-pinnable';
+ $attributes['data-field'] = $field;
+ $attributes['data-value'] = $value;
+ break;
+ case 'registration':
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-interactive';
+ $attributes['class'] .= ' ext-checkuser-investigate-table-cell-pinnable';
+ $date = $this->getLanguage()->userDate(
+ $value,
+ $this->getUser(),
+ [ 'format' => 'ISO 8601' ]
+ );
+ $attributes['data-field'] = $field;
+ $attributes['data-value'] = $date;
+ break;
+ }
+
+ // Add each cell to the tab index.
+ $attributes['tabindex'] = 0;
+
+ return $attributes;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ * @return string
+ */
+ public function formatValue( $name, $value ) {
+ $language = $this->getLanguage();
+ $row = $this->mCurrentRow;
+
+ $formatted = '';
+ switch ( $name ) {
+ case 'name':
+ $formatted = htmlspecialchars( $value );
+ break;
+ case 'registration':
+ $formatted = htmlspecialchars(
+ $language->userTimeAndDate( $value, $this->getUser() )
+ );
+ break;
+ case 'wiki':
+ $wiki = WikiMap::getWiki( $row->wiki );
+ if ( $wiki ) {
+ $formatted = Html::element(
+ 'a',
+ [
+ 'href' => $wiki->getFullUrl(
+ $this->namespaceInfo->getCanonicalName( NS_USER ) . ':' . $row->name
+ ),
+ ],
+ $wiki->getDisplayName()
+ );
+ } else {
+ $formatted = $this->msg( 'checkuser-investigate-preliminary-table-cell-wiki-nowiki' )->text();
+ }
+ break;
+ case 'editcount':
+ $wiki = WikiMap::getWiki( $row->wiki );
+ if ( $wiki ) {
+ $formatted = Html::rawElement(
+ 'a',
+ [
+ 'href' => $wiki->getFullUrl(
+ $this->namespaceInfo->getCanonicalName( NS_SPECIAL ) . ':Contributions/' . $row->name
+ ),
+ ],
+ $this->msg(
+ 'checkuser-investigate-preliminary-table-cell-edits',
+ $value
+ )->parse()
+ );
+ } else {
+ $formatted = $this->getLinkRenderer()->makeKnownLink(
+ \SpecialPage::getTitleFor( 'Contributions', $row->name ),
+ $this->msg(
+ 'checkuser-investigate-preliminary-table-cell-edits',
+ $value
+ )->text()
+ );
+ }
+ break;
+ case 'blocked':
+ if ( $value ) {
+ $formatted = $this->msg(
+ 'checkuser-investigate-preliminary-table-cell-blocked'
+ )->parse();
+ } else {
+ $formatted = $this->msg(
+ 'checkuser-investigate-preliminary-table-cell-unblocked'
+ )->parse();
+ }
+ break;
+ case 'groups':
+ $formatted = htmlspecialchars( implode( ', ', $value ) );
+ break;
+ }
+
+ return $formatted;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getIndexField() {
+ return $this->isGlobalCheck() ? [ [ 'lu_name', 'lu_wiki' ] ] : 'user_name';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFieldNames() {
+ if ( $this->fieldNames === null ) {
+ $fullFieldNames = [
+ 'name' => 'checkuser-investigate-preliminary-table-header-name',
+ 'registration' => 'checkuser-investigate-preliminary-table-header-registration',
+ 'wiki' => 'checkuser-investigate-preliminary-table-header-wiki',
+ 'editcount' => 'checkuser-investigate-preliminary-table-header-editcount',
+ 'blocked' => 'checkuser-investigate-preliminary-table-header-blocked',
+ 'groups' => 'checkuser-investigate-preliminary-table-header-groups',
+ ];
+
+ if ( $this->isGlobalCheck() ) {
+ $this->fieldNames = $fullFieldNames;
+ } else {
+ unset( $fullFieldNames['wiki'] );
+ $this->fieldNames = $fullFieldNames;
+ }
+
+ foreach ( $this->fieldNames as $key => $val ) {
+ $this->fieldNames[$key] = $this->msg( $val )->text();
+ }
+ }
+ return $this->fieldNames;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getQueryInfo() {
+ $targets = $this->tokenData['targets'] ?? [];
+ $users = array_filter( array_map( 'User::newFromName', $targets ), function ( $user ) {
+ return (bool)$user;
+ } );
+
+ return $this->preliminaryCheckService->getQueryInfo( $users );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function preprocessResults( $result ) {
+ $this->mResult = new FakeResultWrapper(
+ $this->preliminaryCheckService->preprocessResults( $result )
+ );
+ }
+
+ /**
+ * @return bool
+ */
+ public function isGlobalCheck(): bool {
+ return $this->extensionRegistry->isLoaded( 'CentralAuth' )
+ && is_callable( [ CentralAuthUtils::class, 'getCentralReplicaDB' ] );
+ }
+
+ /**
+ * @return IDatabase|null
+ */
+ protected function getCentralReplicaDB(): ?IDatabase {
+ if ( is_callable( [ CentralAuthUtils::class, 'getCentralReplicaDB' ] ) ) {
+ return CentralAuthUtils::getCentralReplicaDB();
+ }
+ return null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function isFieldSortable( $field ) {
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDefaultSort() {
+ return '';
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Conceal the offset which may reveal private data.
+ */
+ public function getPagingQueries() {
+ return $this->tokenQueryManager->getPagingQueries(
+ $this->getRequest(), parent::getPagingQueries()
+ );
+ }
+}
diff --git a/CheckUser/src/PreliminaryCheckPagerFactory.php b/CheckUser/src/PreliminaryCheckPagerFactory.php
new file mode 100644
index 00000000..aaee655e
--- /dev/null
+++ b/CheckUser/src/PreliminaryCheckPagerFactory.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use MediaWiki\Linker\LinkRenderer;
+
+class PreliminaryCheckPagerFactory implements PagerFactory {
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ /** @var \NamespaceInfo */
+ private $namespaceInfo;
+
+ /** @var \ExtensionRegistry */
+ private $extensionRegistry;
+
+ /** @var TokenQueryManager */
+ private $tokenQueryManager;
+
+ /** @var PreliminaryCheckService */
+ private $preliminaryCheck;
+
+ /**
+ * @param LinkRenderer $linkRenderer
+ * @param \NamespaceInfo $namespaceInfo
+ * @param \ExtensionRegistry $extensionRegistry
+ * @param TokenQueryManager $tokenQueryManager
+ * @param PreliminaryCheckService $preliminaryCheck
+ */
+ public function __construct(
+ LinkRenderer $linkRenderer,
+ \NamespaceInfo $namespaceInfo,
+ \ExtensionRegistry $extensionRegistry,
+ TokenQueryManager $tokenQueryManager,
+ PreliminaryCheckService $preliminaryCheck
+ ) {
+ $this->linkRenderer = $linkRenderer;
+ $this->namespaceInfo = $namespaceInfo;
+ $this->extensionRegistry = $extensionRegistry;
+ $this->tokenQueryManager = $tokenQueryManager;
+ $this->preliminaryCheck = $preliminaryCheck;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function createPager( \IContextSource $context ) : PreliminaryCheckPager {
+ return new PreliminaryCheckPager(
+ $context,
+ $this->linkRenderer,
+ $this->namespaceInfo,
+ $this->tokenQueryManager,
+ $this->extensionRegistry,
+ $this->preliminaryCheck
+ );
+ }
+}
diff --git a/CheckUser/src/PreliminaryCheckService.php b/CheckUser/src/PreliminaryCheckService.php
new file mode 100644
index 00000000..3fae09d1
--- /dev/null
+++ b/CheckUser/src/PreliminaryCheckService.php
@@ -0,0 +1,194 @@
+<?php
+namespace MediaWiki\CheckUser;
+
+use ExtensionRegistry;
+use MediaWiki\User\UserGroupManagerFactory;
+use MediaWiki\User\UserIdentityValue;
+use stdClass;
+use User;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ILBFactory;
+use Wikimedia\Rdbms\IResultWrapper;
+
+class PreliminaryCheckService {
+ /** @var ILBFactory */
+ private $lbFactory;
+
+ /** @var UserGroupManagerFactory */
+ private $userGroupManagerFactory;
+
+ /** @var string */
+ private $localWikiId;
+
+ /** @var ExtensionRegistry */
+ private $extensionRegistry;
+
+ /**
+ * @param ILBFactory $lbFactory
+ * @param ExtensionRegistry $extensionRegistry
+ * @param UserGroupManagerFactory $userGroupManagerFactory
+ * @param string $localWikiId
+ */
+ public function __construct( ILBFactory $lbFactory,
+ ExtensionRegistry $extensionRegistry,
+ UserGroupManagerFactory $userGroupManagerFactory,
+ string $localWikiId
+ ) {
+ $this->lbFactory = $lbFactory;
+ $this->extensionRegistry = $extensionRegistry;
+ $this->userGroupManagerFactory = $userGroupManagerFactory;
+ $this->localWikiId = $localWikiId;
+ }
+
+ /**
+ * Get the information needed to build a query for the preliminary check. The
+ * query will be different depending on whether CentralAuth is available. Any
+ * information for paginating is handled in the PreliminaryCheckPager.
+ *
+ * @param User[] $users
+ * @return array
+ */
+ public function getQueryInfo( array $users ) : array {
+ if ( $this->extensionRegistry->isLoaded( 'CentralAuth' ) ) {
+ $info = $this->getGlobalQueryInfo( $users );
+ } else {
+ $info = $this->getLocalQueryInfo( $users );
+ }
+ return $info;
+ }
+
+ /**
+ * Get the information for building a query if CentralAuth is available.
+ *
+ * @param User[] $users
+ * @return array
+ */
+ protected function getGlobalQueryInfo( array $users ) : array {
+ return [
+ 'tables' => 'localuser',
+ 'fields' => [
+ 'lu_name',
+ 'lu_wiki',
+ ],
+ 'conds' => $this->buildUserConds( $users, 'lu_name' ),
+ ];
+ }
+
+ /**
+ * Get the information for building a query if CentralAuth is unavailable.
+ *
+ * @param User[]|string[] $users
+ * @return array
+ */
+ protected function getLocalQueryInfo( array $users ) : array {
+ return [
+ 'tables' => 'user',
+ 'fields' => [
+ 'user_name',
+ 'user_id',
+ 'user_editcount',
+ 'user_registration',
+ ],
+ 'conds' => $this->buildUserConds( $users, 'user_name' ),
+ ];
+ }
+
+ /**
+ * @param User[] $users
+ * @param string $field
+ * @return array
+ */
+ protected function buildUserConds( array $users, string $field ) : array {
+ if ( !$users ) {
+ return [ 0 ];
+ }
+ return [ $field => array_map( 'strval', $users ) ];
+ }
+
+ /**
+ * Get the replica database of a local wiki, given a wiki ID.
+ *
+ * @param string $wikiId
+ * @return IDatabase
+ */
+ protected function getLocalDb( $wikiId ) : IDatabase {
+ return $this->lbFactory->getMainLB( $wikiId )->getConnectionRef( DB_REPLICA, [], $wikiId );
+ }
+
+ /**
+ * Perform additional queries to get the required data that is not returned
+ * by the pager's query. (The pager performs the query that is used for
+ * pagination.)
+ *
+ * @param IResultWrapper $rows
+ * @return array
+ */
+ public function preprocessResults( IResultWrapper $rows ) : array {
+ $data = [];
+ foreach ( $rows as $row ) {
+ if ( $this->extensionRegistry->isLoaded( 'CentralAuth' ) ) {
+ $localRow = $this->getLocalUserData( $row->lu_name, $row->lu_wiki );
+ $data[] = $this->getAdditionalLocalData( $localRow, $row->lu_wiki );
+ } else {
+ $data[] = $this->getAdditionalLocalData( $row, $this->localWikiId );
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Get basic user information for a given user's account on a given wiki.
+ *
+ * @param string $username
+ * @param string $wikiId
+ * @return stdClass|bool
+ */
+ public function getLocalUserData( string $username, string $wikiId ) {
+ $db = $this->getLocalDb( $wikiId );
+ $queryInfo = $this->getLocalQueryInfo( [ $username ] );
+ return $db->selectRow(
+ $queryInfo['tables'],
+ $queryInfo['fields'],
+ $queryInfo['conds'],
+ __METHOD__
+ );
+ }
+
+ /**
+ * Get blocked status and user groups for a given user's account on a
+ * given wiki.
+ *
+ * @param stdClass|bool $row
+ * @param string $wikiId
+ * @return array
+ */
+ protected function getAdditionalLocalData( $row, string $wikiId ) : array {
+ $db = $this->getLocalDb( $wikiId );
+
+ return [
+ 'id' => $row->user_id,
+ 'name' => $row->user_name,
+ 'registration' => $row->user_registration,
+ 'editcount' => $row->user_editcount,
+ 'blocked' => $this->isUserBlocked( $row->user_id, $db ),
+ 'groups' => $this->userGroupManagerFactory
+ ->getUserGroupManager( $wikiId )
+ ->getUserGroups(
+ new UserIdentityValue( (int)$row->user_id, $row->user_name, 0 )
+ ),
+ 'wiki' => $wikiId,
+ ];
+ }
+
+ /**
+ * @param int $userId
+ * @param IDatabase $db Database connection
+ * @return bool
+ */
+ protected function isUserBlocked( int $userId, IDatabase $db ): bool {
+ $blocks = $db->selectField(
+ 'ipblocks', '1', [ 'ipb_user' => $userId ], __METHOD__, [ 'LIMIT' => 1 ]
+ );
+ return $blocks > 0;
+ }
+}
diff --git a/CheckUser/src/SpecialInvestigate.php b/CheckUser/src/SpecialInvestigate.php
new file mode 100644
index 00000000..e9ad4c4a
--- /dev/null
+++ b/CheckUser/src/SpecialInvestigate.php
@@ -0,0 +1,1020 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Html;
+use HTMLForm;
+use Language;
+use MediaWiki\CheckUser\GuidedTour\TourLauncher;
+use MediaWiki\CheckUser\Hook\CheckUserSubtitleLinksHook;
+use MediaWiki\CheckUser\HookHandler\Preferences;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\User\UserOptionsManager;
+use Message;
+use OOUI\ButtonGroupWidget;
+use OOUI\ButtonWidget;
+use OOUI\Element;
+use OOUI\FieldLayout;
+use OOUI\FieldsetLayout;
+use OOUI\HorizontalLayout;
+use OOUI\HtmlSnippet;
+use OOUI\IndexLayout;
+use OOUI\MessageWidget;
+use OOUI\TabOptionWidget;
+use OOUI\Tag;
+use OOUI\Widget;
+use SpecialCheckUser;
+use User;
+use Wikimedia\IPUtils;
+
+class SpecialInvestigate extends \FormSpecialPage {
+ /** @var Language */
+ private $contentLanguage;
+
+ /** @var UserOptionsManager */
+ private $userOptionsManager;
+
+ /** @var PagerFactory */
+ private $preliminaryCheckPagerFactory;
+
+ /** @var PagerFactory */
+ private $comparePagerFactory;
+
+ /** @var TimelinePagerFactory */
+ private $timelinePagerFactory;
+
+ /** @var TokenQueryManager */
+ private $tokenQueryManager;
+
+ /** @var DurationManager */
+ private $durationManager;
+
+ /** @var EventLogger */
+ private $eventLogger;
+
+ /** @var TourLauncher */
+ private $tourLauncher;
+
+ /** @var CheckUserSubtitleLinksHook */
+ private $subtitleLinksHookRunner;
+
+ /** @var IndexLayout|null */
+ private $layout;
+
+ /** @var array|null */
+ private $tokenData;
+
+ /** @var HTMLForm|null */
+ private $form;
+
+ /** @var string|null */
+ private $tokenWithoutPaginationData;
+
+ /** @var int */
+ private const MAX_TARGETS = 10;
+
+ /** @var string */
+ private const TOUR_INVESTIGATE = 'checkuserinvestigate';
+
+ /** @var string */
+ private const TOUR_INVESTIGATE_FORM = 'checkuserinvestigateform';
+
+ /** @var string[] */
+ private const TOURS = [
+ self::TOUR_INVESTIGATE,
+ self::TOUR_INVESTIGATE_FORM,
+ ];
+
+ /**
+ * @param LinkRenderer $linkRenderer
+ * @param Language $contentLanguage
+ * @param UserOptionsManager $userOptionsManager
+ * @param PagerFactory $preliminaryCheckPagerFactory
+ * @param PagerFactory $comparePagerFactory
+ * @param PagerFactory $timelinePagerFactory
+ * @param TokenQueryManager $tokenQueryManager
+ * @param DurationManager $durationManager
+ * @param EventLogger $eventLogger
+ * @param TourLauncher $tourLauncher
+ * @param CheckUserSubtitleLinksHook $subtitleLinksHookRunner
+ */
+ public function __construct(
+ LinkRenderer $linkRenderer,
+ Language $contentLanguage,
+ UserOptionsManager $userOptionsManager,
+ PagerFactory $preliminaryCheckPagerFactory,
+ PagerFactory $comparePagerFactory,
+ PagerFactory $timelinePagerFactory,
+ TokenQueryManager $tokenQueryManager,
+ DurationManager $durationManager,
+ EventLogger $eventLogger,
+ TourLauncher $tourLauncher,
+ CheckUserSubtitleLinksHook $subtitleLinksHookRunner
+ ) {
+ parent::__construct( 'Investigate', 'checkuser' );
+ $this->setLinkRenderer( $linkRenderer );
+ $this->contentLanguage = $contentLanguage;
+ $this->userOptionsManager = $userOptionsManager;
+ $this->preliminaryCheckPagerFactory = $preliminaryCheckPagerFactory;
+ $this->comparePagerFactory = $comparePagerFactory;
+ $this->timelinePagerFactory = $timelinePagerFactory;
+ $this->tokenQueryManager = $tokenQueryManager;
+ $this->durationManager = $durationManager;
+ $this->eventLogger = $eventLogger;
+ $this->tourLauncher = $tourLauncher;
+ $this->subtitleLinksHookRunner = $subtitleLinksHookRunner;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function preText() {
+ // Add necessary styles
+ $this->getOutput()->addModuleStyles( [
+ 'mediawiki.widgets.TagMultiselectWidget.styles',
+ ] );
+ // Add button link to the log page on the main form.
+ // Open in the current tab.
+ $this->addIndicators( /** $newTab */ false, /** $logOnly */ true );
+
+ return '';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function execute( $par ) {
+ // Always call the parent method in order to check execute permissions.
+ parent::execute( $par );
+
+ // If the form submission results in a redirect, there is no need to
+ // generate content for the page.
+ if ( $this->getOutput()->getRedirect() !== '' ) {
+ return;
+ }
+
+ // The tour is being explicitly launched by the user, reset their preferences.
+ if ( $this->reLaunchTour() ) {
+ return;
+ }
+
+ $this->getOutput()->addModuleStyles( 'ext.checkUser.investigate.styles' );
+ $this->getOutput()->addModules( [ 'ext.checkUser.investigate' ] );
+
+ // Show the tabs if there is any request data.
+ // The tabs should also be shown even if the form was a POST request because
+ // the filters could have failed validation.
+ if ( $this->getTokenData() !== [] ) {
+ // Remove the filters, unless a valid tab that supports filters is selected.
+ if ( !in_array( $par, [
+ $this->getTabParam( 'compare' ),
+ $this->getTabParam( 'timeline' ),
+ ] ) ) {
+ $this->getOutput()->clearHTML();
+ }
+
+ $this->addIndicators();
+ $this->addBlockForm();
+ $this->addTabs( $par )->addTabContent( $par );
+ $this->getOutput()->addHTML( $this->getLayout() );
+ } else {
+ $this->launchTour( self::TOUR_INVESTIGATE_FORM );
+ }
+
+ // Add the links after any previous HTML has been cleared.
+ $this->addSubtitle();
+ $this->addHelpLink(
+ 'https://meta.wikimedia.org/wiki/Special:MyLanguage/Help:Special_Investigate',
+ true
+ );
+ }
+
+ /**
+ * Returns the OOUI Index Layout and adds the module dependencies for OOUI.
+ *
+ * @return IndexLayout
+ */
+ private function getLayout() : IndexLayout {
+ if ( $this->layout === null ) {
+ $this->getOutput()->enableOOUI();
+ $this->getOutput()->addModuleStyles( [
+ 'oojs-ui-widgets.styles',
+ ] );
+
+ $this->layout = new IndexLayout( [
+ 'framed' => false,
+ 'expanded' => false,
+ 'classes' => [ 'ext-checkuser-investigate-tabs-indexLayout' ],
+ ] );
+ }
+
+ return $this->layout;
+ }
+
+ /**
+ * Add tabs to the layout. Provide the current tab so that tab can be highlighted.
+ *
+ * @param string $par
+ * @return self
+ */
+ private function addTabs( string $par ) : self {
+ $config = [];
+ [
+ 'tabSelectWidget' => $tabSelectWidget,
+ ] = $this->getLayout()->getConfig( $config );
+
+ $token = $this->getTokenWithoutPaginationData();
+
+ $tabs = array_map( function ( $tab ) use ( $par, $token ) {
+ $label = $this->getTabMessage( $tab )->text();
+ $param = $this->getTabParam( $tab );
+ return new TabOptionWidget( [
+ 'label' => $label,
+ 'labelElement' => ( new Tag( 'a' ) )->setAttributes( [
+ 'href' => $this->getPageTitle( $param )->getLocalURL( [
+ 'token' => $token,
+ 'duration' => $this->getDuration() ?: null,
+ ] ),
+ ] ),
+ 'selected' => ( $par === $param ),
+ ] );
+ }, [
+ 'preliminary-check',
+ 'compare',
+ 'timeline',
+ ] );
+
+ $tabSelectWidget->addItems( $tabs );
+
+ return $this;
+ }
+
+ /**
+ * @return string|null
+ */
+ private function getTokenWithoutPaginationData() {
+ if ( $this->tokenWithoutPaginationData === null ) {
+ $this->tokenWithoutPaginationData = $this->getUpdatedToken( [
+ 'offset' => null,
+ ] );
+ }
+ return $this->tokenWithoutPaginationData;
+ }
+
+ /**
+ * Add HTML to Layout.
+ *
+ * @param string $html
+ * @return self
+ */
+ private function addHtml( string $html ) : self {
+ $config = [];
+ [
+ 'contentPanel' => $contentPanel
+ ] = $this->getLayout()->getConfig( $config );
+
+ $contentPanel->addItems( [
+ new Element( [
+ 'content' => new HtmlSnippet( $html ),
+ ] ),
+ ] );
+
+ return $this;
+ }
+
+ /**
+ * Add Pager Output to Layout.
+ *
+ * @param \ParserOutput $parserOutput
+ * @return self
+ */
+ private function addParserOutput( \ParserOutput $parserOutput ) : self {
+ $this->getOutput()->addParserOutputMetadata( $parserOutput );
+ $this->addHTML( $parserOutput->getText() );
+
+ return $this;
+ }
+
+ /**
+ * Add Tab content to Layout
+ *
+ * @param string $par
+ * @return self
+ */
+ private function addTabContent( string $par ) : self {
+ $startTime = $this->eventLogger->getTime();
+
+ switch ( $par ) {
+ case $this->getTabParam( 'preliminary-check' ):
+ $pager = $this->preliminaryCheckPagerFactory->createPager( $this->getContext() );
+ $hasIpTargets = (bool)array_filter(
+ $this->getTokenData()['targets'] ?? [],
+ function ( $target ) {
+ return IPUtils::isIPAddress( $target );
+ }
+ );
+
+ if ( $pager->getNumRows() ) {
+ $this->addParserOutput( $pager->getFullOutput() );
+ } elseif ( !$hasIpTargets ) {
+ $this->addHTML(
+ $this->msg( 'checkuser-investigate-notice-no-results' )->parse()
+ );
+ }
+
+ if ( $hasIpTargets ) {
+ $compareParam = $this->getTabParam( 'compare' );
+ // getFullURL handles the query params:
+ // https://www.mediawiki.org/wiki/Help:Links#External_links_to_internal_pages
+ $link = $this->getPageTitle( $compareParam )->getFullURL( [
+ 'token' => $this->getTokenWithoutPaginationData(),
+ ] );
+ $message = $this->msg( 'checkuser-investigate-preliminary-notice-ip-targets', $link )->parse();
+ $this->addHTML( new MessageWidget( [
+ 'type' => 'notice',
+ 'label' => new HtmlSnippet( $message )
+ ] ) );
+ }
+
+ $this->logQuery( [
+ 'tab' => 'preliminary-check',
+ 'resultsCount' => $pager->getNumRows(),
+ 'resultsIncomplete' => false,
+ 'queryTime' => $this->eventLogger->getTime() - $startTime,
+ ] );
+
+ break;
+
+ case $this->getTabParam( 'compare' ):
+ $pager = $this->comparePagerFactory->createPager( $this->getContext() );
+ $numRows = $pager->getNumRows();
+
+ if ( $numRows ) {
+ $targetsOverLimit = $pager->getTargetsOverLimit();
+ if ( $targetsOverLimit ) {
+ $message = $this->msg(
+ 'checkuser-investigate-compare-notice-exceeded-limit',
+ $this->getLanguage()->commaList( $targetsOverLimit )
+ )->parse();
+ $this->addHTML( new MessageWidget( [
+ 'type' => 'warning',
+ 'label' => new HtmlSnippet( $message )
+ ] ) );
+ }
+
+ // Only start the tour if there are results on the page.
+ $this->launchTour( self::TOUR_INVESTIGATE );
+
+ $this->addParserOutput( $pager->getFullOutput() );
+ } else {
+ $messageKey = $this->usingFilters() ?
+ 'checkuser-investigate-compare-notice-no-results-filters' :
+ 'checkuser-investigate-compare-notice-no-results';
+ $message = $this->msg( $messageKey )->parse();
+ $this->addHTML( new MessageWidget( [
+ 'type' => 'warning',
+ 'label' => new HtmlSnippet( $message )
+ ] ) );
+ }
+
+ $this->logQuery( [
+ 'tab' => 'compare',
+ 'resultsCount' => $numRows,
+ 'resultsIncomplete' => $numRows && $targetsOverLimit,
+ 'queryTime' => $this->eventLogger->getTime() - $startTime,
+ ] );
+
+ break;
+
+ case $this->getTabParam( 'timeline' ):
+ $pager = $this->timelinePagerFactory->createPager( $this->getContext() );
+ $numRows = $pager->getNumRows();
+
+ if ( $numRows ) {
+ $this->addParserOutput( $pager->getFullOutput() );
+ } else {
+ $messageKey = $this->usingFilters() ?
+ 'checkuser-investigate-timeline-notice-no-results-filters' :
+ 'checkuser-investigate-timeline-notice-no-results';
+ $message = $this->msg( $messageKey )->parse();
+ $this->addHTML( new MessageWidget( [
+ 'type' => 'warning',
+ 'label' => new HtmlSnippet( $message )
+ ] ) );
+ }
+
+ $this->logQuery( [
+ 'tab' => 'timeline',
+ 'resultsCount' => $pager->getNumRows(),
+ 'resultsIncomplete' => false,
+ 'queryTime' => $this->eventLogger->getTime() - $startTime,
+ ] );
+
+ break;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array $logData
+ */
+ private function logQuery( array $logData ) : void {
+ $relevantTargetsCount = count( array_diff(
+ $this->getTokenData()['targets'] ?? [],
+ $this->getTokenData()['exclude-targets'] ?? []
+ ) );
+
+ $this->eventLogger->logEvent( array_merge(
+ [
+ 'action' => 'query',
+ 'relevantTargetsCount' => $relevantTargetsCount,
+ ],
+ $logData
+ ) );
+ }
+
+ /**
+ * Given a tab name, return the subpage $par.
+ *
+ * Since the page title is always in the content language, the subpage should be also.
+ *
+ * @param string $tab
+ *
+ * @return string
+ */
+ private function getTabParam( string $tab ) : string {
+ $name = $this->getTabMessage( $tab )->inLanguage( $this->contentLanguage )->text();
+ return str_replace( ' ', '_', $name );
+ }
+
+ /**
+ * Given a tab name, return the subpage tab message.
+ *
+ * @param string $tab
+ *
+ * @return Message
+ */
+ private function getTabMessage( string $tab ) : Message {
+ return $this->msg( 'checkuser-investigate-tab-' . $tab );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDescription() {
+ return $this->msg( $this->getMessagePrefix() )->text();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getMessagePrefix() {
+ return 'checkuser-' . strtolower( $this->getName() );
+ }
+
+ /**
+ * Add page subtitle including the name of the targets in the investigation,
+ * and a block form. Add the block form elements that are visible initially,
+ * to avoid a flicker on page load.
+ */
+ private function addBlockForm() {
+ $targets = $this->getTokenData()['targets'] ?? [];
+ if ( $targets ) {
+ $excludeTargets = $this->getTokenData()['exclude-targets'] ?? [];
+
+ $this->getOutput()->addJsConfigVars( [
+ 'wgCheckUserInvestigateTargets' => $targets,
+ 'wgCheckUserInvestigateExcludeTargets' => $excludeTargets,
+ ] );
+
+ $targetsText = $this->getLanguage()->listToText( array_map( function ( $target ) {
+ return Html::rawElement( 'strong', [], htmlspecialchars( $target ) );
+ }, $targets ) );
+ $subtitle = $this->msg( 'checkuser-investigate-page-subtitle', $targetsText );
+
+ // Placeholder, to allow the FieldLayout label to be shown before the
+ // JavaScript loads. This will be replaced by a TagMultiselect (which
+ // has not yet been implemented in PHP).
+ $placeholderWidget = new Widget( [
+ 'classes' => [ 'ext-checkuser-investigate-subtitle-placeholder-widget' ],
+ ] );
+ $targetsLayout = new FieldLayout(
+ $placeholderWidget,
+ [
+ 'label' => new HtmlSnippet( $subtitle->parse() ),
+ 'align' => 'top',
+ 'infusable' => true,
+ 'classes' => [
+ 'ext-checkuser-investigate-subtitle-targets-layout'
+ ]
+ ]
+ );
+
+ $blockButton = new ButtonWidget( [
+ 'infusable' => true,
+ 'label' => $this->msg( 'checkuser-investigate-subtitle-block-button-label' )->text(),
+ 'flags' => [ 'primary', 'progressive' ],
+ 'classes' => [
+ 'ext-checkuser-investigate-subtitle-block-button',
+ ],
+ ] );
+ $buttonsLayout = new FieldLayout(
+ new Widget( [
+ 'content' => new HorizontalLayout( [
+ 'items' => [
+ $blockButton,
+ ]
+ ] )
+ ] ),
+ [
+ 'align' => 'top',
+ 'infusable' => true,
+ ]
+ );
+
+ $blockFieldset = new FieldsetLayout( [
+ 'classes' => [
+ 'ext-checkuser-investigate-subtitle-fieldset'
+ ],
+ 'items' => [
+ $targetsLayout,
+ $buttonsLayout,
+ ]
+ ] );
+
+ $this->getOutput()->prependHTML(
+ $blockFieldset
+ );
+ }
+ }
+
+ /**
+ * Add buttons to start a new investigation and linking
+ * to InvestigateLog page
+ *
+ * @param bool $newTab Whether to open the link in a new tab
+ * @param bool $logOnly Whether to show only the log button
+ */
+ private function addIndicators( $newTab = true, $logOnly = false ) {
+ $log = new ButtonWidget( [
+ 'label' => $this->msg( 'checkuser-investigate-indicator-logs' )->text(),
+ 'href' => self::getTitleFor( 'InvestigateLog' )->getLinkURL(),
+ 'target' => $newTab ? '_blank' : '',
+ ] );
+
+ $newForm = new ButtonWidget( [
+ 'label' => $this->msg( 'checkuser-investigate-indicator-new-investigation' )->text(),
+ 'href' => $this->getPageTitle()->getLinkURL(),
+ 'target' => $newTab ? '_blank' : '',
+ ] );
+
+ if ( $logOnly ) {
+ $this->getOutput()->setIndicators( [
+ 'ext-checkuser-investigation-btns' => $log,
+ ] );
+ } else {
+ $this->getOutput()->setIndicators( [
+ 'ext-checkuser-investigation-btns' => new ButtonGroupWidget( [
+ 'classes' => [ 'ext-checkuser-investigate-indicators' ],
+ 'items' => [ $newForm, $log ],
+ ] ),
+ ] );
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getForm() {
+ if ( $this->form === null ) {
+ $this->form = parent::getForm();
+ }
+
+ return $this->form;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getFormFields() {
+ $data = $this->getTokenData();
+ $prefix = $this->getMessagePrefix();
+
+ $duration = [
+ 'type' => 'select',
+ 'name' => 'duration',
+ 'label-message' => $prefix . '-duration-label',
+ 'options-messages' => [
+ $prefix . '-duration-option-all' => '',
+ $prefix . '-duration-option-1w' => 'P1W',
+ $prefix . '-duration-option-2w' => 'P2W',
+ $prefix . '-duration-option-30d' => 'P30D',
+ ],
+ // If this duration in the URL is not in the list, "all" is displayed.
+ 'default' => $this->getDuration(),
+ 'validation-callback' => function ( $value ) {
+ if ( !$this->durationManager->isValid( $value ) ) {
+ return $this->getMessagePrefix() . '-duration-invalid';
+ }
+
+ return true;
+ }
+ ];
+
+ if ( $data === [] ) {
+ $this->getOutput()->addJsConfigVars( 'wgCheckUserInvestigateMaxTargets', self::MAX_TARGETS );
+
+ return [
+ 'Targets' => [
+ 'type' => 'usersmultiselect',
+ 'name' => 'targets',
+ 'label-message' => $prefix . '-targets-label',
+ 'placeholder' => $this->msg( $prefix . '-targets-placeholder' )->text(),
+ 'id' => 'targets',
+ 'required' => true,
+ 'max' => self::MAX_TARGETS,
+ 'exists' => true,
+ 'ipallowed' => true,
+ 'iprange' => true,
+ 'default' => implode( "\n", $data['targets'] ?? [] ),
+ 'input' => [
+ 'autocomplete' => false,
+ ],
+ ],
+ 'Duration' => $duration,
+ 'Reason' => [
+ 'type' => 'text',
+ 'name' => 'reason',
+ 'label-message' => $prefix . '-reason-label',
+ 'required' => true,
+ 'autocomplete' => false,
+ ],
+ ];
+ }
+
+ $fields = [];
+
+ // Filters for both Compare & Timeline
+ $compareTab = $this->getTabParam( 'compare' );
+ $timelineTab = $this->getTabParam( 'timeline' );
+
+ // Filters for both Compare & Timeline
+ if ( in_array( $this->par, [ $compareTab, $timelineTab ], true ) ) {
+ $fields['ExcludeTargets'] = [
+ 'type' => 'usersmultiselect',
+ 'name' => 'exclude-targets',
+ 'label-message' => $prefix . '-filters-exclude-targets-label',
+ 'exists' => true,
+ 'required' => false,
+ 'ipallowed' => true,
+ 'iprange' => false,
+ 'default' => implode( "\n", $data['exclude-targets'] ?? [] ),
+ 'input' => [
+ 'autocomplete' => false,
+ ],
+ ];
+ $fields['Duration'] = $duration;
+ }
+
+ if ( $this->par === $compareTab ) {
+ $fields['Targets'] = [
+ 'type' => 'hidden',
+ 'name' => 'targets',
+ ];
+ }
+
+ if ( $this->par === $timelineTab ) {
+ // @TODO Add filters specific to the timeline tab.
+ }
+
+ return $fields;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function alterForm( HTMLForm $form ) {
+ // Not done by default in OOUI forms, but done here to match
+ // intended design in T237034. See FormSpecialPage::getForm
+ if ( $this->getTokenData() === [] ) {
+ $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
+ } else {
+ $tabs = [ $this->getTabParam( 'compare' ), $this->getTabParam( 'timeline' ) ];
+ if ( in_array( $this->par, $tabs ) ) {
+ $form->setAction( $this->getRequest()->getRequestURL() );
+ $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-filters-legend' );
+ // If the page is a result of a POST then validation failed, and the form should be open.
+ // If the page is a result of a GET then validation succeeded and the form should be closed.
+ $form->setCollapsibleOptions( !$this->getRequest()->wasPosted() );
+ }
+ }
+ }
+
+ /**
+ * Get data from the request token.
+ *
+ * @return array
+ */
+ private function getTokenData() : array {
+ if ( $this->tokenData === null ) {
+ $this->tokenData = $this->tokenQueryManager->getDataFromRequest( $this->getRequest() );
+ }
+
+ return $this->tokenData;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function onSubmit( array $data ) {
+ $update = [
+ 'offset' => null,
+ ];
+
+ if ( isset( $data['Reason'] ) ) {
+ $update['reason'] = $data['Reason'];
+ }
+ if ( isset( $data['ExcludeTargets' ] ) ) {
+ $submittedExcludeTargets = $this->getArrayFromField( $data, 'ExcludeTargets' );
+ $update['exclude-targets'] = $submittedExcludeTargets;
+ }
+ if ( isset( $data['Targets' ] ) ) {
+ $tokenData = $this->getTokenData();
+
+ $submittedTargets = $this->getArrayFromField( $data, 'Targets' );
+ $update['targets'] = $submittedTargets;
+
+ $this->addLogEntries(
+ $update['targets'],
+ $update['reason'] ?? $tokenData['reason']
+ );
+
+ $update['targets'] = array_unique( array_merge(
+ $update['targets'],
+ $tokenData['targets'] ?? []
+ ) );
+ }
+
+ $token = $this->getUpdatedToken( $update );
+
+ if ( isset( $this->par ) && $this->par !== '' ) {
+ // Redirect to the same subpage with an updated token.
+ $url = $this->getRedirectUrl( [
+ 'token' => $token,
+ 'duration' => $data['Duration'] ?: null,
+ ] );
+ } else {
+ // Redirect to compare tab
+ $url = $this->getPageTitle( $this->getTabParam( 'compare' ) )->getFullUrlForRedirect( [
+ 'token' => $token,
+ 'duration' => $data['Duration'] ?: null,
+ ] );
+ }
+ $this->getOutput()->redirect( $url );
+
+ $this->eventLogger->logEvent( [
+ 'action' => 'submit',
+ 'targetsCount' => count( $submittedTargets ?? [] ),
+ 'excludeTargetsCount' => count( $submittedExcludeTargets ?? [] ),
+ ] );
+
+ return \Status::newGood();
+ }
+
+ /**
+ * Add a log entry for each target under investigation.
+ *
+ * @param string[] $targets
+ * @param string $reason
+ */
+ protected function addLogEntries( array $targets, string $reason ) {
+ $logType = 'investigate';
+
+ foreach ( $targets as $target ) {
+ if ( IPUtils::isIPAddress( $target ) ) {
+ $targetType = 'ip';
+ $targetId = 0;
+ } else {
+ // The form validated that the user exists on this wiki
+ $targetType = 'user';
+ $targetId = User::idFromName( $target );
+ }
+
+ SpecialCheckUser::addLogEntry(
+ $logType,
+ $targetType,
+ $target,
+ $reason,
+ $targetId
+ );
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getGroupName() {
+ return 'users';
+ }
+
+ /**
+ * Get an updated token.
+ *
+ * Preforms an array merge on the updates with what is in the current token.
+ * Setting a value to null will remove it.
+ *
+ * @param array $update
+ * @return string
+ */
+ private function getUpdatedToken( array $update ) : string {
+ return $this->tokenQueryManager->updateToken(
+ $this->getRequest(),
+ $update
+ );
+ }
+
+ /**
+ * Get a redirect URL with a new query string.
+ *
+ * @param array $update
+ * @return string
+ */
+ private function getRedirectUrl( array $update ) : string {
+ $parts = wfParseURL( $this->getRequest()->getFullRequestURL() );
+ $query = isset( $parts['query'] ) ? wfCgiToArray( $parts['query'] ) : [];
+ $data = array_filter( array_merge( $query, $update ), function ( $value ) {
+ return $value !== null;
+ } );
+ $parts['query'] = wfArrayToCgi( $data );
+ return wfAssembleUrl( $parts );
+ }
+
+ /**
+ * Get an array of values from a new line seperated field.
+ *
+ * @param array $data
+ * @param string $field
+ * @return string[]
+ */
+ private function getArrayFromField( array $data, string $field ) : array {
+ if ( !isset( $data[$field] ) ) {
+ return [];
+ }
+
+ if ( !is_string( $data[$field] ) ) {
+ return [];
+ }
+
+ if ( $data[$field] === '' ) {
+ return [];
+ }
+
+ return explode( "\n", $data[$field] );
+ }
+
+ /**
+ * Determine if the filters are in use by the current request.
+ *
+ * @return bool
+ */
+ private function usingFilters() : bool {
+ return count( $this->getTokenData()['exclude-targets'] ?? [] ) > 0
+ || $this->getDuration() !== '';
+ }
+
+ /**
+ * Get the duration from the request.
+ *
+ * @return string
+ */
+ private function getDuration() : string {
+ return $this->durationManager->getFromRequest( $this->getRequest() );
+ }
+
+ /**
+ * Relaunch Tour Intercept
+ *
+ * Intercepts a request and relaunches the tour by updating the user preferences and setting
+ * a redirect.
+ *
+ * @return bool If the tour is being relaunched and a redirect was set.
+ */
+ public function reLaunchTour() : bool {
+ if ( $this->getRequest()->getMethod() !== 'GET' ) {
+ return false;
+ }
+
+ if ( !in_array( $this->getRequest()->getVal( 'tour' ), self::TOURS, true ) ) {
+ return false;
+ }
+
+ $user = $this->getUser();
+
+ $options = [];
+ switch ( $this->getRequest()->getVal( 'tour' ) ) {
+ case self::TOUR_INVESTIGATE_FORM:
+ $options = [
+ Preferences::INVESTIGATE_FORM_TOUR_SEEN,
+ Preferences::INVESTIGATE_TOUR_SEEN,
+ ];
+ break;
+ case self::TOUR_INVESTIGATE:
+ $options = [
+ Preferences::INVESTIGATE_TOUR_SEEN,
+ ];
+ break;
+ }
+
+ foreach ( $options as $option ) {
+ $this->userOptionsManager->setOption( $user, $option, null );
+ }
+
+ $this->userOptionsManager->saveOptions( $user );
+
+ $parts = wfParseUrl( $this->getRequest()->getFullRequestURL() );
+ $query = wfCgiToArray( $parts['query'] ?? '' );
+ $query['tour'] = null;
+ $parts['query'] = wfArrayToCgi( $query );
+
+ $this->getOutput()->redirect( wfAssembleUrl( $parts ) );
+
+ return true;
+ }
+
+ /**
+ * Launches the tour unless the user has already completed or canceled it.
+ *
+ * @param string $tour
+ * @return void
+ */
+ private function launchTour( string $tour ) : void {
+ $user = $this->getUser();
+
+ $preference = '';
+ $step = '';
+
+ switch ( $tour ) {
+ case self::TOUR_INVESTIGATE_FORM:
+ $preference = Preferences::INVESTIGATE_FORM_TOUR_SEEN;
+ $step = 'targets';
+ break;
+ case self::TOUR_INVESTIGATE:
+ $preference = Preferences::INVESTIGATE_TOUR_SEEN;
+ $step = 'useragents';
+ break;
+ default:
+ return;
+ }
+
+ if ( $this->userOptionsManager->getOption( $user, $preference ) ) {
+ return;
+ }
+
+ $this->tourLauncher->launchTour( $tour, $step );
+ }
+
+ /**
+ * Add the subtitle to the page.
+ */
+ private function addSubtitle() : void {
+ $subpage = false;
+ $token = null;
+ $tour = self::TOUR_INVESTIGATE_FORM;
+
+ if ( $this->getTokenData() !== [] ) {
+ $token = $this->getTokenWithoutPaginationData();
+ $subpage = $this->getTabParam( 'compare' );
+ $tour = self::TOUR_INVESTIGATE;
+ }
+
+ $links = [
+ $this->getLinkRenderer()->makeLink( self::getTitleValueFor( 'CheckUser' ) ),
+ $this->tourLauncher->makeTourLink(
+ $tour,
+ $this->getPageTitle( $subpage ),
+ $this->msg( 'checkuser-investigate-subtitle-link-restart-tour' )->text(),
+ [],
+ [
+ 'token' => $token,
+ 'duration' => $this->getDuration() ?: null,
+ ]
+ ),
+ ];
+
+ $this->subtitleLinksHookRunner->onCheckUserSubtitleLinks( $this->getContext(), $links );
+
+ $subtitle = implode( ' | ', array_filter( $links, function ( $link ) {
+ return (bool)$link;
+ } ) );
+
+ $this->getOutput()->setSubtitle( $subtitle );
+ }
+}
diff --git a/CheckUser/src/SpecialInvestigateBlock.php b/CheckUser/src/SpecialInvestigateBlock.php
new file mode 100644
index 00000000..a406f2ee
--- /dev/null
+++ b/CheckUser/src/SpecialInvestigateBlock.php
@@ -0,0 +1,349 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use ApiMain;
+use DerivativeRequest;
+use Exception;
+use FormSpecialPage;
+use Linker;
+use MediaWiki\Permissions\PermissionManager;
+use MediaWiki\User\UserFactory;
+use MediaWiki\User\UserNameUtils;
+use SpecialBlock;
+use TitleFormatter;
+use TitleValue;
+use User;
+use Wikimedia\IPUtils;
+
+class SpecialInvestigateBlock extends FormSpecialPage {
+ /** @var PermissionManager */
+ private $permissionManager;
+
+ /** @var TitleFormatter */
+ private $titleFormatter;
+
+ /** @var UserFactory */
+ private $userFactory;
+
+ /** @var EventLogger */
+ private $eventLogger;
+
+ /** @var array */
+ private $blockedUsers = [];
+
+ /** @var bool */
+ private $noticesFailed = false;
+
+ public function __construct(
+ PermissionManager $permissionManager,
+ TitleFormatter $titleFormatter,
+ UserFactory $userFactory,
+ EventLogger $eventLogger
+ ) {
+ parent::__construct( 'InvestigateBlock', 'checkuser' );
+
+ $this->permissionManager = $permissionManager;
+ $this->titleFormatter = $titleFormatter;
+ $this->userFactory = $userFactory;
+ $this->eventLogger = $eventLogger;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function userCanExecute( User $user ) {
+ return parent::userCanExecute( $user ) &&
+ $this->permissionManager->userHasRight( $user, 'block' );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFormFields() {
+ $this->getOutput()->addModules( [
+ 'ext.checkUser.investigateblock'
+ ] );
+ $this->getOutput()->addModuleStyles( [
+ 'mediawiki.widgets.TagMultiselectWidget.styles',
+ 'ext.checkUser.investigateblock.styles',
+ ] );
+ $this->getOutput()->enableOOUI();
+
+ $prefix = $this->getMessagePrefix();
+ $fields = [];
+
+ $fields['Targets'] = [
+ 'type' => 'usersmultiselect',
+ 'ipallowed' => true,
+ 'iprange' => true,
+ 'autofocus' => true,
+ 'required' => true,
+ 'exists' => true,
+ 'input' => [
+ 'autocomplete' => false,
+ ],
+ 'section' => 'target',
+ ];
+
+ if ( SpecialBlock::canBlockEmail( $this->getUser() ) ) {
+ $fields['DisableEmail'] = [
+ 'type' => 'check',
+ 'label-message' => $prefix . '-email-label',
+ 'default' => false,
+ 'section' => 'actions',
+ ];
+ }
+
+ if ( $this->getConfig()->get( 'BlockAllowsUTEdit' ) ) {
+ $fields['DisableUTEdit'] = [
+ 'type' => 'check',
+ 'label-message' => $prefix . '-usertalk-label',
+ 'default' => false,
+ 'section' => 'actions',
+ ];
+ }
+
+ $fields['Reblock'] = [
+ 'type' => 'check',
+ 'label-message' => $prefix . '-reblock-label',
+ 'default' => false,
+ 'section' => 'actions',
+ ];
+
+ $fields['Reason'] = [
+ 'type' => 'text',
+ 'maxlength' => 150,
+ 'required' => true,
+ 'autocomplete' => false,
+ 'section' => 'reason',
+ ];
+
+ $pageNoticeClass = 'ext-checkuser-investigate-block-notice';
+ $pageNoticePosition = [
+ 'type' => 'select',
+ 'cssclass' => $pageNoticeClass,
+ 'label-message' => $prefix . '-notice-position-label',
+ 'options-messages' => [
+ $prefix . '-notice-prepend' => 'prependtext',
+ $prefix . '-notice-replace' => 'text',
+ $prefix . '-notice-append' => 'appendtext',
+ ],
+ 'section' => 'options',
+ ];
+ $pageNoticeText = [
+ 'type' => 'text',
+ 'cssclass' => $pageNoticeClass,
+ 'label-message' => $prefix . '-notice-text-label',
+ 'default' => '',
+ 'section' => 'options',
+ ];
+
+ $fields['UserPageNotice'] = [
+ 'type' => 'check',
+ 'label-message' => $prefix . '-notice-user-page-label',
+ 'default' => false,
+ 'section' => 'options',
+ ];
+ $fields['UserPageNoticePosition'] = array_merge(
+ $pageNoticePosition,
+ [ 'default' => 'prependtext' ]
+ );
+ $fields['UserPageNoticeText'] = $pageNoticeText;
+
+ $fields['TalkPageNotice'] = [
+ 'type' => 'check',
+ 'label-message' => $prefix . '-notice-talk-page-label',
+ 'default' => false,
+ 'section' => 'options',
+ ];
+ $fields['TalkPageNoticePosition'] = array_merge(
+ $pageNoticePosition,
+ [ 'default' => 'appendtext' ]
+ );
+ $fields['TalkPageNoticeText'] = $pageNoticeText;
+
+ return $fields;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDescription() {
+ return $this->msg( $this->getMessagePrefix() )->text();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getMessagePrefix() {
+ return 'checkuser-' . strtolower( $this->getName() );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getGroupName() {
+ return 'users';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function onSubmit( array $data ) {
+ $this->blockedUsers = [];
+ $targets = explode( "\n", $data['Targets'] );
+ $canBlockEmail = SpecialBlock::canBlockEmail( $this->getUser() );
+
+ foreach ( $targets as $target ) {
+ $isIP = IPUtils::isIPAddress( $target );
+
+ if ( !$isIP ) {
+ $user = $this->userFactory->newFromName( $target );
+ if ( !$user || !$user->getId() ) {
+ continue;
+ }
+ }
+
+ $expiry = $isIP ? '1 week' : 'indefinite';
+ $blockEmail = $canBlockEmail ? $data['DisableEmail'] : false;
+
+ $result = SpecialBlock::processForm( [
+ 'Target' => $target,
+ 'Reason' => [ $data['Reason'] ],
+ 'Expiry' => $expiry,
+ 'HardBlock' => !$isIP,
+ 'CreateAccount' => true,
+ 'AutoBlock' => true,
+ 'DisableEmail' => $blockEmail,
+ 'DisableUTEdit' => $data['DisableUTEdit'] ?? false,
+ 'Reblock' => $data['Reblock'],
+ 'Confirm' => true,
+ 'Watch' => false,
+ ], $this->getContext() );
+
+ if ( $result === true ) {
+ $this->blockedUsers[] = $target;
+
+ if ( $data['UserPageNotice'] ) {
+ $this->addNoticeToPage(
+ $this->getTargetPage( NS_USER, $target ),
+ $data['UserPageNoticeText'],
+ $data['UserPageNoticePosition'],
+ $data['Reason']
+ );
+ }
+
+ if ( $data['TalkPageNotice'] ) {
+ $this->addNoticeToPage(
+ $this->getTargetPage( NS_USER_TALK, $target ),
+ $data['TalkPageNoticeText'],
+ $data['TalkPageNoticePosition'],
+ $data['Reason']
+ );
+ }
+ }
+ }
+
+ $blockedUsersCount = count( $this->blockedUsers );
+
+ $this->eventLogger->logEvent( [
+ 'action' => 'block',
+ 'targetsCount' => count( $targets ),
+ 'relevantTargetsCount' => $blockedUsersCount,
+ ] );
+
+ if ( $blockedUsersCount === 0 ) {
+ return $this->getMessagePrefix() . '-failure';
+ }
+
+ return true;
+ }
+
+ /**
+ * @param int $namespace
+ * @param string $target Must be a valid IP address or a valid user name
+ * @return string
+ */
+ private function getTargetPage( int $namespace, string $target ) : string {
+ return $this->titleFormatter->getPrefixedText(
+ new TitleValue( $namespace, $target )
+ );
+ }
+
+ /**
+ * Add a notice to a given page. The notice may be prepended or appended,
+ * or it may replace the page.
+ *
+ * @param string $title Page to which to add the notice
+ * @param string $notice The notice, as wikitext
+ * @param string $position One of 'prependtext', 'appendtext' or 'text'
+ * @param string $summary Edit summary
+ */
+ private function addNoticeToPage(
+ string $title,
+ string $notice,
+ string $position,
+ string $summary
+ ) : void {
+ $apiParams = [
+ 'action' => 'edit',
+ 'title' => $title,
+ $position => $notice,
+ 'summary' => $summary,
+ 'token' => $this->getUser()->getEditToken(),
+ ];
+
+ $api = new ApiMain(
+ new DerivativeRequest(
+ $this->getRequest(),
+ $apiParams,
+ true // was posted
+ ),
+ true // enable write
+ );
+
+ try {
+ $api->execute();
+ } catch ( Exception $e ) {
+ $this->noticesFailed = true;
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function onSuccess() {
+ $blockedUsers = array_map( function ( $userName ) {
+ $user = $this->userFactory->newFromName(
+ $userName,
+ UserNameUtils::RIGOR_NONE
+ );
+ return Linker::userLink( $user->getId(), $userName );
+ }, $this->blockedUsers );
+
+ $language = $this->getLanguage();
+ $prefix = $this->getMessagePrefix();
+
+ $blockedMessage = $this->msg( $prefix . '-success' )
+ ->rawParams( $language->listToText( $blockedUsers ) )
+ ->params( $language->formatNum( count( $blockedUsers ) ) )
+ ->parseAsBlock();
+
+ $out = $this->getOutput();
+ $out->setPageTitle( $this->msg( 'blockipsuccesssub' ) );
+ $out->addHtml( $blockedMessage );
+
+ if ( $this->noticesFailed ) {
+ $failedNoticesMessage = $this->msg( $prefix . '-notices-failed' );
+ $out->addHtml( $failedNoticesMessage );
+ }
+ }
+}
diff --git a/CheckUser/src/SpecialInvestigateLog.php b/CheckUser/src/SpecialInvestigateLog.php
new file mode 100644
index 00000000..1556f33d
--- /dev/null
+++ b/CheckUser/src/SpecialInvestigateLog.php
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+namespace MediaWiki\CheckUser;
+
+use FormSpecialPage;
+
+class SpecialInvestigateLog extends FormSpecialPage {
+ /** @var PagerFactory */
+ private $pagerFactory;
+
+ public function __construct( PagerFactory $pagerFactory ) {
+ parent::__construct( 'InvestigateLog', 'checkuser-log' );
+
+ $this->pagerFactory = $pagerFactory;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function execute( $par ) {
+ // Perform access check ourselves. A filters form will be
+ // defined in a follow up task and parent::execute()
+ // can be used instead
+ // @see parent::execute().
+ $this->setParameter( $par );
+ $this->setHeaders();
+
+ // This will throw exceptions if there's a problem
+ $this->checkExecutePermissions( $this->getUser() );
+
+ $securityLevel = $this->getLoginSecurityLevel();
+ if ( $securityLevel !== false && !$this->checkLoginSecurityLevel( $securityLevel ) ) {
+ return;
+ }
+ // @see parent::execute() for above block
+
+ $pager = $this->pagerFactory->createPager( $this->getContext() );
+ $this->getOutput()->addHTML(
+ $pager->getNavigationBar() .
+ $pager->getBody() .
+ $pager->getNavigationBar()
+ );
+
+ $this->addPageSubtitle();
+ }
+
+ /**
+ * Add page subtitle linking to Special:Investigate
+ */
+ private function addPageSubtitle() {
+ $subtitle = $this->getLinkRenderer()->makeKnownLink(
+ self::getTitleFor( 'Investigate' ),
+ $this->msg( 'checkuser-investigate-log-subtitle' )->text()
+ );
+ $this->getOutput()->addSubtitle( $subtitle );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFormFields() {
+ return [];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function requiresWrite() {
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getDescription() {
+ return $this->msg( 'checkuser-investigate-log' )->text();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function getGroupName() {
+ return 'users';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function onSubmit( array $data ) {
+ return false;
+ }
+}
diff --git a/CheckUser/src/TimelinePager.php b/CheckUser/src/TimelinePager.php
new file mode 100644
index 00000000..3252579e
--- /dev/null
+++ b/CheckUser/src/TimelinePager.php
@@ -0,0 +1,185 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Html;
+use IContextSource;
+use MediaWiki\CheckUser\Hook\CheckUserFormatRowHook;
+use MediaWiki\Linker\LinkRenderer;
+use ParserOutput;
+use ReverseChronologicalPager;
+
+class TimelinePager extends ReverseChronologicalPager {
+ /** @var CheckUserFormatRowHook */
+ private $formatRowHookRunner;
+
+ /** @var TimelineService */
+ private $timelineService;
+
+ /** @var TimelineRowFormatter */
+ private $timelineRowFormatter;
+
+ /** @var string */
+ private $start;
+
+ /** @var string|null */
+ private $lastDateHeader;
+
+ /** @var TokenQueryManager */
+ private $tokenQueryManager;
+
+ /**
+ * Targets whose results should not be included in the investigation.
+ * Targets in this list may or may not also be in the $targets list.
+ * Either way, no activity related to these targets will appear in the
+ * results.
+ *
+ * @var string[]
+ */
+ private $excludeTargets;
+
+ /**
+ * Targets that have been added to the investigation but that are not
+ * present in $excludeTargets. These are the targets that will actually
+ * be investigated.
+ *
+ * @var string[]
+ */
+ private $filteredTargets;
+
+ public function __construct(
+ IContextSource $context,
+ LinkRenderer $linkRenderer,
+ CheckUserFormatRowHook $formatRowHookRunner,
+ TokenQueryManager $tokenQueryManager,
+ DurationManager $durationManager,
+ TimelineService $timelineService,
+ TimelineRowFormatter $timelineRowFormatter
+ ) {
+ parent::__construct( $context, $linkRenderer );
+ $this->formatRowHookRunner = $formatRowHookRunner;
+ $this->timelineService = $timelineService;
+ $this->timelineRowFormatter = $timelineRowFormatter;
+ $this->tokenQueryManager = $tokenQueryManager;
+
+ $tokenData = $tokenQueryManager->getDataFromRequest( $context->getRequest() );
+ $this->mOffset = $tokenData['offset'] ?? '';
+ $this->excludeTargets = $tokenData['exclude-targets'] ?? [];
+ $this->filteredTargets = array_diff(
+ $tokenData['targets'] ?? [],
+ $this->excludeTargets
+ );
+ $this->start = $durationManager->getTimestampFromRequest( $context->getRequest() );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getQueryInfo() {
+ return $this->timelineService->getQueryInfo(
+ $this->filteredTargets,
+ $this->excludeTargets,
+ $this->start
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getIndexField() {
+ return [ [ 'cuc_timestamp', 'cuc_id' ] ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function formatRow( $row ) {
+ $line = '';
+ $dateHeader = $this->getLanguage()->userDate( wfTimestamp( TS_MW, $row->cuc_timestamp ), $this->getUser() );
+ if ( $this->lastDateHeader === null ) {
+ $this->lastDateHeader = $dateHeader;
+ $line .= Html::rawElement( 'h4', [], $dateHeader );
+ $line .= Html::openElement( 'ul' );
+ } elseif ( $this->lastDateHeader !== $dateHeader ) {
+ $this->lastDateHeader = $dateHeader;
+
+ // Start a new list with a new date header
+ $line .= Html::closeElement( 'ul' );
+ $line .= Html::rawElement( 'h4', [], $dateHeader );
+ $line .= Html::openElement( 'ul' );
+ }
+
+ $rowItems = $this->timelineRowFormatter->getFormattedRowItems( $row );
+
+ $this->formatRowHookRunner->onCheckUserFormatRow( $this->getContext(), $row, $rowItems );
+
+ if ( !is_array( $rowItems ) || !isset( $rowItems['links'] ) || !isset( $rowItems['info'] ) ) {
+ wfDebugLog(
+ __CLASS__,
+ __METHOD__ . ': Expected array with keys \'links\' and \'info\''
+ . ' from CheckUserFormatRow $rowItems param'
+ );
+ return '';
+ }
+
+ $formattedLinks = implode( ' ', array_filter(
+ $rowItems['links'],
+ function ( $item ) {
+ return $item !== '';
+ } )
+ );
+
+ $formatted = implode( ' . . ', array_filter(
+ array_merge(
+ [ $formattedLinks ],
+ $rowItems['info']
+ ), function ( $item ) {
+ return $item !== '';
+ } )
+ );
+
+ $line .= Html::rawElement(
+ 'li',
+ [],
+ $formatted
+ );
+
+ return $line;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEmptyBody() {
+ return Html::rawElement( 'p', [], $this->msg( 'checkuser-investigate-timeline-empty' )->text() );
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Conceal the offset which may reveal private data.
+ */
+ public function getPagingQueries() {
+ return $this->tokenQueryManager->getPagingQueries(
+ $this->getRequest(), parent::getPagingQueries()
+ );
+ }
+
+ /**
+ * Get the formatted result list, with naviation bars.
+ *
+ * @return ParserOutput
+ */
+ public function getFullOutput() : ParserOutput {
+ return new ParserOutput(
+ $this->getNavigationBar() . $this->getBody() . $this->getNavigationBar()
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getEndBody() {
+ return $this->getNumRows() ? Html::closeElement( 'ul' ) : '';
+ }
+}
diff --git a/CheckUser/src/TimelinePagerFactory.php b/CheckUser/src/TimelinePagerFactory.php
new file mode 100644
index 00000000..04d1a37a
--- /dev/null
+++ b/CheckUser/src/TimelinePagerFactory.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use IContextSource;
+use MediaWiki\CheckUser\Hook\CheckUserFormatRowHook;
+use MediaWiki\Linker\LinkRenderer;
+
+class TimelinePagerFactory implements PagerFactory {
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ /** @var CheckUserFormatRowHook */
+ private $formatRowHookRunner;
+
+ /** @var TokenQueryManager */
+ private $tokenQueryManager;
+
+ /** @var DurationManager */
+ private $durationManager;
+
+ /** @var TimelineService */
+ private $service;
+
+ /** @var TimelineRowFormatterFactory */
+ private $rowFormatterFactory;
+
+ public function __construct(
+ LinkRenderer $linkRenderer,
+ CheckUserFormatRowHook $formatRowHookRunner,
+ TokenQueryManager $tokenQueryManager,
+ DurationManager $durationManager,
+ TimelineService $service,
+ TimelineRowFormatterFactory $rowFormatterFactory
+ ) {
+ $this->linkRenderer = $linkRenderer;
+ $this->formatRowHookRunner = $formatRowHookRunner;
+ $this->tokenQueryManager = $tokenQueryManager;
+ $this->durationManager = $durationManager;
+ $this->service = $service;
+ $this->rowFormatterFactory = $rowFormatterFactory;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function createPager( IContextSource $context ) : TimelinePager {
+ $rowFormatter = $this->rowFormatterFactory->createRowFormatter(
+ $context->getUser(), $context->getLanguage()
+ );
+
+ return new TimelinePager(
+ $context,
+ $this->linkRenderer,
+ $this->formatRowHookRunner,
+ $this->tokenQueryManager,
+ $this->durationManager,
+ $this->service,
+ $rowFormatter
+ );
+ }
+}
diff --git a/CheckUser/src/TimelineRowFormatter.php b/CheckUser/src/TimelineRowFormatter.php
new file mode 100644
index 00000000..7b67e4aa
--- /dev/null
+++ b/CheckUser/src/TimelineRowFormatter.php
@@ -0,0 +1,368 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Html;
+use HtmlArmor;
+use Language;
+use Linker;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Revision\RevisionFactory;
+use MediaWiki\Revision\RevisionLookup;
+use MediaWiki\Revision\RevisionRecord;
+use MediaWiki\Revision\RevisionStore;
+use MediaWiki\SpecialPage\SpecialPageFactory;
+use Message;
+use TitleFormatter;
+use TitleValue;
+use User;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+class TimelineRowFormatter {
+
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ /** @var ILoadBalancer */
+ private $loadBalancer;
+
+ /** @var RevisionLookup */
+ private $revisionLookup;
+
+ /** @var RevisionStore */
+ private $revisionStore;
+
+ /** @var RevisionFactory */
+ private $revisionFactory;
+
+ /** @var TitleFormatter */
+ private $titleFormatter;
+
+ /** @var SpecialPageFactory */
+ private $specialPageFactory;
+
+ /** @var array */
+ private $message = [];
+
+ /** @var Language */
+ private $language;
+
+ /** @var User */
+ private $user;
+
+ public function __construct(
+ LinkRenderer $linkRenderer,
+ ILoadBalancer $loadBalancer,
+ RevisionLookup $revisionLookup,
+ RevisionStore $revisionStore,
+ RevisionFactory $revisionFactory,
+ TitleFormatter $titleFormatter,
+ SpecialPageFactory $specialPageFactory,
+ User $user,
+ Language $language
+ ) {
+ $this->linkRenderer = $linkRenderer;
+ $this->loadBalancer = $loadBalancer;
+ $this->revisionLookup = $revisionLookup;
+ $this->revisionStore = $revisionStore;
+ $this->revisionFactory = $revisionFactory;
+ $this->titleFormatter = $titleFormatter;
+ $this->specialPageFactory = $specialPageFactory;
+ $this->user = $user;
+ $this->language = $language;
+
+ $this->preCacheMessages();
+ }
+
+ /**
+ * Format cu_changes record and display appropiate information
+ * depending on user privileges
+ *
+ * @param \stdClass $row
+ * @return array
+ */
+ public function getFormattedRowItems( \stdClass $row ) : array {
+ return [
+ 'links' => [
+ 'logLink' => $this->getLogLink( $row ),
+ 'diffLink' => $this->getDiffLink( $row ),
+ 'historyLink' => $this->getHistoryLink( $row ),
+ 'newPageFlag' => $this->getNewPageFlag( (int)$row->cuc_type ),
+ 'minorFlag' => $this->getMinorFlag( (bool)$row->cuc_minor ),
+ ],
+ 'info' => [
+ 'title' => $this->getTitleLink( $row ),
+ 'time' => $this->getTime( $row->cuc_timestamp ),
+ 'userLinks' => $this->getUserLinks( $row ),
+ 'actionText' => $this->getActionText( $row->cuc_actiontext ),
+ 'ipInfo' => $this->getIpInfo( $row->cuc_ip ),
+ 'userAgent' => $this->getUserAgent( $row->cuc_agent ),
+ 'comment' => $this->getComment( $row ),
+ ],
+ ];
+ }
+
+ /**
+ * Show the comment, or redact if appropriate. If the revision is not found,
+ * show nothing.
+ *
+ * @param \stdClass $row
+ * @return string
+ */
+ private function getComment( \stdClass $row ) : string {
+ $comment = '';
+
+ if (
+ $row->cuc_this_oldid != 0 &&
+ ( $row->cuc_type == RC_EDIT || $row->cuc_type == RC_NEW )
+ ) {
+ $revRecord = $this->revisionLookup->getRevisionById( $row->cuc_this_oldid );
+ if ( !$revRecord ) {
+ // Revision may have been deleted
+ $db = $this->loadBalancer->getConnectionRef( DB_REPLICA );
+ $queryInfo = $this->revisionStore->getArchiveQueryInfo();
+ $archiveRow = $db->selectRow(
+ $queryInfo['tables'],
+ $queryInfo['fields'],
+ [ 'ar_rev_id' => $row->cuc_this_oldid ],
+ __METHOD__,
+ [],
+ $queryInfo['joins']
+ );
+ if ( $archiveRow ) {
+ $revRecord = $this->revisionFactory->newRevisionFromArchiveRow( $archiveRow );
+ }
+ }
+ if (
+ $revRecord instanceof RevisionRecord &&
+ RevisionRecord::userCanBitfield(
+ $revRecord->getVisibility(),
+ RevisionRecord::DELETED_COMMENT,
+ $this->user
+ )
+ ) {
+ $comment = Linker::revComment( $revRecord );
+ } else {
+ $comment = Linker::commentBlock(
+ $this->msg( 'rev-deleted-comment' )->text(),
+ null,
+ false,
+ null,
+ false
+ );
+ }
+ }
+
+ return $comment;
+ }
+
+ /**
+ * @param string $ip
+ * @return string
+ */
+ private function getIpInfo( string $ip ) : string {
+ // Note: in the old check user this links to self with ip as target. Can't do now
+ // because of token. We could prefill a new investigation tab
+ return $ip;
+ }
+
+ /**
+ * @param string $userAgent
+ * @return string
+ */
+ private function getUserAgent( string $userAgent ) : string {
+ return htmlspecialchars( $userAgent );
+ }
+
+ /**
+ * @param string $actionText
+ * @return string
+ */
+ private function getActionText( string $actionText ) : string {
+ return Linker::formatComment( $actionText );
+ }
+
+ /**
+ * @param \stdClass $row
+ * @return string
+ */
+ private function getTitleLink( \stdClass $row ) : string {
+ if ( $row->cuc_type == RC_LOG ) {
+ return '';
+ }
+
+ $title = TitleValue::tryNew( (int)$row->cuc_namespace, $row->cuc_title );
+
+ if ( !$title ) {
+ return '';
+ }
+
+ return $this->linkRenderer->makeLink( $title );
+ }
+
+ /**
+ * @param \stdClass $row
+ * @return string
+ */
+ private function getLogLink( \stdClass $row ) : string {
+ if ( $row->cuc_type != RC_LOG ) {
+ return '';
+ }
+
+ $title = TitleValue::tryNew( (int)$row->cuc_namespace, $row->cuc_title );
+
+ if ( !$title ) {
+ return '';
+ }
+ return $this->msg( 'parentheses' )
+ ->rawParams(
+ $this->linkRenderer->makeKnownLink(
+ new TitleValue( NS_SPECIAL, $this->specialPageFactory->getLocalNameFor( 'Log' ) ),
+ new HtmlArmor( $this->message['log'] ),
+ [],
+ [ 'page' => $this->titleFormatter->getPrefixedText( $title ) ]
+ )
+ )->escaped();
+ }
+
+ /**
+ * @param \stdClass $row
+ * @return string
+ */
+ private function getDiffLink( \stdClass $row ) : string {
+ if ( $row->cuc_type == RC_NEW || $row->cuc_type == RC_LOG ) {
+ return '';
+ }
+
+ $title = TitleValue::tryNew( (int)$row->cuc_namespace, $row->cuc_title );
+
+ if ( !$title ) {
+ return '';
+ }
+
+ return $this->msg( 'parentheses' )
+ ->rawParams(
+ $this->linkRenderer->makeKnownLink(
+ $title,
+ new HtmlArmor( $this->message['diff'] ),
+ [],
+ [
+ 'curid' => $row->cuc_page_id,
+ 'diff' => $row->cuc_this_oldid,
+ 'oldid' => $row->cuc_last_oldid
+ ]
+ )
+ )->escaped();
+ }
+
+ /**
+ * @param \stdClass $row
+ * @return string
+ */
+ private function getHistoryLink( \stdClass $row ) : string {
+ if ( $row->cuc_type == RC_NEW || $row->cuc_type == RC_LOG ) {
+ return '';
+ }
+
+ $title = TitleValue::tryNew( (int)$row->cuc_namespace, $row->cuc_title );
+
+ if ( !$title ) {
+ return '';
+ }
+
+ return $this->msg( 'parentheses' )
+ ->rawParams(
+ $this->linkRenderer->makeKnownLink(
+ $title,
+ new HtmlArmor( $this->message['hist'] ),
+ [],
+ [
+ 'curid' => $row->cuc_page_id,
+ 'action' => 'history'
+ ]
+ )
+ )->escaped();
+ }
+
+ /**
+ * @param int $type
+ * @return string
+ */
+ private function getNewPageFlag( int $type ) : string {
+ if ( $type == RC_NEW ) {
+ return Html::rawElement( 'span',
+ [ 'class' => 'newpage' ],
+ $this->message['newpageletter']
+ );
+ }
+ return '';
+ }
+
+ /**
+ * @param bool $minor
+ * @return string
+ */
+ private function getMinorFlag( bool $minor ) : string {
+ if ( $minor ) {
+ return Html::rawElement(
+ 'span',
+ [ 'class' => 'minor' ],
+ $this->message['minoreditletter']
+ );
+ }
+ return '';
+ }
+
+ /**
+ * @param string $timestamp
+ * @return string
+ */
+ private function getTime( string $timestamp ) : string {
+ return htmlspecialchars(
+ $this->language->userTime( wfTimestamp( TS_MW, $timestamp ), $this->user )
+ );
+ }
+
+ /**
+ * @param \stdClass $row
+ * @return string
+ */
+ private function getUserLinks( \stdClass $row ) : string {
+ // Note: this is incomplete. It should match the checks
+ // in SpecialCheckUser when displaying the same info
+ $user = User::newFromId( $row->cuc_user );
+ $userId = $user->getId();
+
+ $links = Html::rawElement(
+ 'span', [], Linker::userLink( $userId, $user->getName() )
+ );
+
+ $links .= Linker::userToolLinksRedContribs(
+ $userId,
+ $user->getName(),
+ $user->getEditCount()
+ );
+
+ return $links;
+ }
+
+ /**
+ * As we use the same small set of messages in various methods and that
+ * they are called often, we call them once and save them in $this->message
+ */
+ private function preCacheMessages() {
+ $msgKeys = [ 'diff', 'hist', 'minoreditletter', 'newpageletter', 'blocklink', 'log' ];
+ foreach ( $msgKeys as $msg ) {
+ $this->message[$msg] = $this->msg( $msg )->escaped();
+ }
+ }
+
+ /**
+ * @param string $key
+ * @param array $params
+ * @return Message
+ */
+ private function msg( string $key, array $params = [] ) : Message {
+ return new Message( $key, $params, $this->language );
+ }
+}
diff --git a/CheckUser/src/TimelineRowFormatterFactory.php b/CheckUser/src/TimelineRowFormatterFactory.php
new file mode 100644
index 00000000..847126f6
--- /dev/null
+++ b/CheckUser/src/TimelineRowFormatterFactory.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Language;
+use MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Revision\RevisionFactory;
+use MediaWiki\Revision\RevisionLookup;
+use MediaWiki\Revision\RevisionStore;
+use MediaWiki\SpecialPage\SpecialPageFactory;
+use TitleFormatter;
+use User;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+class TimelineRowFormatterFactory {
+
+ /** @var LinkRenderer */
+ private $linkRenderer;
+
+ /** @var ILoadBalancer */
+ private $loadBalancer;
+
+ /** @var RevisionLookup */
+ private $revisionLookup;
+
+ /** @var RevisionStore */
+ private $revisionStore;
+
+ /** @var RevisionFactory */
+ private $revisionFactory;
+
+ /** @var TitleFormatter */
+ private $titleFormatter;
+
+ /** @var SpecialPageFactory */
+ private $specialPageFactory;
+
+ public function __construct(
+ LinkRenderer $linkRenderer,
+ ILoadBalancer $loadBalancer,
+ RevisionLookup $revisionLookup,
+ RevisionStore $revisionStore,
+ RevisionFactory $revisionFactory,
+ TitleFormatter $titleFormatter,
+ SpecialPageFactory $specialPageFactory
+ ) {
+ $this->linkRenderer = $linkRenderer;
+ $this->loadBalancer = $loadBalancer;
+ $this->revisionLookup = $revisionLookup;
+ $this->revisionStore = $revisionStore;
+ $this->revisionFactory = $revisionFactory;
+ $this->titleFormatter = $titleFormatter;
+ $this->specialPageFactory = $specialPageFactory;
+ }
+
+ /**
+ * Creates a row formatter
+ *
+ * @param User $user
+ * @param Language $language
+ * @return TimelineRowFormatter
+ */
+ public function createRowFormatter( User $user, Language $language ) : TimelineRowFormatter {
+ return new TimelineRowFormatter(
+ $this->linkRenderer,
+ $this->loadBalancer,
+ $this->revisionLookup,
+ $this->revisionStore,
+ $this->revisionFactory,
+ $this->titleFormatter,
+ $this->specialPageFactory,
+ $user,
+ $language
+ );
+ }
+}
diff --git a/CheckUser/src/TimelineService.php b/CheckUser/src/TimelineService.php
new file mode 100644
index 00000000..4a1c3cec
--- /dev/null
+++ b/CheckUser/src/TimelineService.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+class TimelineService extends ChangeService {
+ /**
+ * Get timeline query info
+ *
+ * @param string[] $targets
+ * @param string[] $excludeTargets
+ * @param string $start
+ * @return array
+ */
+ public function getQueryInfo( array $targets, array $excludeTargets, string $start ): array {
+ return [
+ 'tables' => 'cu_changes',
+ 'fields' => [
+ 'cuc_namespace', 'cuc_title', 'cuc_user', 'cuc_user_text', 'cuc_comment',
+ 'cuc_actiontext', 'cuc_timestamp', 'cuc_minor', 'cuc_page_id', 'cuc_type',
+ 'cuc_this_oldid', 'cuc_last_oldid', 'cuc_ip', 'cuc_xff', 'cuc_agent', 'cuc_id',
+ ],
+ 'conds' => array_merge(
+ $this->buildTargetCondsMultiple( $targets ),
+ $this->buildExcludeTargetsConds( $excludeTargets ),
+ $this->buildStartConds( $start )
+ ),
+ ];
+ }
+}
diff --git a/CheckUser/src/TokenManager.php b/CheckUser/src/TokenManager.php
new file mode 100644
index 00000000..e0606df3
--- /dev/null
+++ b/CheckUser/src/TokenManager.php
@@ -0,0 +1,181 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Firebase\JWT\JWT;
+use MediaWiki\Session\Session;
+
+class TokenManager {
+ /** @var string */
+ private const SIGNING_ALGO = 'HS256';
+
+ /** @var string|null */
+ private $cipherMethod;
+
+ /** @var string */
+ private $secret;
+
+ /**
+ * @param string $secret
+ */
+ public function __construct(
+ string $secret
+ ) {
+ if ( $secret === '' ) {
+ throw new \Exception(
+ 'CheckUser Token Manager requires $wgSecretKey to be set.'
+ );
+ }
+ $this->secret = $secret;
+ }
+
+ /**
+ * Creates a token
+ *
+ * @param Session $session
+ * @param array $data
+ * @return string
+ */
+ public function encode( Session $session, array $data ) : string {
+ $key = $this->getSessionKey( $session );
+ return JWT::encode(
+ [
+ // Expiration Time https://tools.ietf.org/html/rfc7519#section-4.1.4
+ 'exp' => \MWTimestamp::time() + 86400, // 24 hours from now
+ // Encrypt the form data to pevent it from being leaked.
+ 'data' => $this->encrypt( $data, $this->getInitializationVector( $key ) ),
+ ],
+ $this->getSigningKey( $key ),
+ self::SIGNING_ALGO
+ );
+ }
+
+ /**
+ * Encrypt private data.
+ *
+ * @param mixed $input
+ * @param string $iv
+ * @return string
+ */
+ private function encrypt( $input, string $iv ) : string {
+ return openssl_encrypt(
+ \FormatJson::encode( $input ),
+ $this->getCipherMethod(),
+ $this->secret,
+ 0,
+ $iv
+ );
+ }
+
+ /**
+ * Decode the JWT and return the targets.
+ *
+ * @param Session $session
+ * @param string $token
+ * @return array
+ */
+ public function decode( Session $session, string $token ) : array {
+ $key = $this->getSessionKey( $session );
+ $payload = JWT::decode(
+ $token,
+ $this->getSigningKey( $key ),
+ [ self::SIGNING_ALGO ]
+ );
+
+ return $this->decrypt(
+ $payload->data,
+ $this->getInitializationVector( $key )
+ );
+ }
+
+ /**
+ * Decrypt private data.
+ *
+ * @param string $input
+ * @param string $iv
+ * @return array
+ */
+ private function decrypt( string $input, string $iv ) : array {
+ $decrypted = openssl_decrypt(
+ $input,
+ $this->getCipherMethod(),
+ $this->secret,
+ 0,
+ $iv
+ );
+
+ if ( $decrypted === false ) {
+ throw new \Exception( 'Decryption Failed' );
+ }
+
+ return \FormatJson::parse( $decrypted, \FormatJson::FORCE_ASSOC )->getValue();
+ }
+
+ /**
+ * Get the initialization vector.
+ *
+ * This must be consistent between encryption and decryption
+ * and must be no more than 16 bytes in length.
+ *
+ * @param string $sessionKey
+ * @return string
+ */
+ private function getInitializationVector( string $sessionKey ) : string {
+ return hash_hmac( 'md5', $sessionKey, $this->secret, true );
+ }
+
+ /**
+ * Decide what type of encryption to use, based on system capabilities.
+ *
+ * @see Session::getEncryptionAlgorithm()
+ *
+ * @return string
+ */
+ private function getCipherMethod() : string {
+ if ( !$this->cipherMethod ) {
+ $methods = openssl_get_cipher_methods();
+ if ( in_array( 'aes-256-ctr', $methods, true ) ) {
+ $this->cipherMethod = 'aes-256-ctr';
+ } elseif ( in_array( 'aes-256-cbc', $methods, true ) ) {
+ $this->cipherMethod = 'aes-256-cbc';
+ } else {
+ throw new \Exception( 'No valid cipher method found with openssl_get_cipher_methods()' );
+ }
+ }
+
+ return $this->cipherMethod;
+ }
+
+ /**
+ * Get the session key suitable for the signing key and initialization vector.
+ *
+ * For the initialization vector, this must be consistent between encryption and decryption
+ * and must be no more than 16 bytes in length.
+ *
+ * This is retrieved from the session or randomly generated and stored in the session. This means
+ * that a token cannot be shared between sessions.
+ *
+ * @param Session $session
+ *
+ * @return string
+ */
+ private function getSessionKey( Session $session ) : string {
+ $key = $session->get( 'CheckUserTokenKey' );
+ if ( $key === null ) {
+ $key = base64_encode( random_bytes( 16 ) );
+ $session->set( 'CheckUserTokenKey', $key );
+ }
+
+ return base64_decode( $key );
+ }
+
+ /**
+ * Get the signing key.
+ *
+ * @param string $sessionKey
+ * @return string
+ */
+ private function getSigningKey( string $sessionKey ) : string {
+ return hash_hmac( 'sha256', $sessionKey, $this->secret );
+ }
+}
diff --git a/CheckUser/src/TokenQueryManager.php b/CheckUser/src/TokenQueryManager.php
new file mode 100644
index 00000000..937c27d9
--- /dev/null
+++ b/CheckUser/src/TokenQueryManager.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use WebRequest;
+
+class TokenQueryManager {
+ /** @var TokenManager */
+ public $tokenManager;
+
+ /**
+ * @param TokenManager $tokenManager
+ */
+ public function __construct( TokenManager $tokenManager ) {
+ $this->tokenManager = $tokenManager;
+ }
+
+ /**
+ * Conceal the offset in pager pagination params
+ * which may reveal sensitive data.
+ *
+ * @param WebRequest $request
+ * @param array $queries
+ * @return array
+ */
+ public function getPagingQueries( WebRequest $request, array $queries ) : array {
+ $tokenData = $this->getDataFromRequest( $request );
+ foreach ( $queries as &$query ) {
+ if ( $query === false ) {
+ continue;
+ }
+
+ if ( isset( $query['offset'] ) ) {
+ // Move the offset into the token since it may contain sensitive information
+ $query['token'] = $this->updateToken( $request, [ 'offset' => $query['offset'] ] );
+ unset( $query['offset'] );
+ } elseif ( isset( $tokenData['offset'] ) ) {
+ // Remove the offset.
+ $query['token'] = $this->updateToken( $request, [ 'offset' => null ] );
+ }
+ }
+
+ return $queries;
+ }
+
+ /**
+ * Preforms an array merge on the updates with what is in the current token.
+ * Setting a value to null will remove it.
+ *
+ * @param WebRequest $request
+ * @param array $update
+ * @return string
+ */
+ public function updateToken( WebRequest $request, array $update ) : string {
+ $tokenData = $this->getDataFromRequest( $request );
+ $data = array_filter( array_merge( $tokenData, $update ), function ( $value ) {
+ return $value !== null;
+ } );
+
+ return $this->tokenManager->encode( $request->getSession(), $data );
+ }
+
+ /**
+ * Get token data
+ *
+ * @param WebRequest $request
+ * @return array
+ */
+ public function getDataFromRequest( WebRequest $request ) : array {
+ $token = $request->getVal( 'token' );
+
+ if ( empty( $token ) ) {
+ return [];
+ }
+
+ try {
+ return $this->tokenManager->decode( $request->getSession(), $token );
+ } catch ( \Exception $e ) {
+ return [];
+ }
+ }
+}
diff --git a/CheckUser/src/ToolLinksMessages.php b/CheckUser/src/ToolLinksMessages.php
new file mode 100644
index 00000000..7b4bf1db
--- /dev/null
+++ b/CheckUser/src/ToolLinksMessages.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use Config;
+use ResourceLoaderContext;
+
+class ToolLinksMessages {
+
+ public static function getParsedMessage(
+ ResourceLoaderContext $context,
+ Config $config,
+ string $messageKey
+ ) {
+ return [ $messageKey => $context->msg( $messageKey )->parse() ];
+ }
+}
diff --git a/CheckUser/src/UserManager.php b/CheckUser/src/UserManager.php
new file mode 100644
index 00000000..f5a0a6f9
--- /dev/null
+++ b/CheckUser/src/UserManager.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace MediaWiki\CheckUser;
+
+use User;
+
+/**
+ * User Manager to wrap static User methods.
+ *
+ * This service makes it easier to mock static User methods. The service can be removed when a
+ * better alternative exists in MediaWiki core.
+ *
+ * @see https://phabricator.wikimedia.org/T255276
+ *
+ * @internal
+ */
+class UserManager {
+ /**
+ * Get user ID from a user name.
+ *
+ * @param string $username
+ * @return int|null Id, or null if the username is invalid or non-existent
+ */
+ public function idFromName( string $username ) : ?int {
+ return User::idFromName( $username );
+ }
+}
diff --git a/CheckUser/tests/phpunit/ComparePagerTest.php b/CheckUser/tests/phpunit/ComparePagerTest.php
new file mode 100644
index 00000000..70e08181
--- /dev/null
+++ b/CheckUser/tests/phpunit/ComparePagerTest.php
@@ -0,0 +1,164 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use MediaWiki\CheckUser\ComparePager;
+use MediaWiki\CheckUser\CompareService;
+use MediaWiki\CheckUser\DurationManager;
+use MediaWiki\CheckUser\TokenQueryManager;
+use MediaWiki\CheckUser\UserManager;
+use MediaWiki\MediaWikiServices;
+use MediaWikiIntegrationTestCase;
+use RequestContext;
+use Wikimedia\IPUtils;
+
+/**
+ * @group CheckUser
+ * @group Database
+ * @covers \MediaWiki\CheckUser\ComparePager
+ */
+class ComparePagerTest extends MediaWikiIntegrationTestCase {
+
+ /**
+ * @dataProvider provideDoQuery
+ */
+ public function testDoQuery( $targets, $excludeTargets, $expected ) {
+ $services = MediaWikiServices::getInstance();
+
+ $tokenQueryManager = $this->getMockBuilder( TokenQueryManager::class )
+ ->disableOriginalConstructor()
+ ->setMethods( [ 'getDataFromRequest' ] )
+ ->getMock();
+ $tokenQueryManager->method( 'getDataFromRequest' )
+ ->willReturn( [
+ 'targets' => $targets,
+ 'exclude-targets' => $excludeTargets,
+ ] );
+
+ $userManager = $this->createMock( UserManager::class );
+ $userManager->method( 'idFromName' )
+ ->will(
+ $this->returnValueMap( [
+ [ 'User1', 11111, ],
+ [ 'User2', 22222, ],
+ [ 'InvalidUser', 0 ],
+ [ '', 0 ],
+ [ '1.2.3.9/120', 0 ]
+ ] )
+ );
+
+ $compareService = new CompareService(
+ $services->getDBLoadBalancer(),
+ $userManager
+ );
+
+ $durationManager = $this->createMock( DurationManager::class );
+
+ $pager = new ComparePager(
+ RequestContext::getMain(),
+ $services->get( 'LinkRenderer' ),
+ $tokenQueryManager,
+ $durationManager,
+ $compareService
+ );
+ $pager->doQuery();
+
+ $this->assertSame( $expected, $pager->mResult->numRows() );
+ }
+
+ public function provideDoQuery() {
+ // $targets, $excludeTargets, $expected
+ return [
+ 'Valid and invalid targets' => [ [ 'User1', 'InvalidUser', '1.2.3.9/120' ], [], 2 ],
+ 'Valid and empty targets' => [ [ 'User1', '' ], [], 2 ],
+ 'Valid user target' => [ [ 'User2' ], [], 1 ],
+ 'Valid user target with excluded name' => [ [ 'User2' ], [ 'User2' ], 0 ],
+ 'Valid user target with excluded IP' => [ [ 'User2' ], [ '1.2.3.4' ], 0 ],
+ 'Valid IP target' => [ [ '1.2.3.4' ], [], 4 ],
+ 'Valid IP target with users excluded' => [ [ '1.2.3.4' ], [ 'User1', 'User2' ], 2 ],
+ 'Valid IP range target' => [ [ '1.2.3.0/24' ], [], 7 ],
+ ];
+ }
+
+ public function addDBData() {
+ $testData = [
+ [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.4',
+ 'cuc_type' => RC_NEW,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.4',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.4',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'bar user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.5',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.5',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.5' ),
+ 'cuc_agent' => 'bar user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.5',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.5',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.5' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 11111,
+ 'cuc_user_text' => 'User1',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 22222,
+ 'cuc_user_text' => 'User2',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 11111,
+ 'cuc_user_text' => 'User1',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.5',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.5' ),
+ 'cuc_agent' => 'foo user agent',
+ ],
+ ];
+
+ $commonData = [
+ 'cuc_namespace' => NS_MAIN,
+ 'cuc_title' => 'Foo_Page',
+ 'cuc_minor' => 0,
+ 'cuc_page_id' => 1,
+ 'cuc_timestamp' => '',
+ 'cuc_xff' => 0,
+ 'cuc_xff_hex' => null,
+ 'cuc_actiontext' => '',
+ 'cuc_comment' => '',
+ 'cuc_this_oldid' => 0,
+ 'cuc_last_oldid' => 0,
+ ];
+
+ foreach ( $testData as $row ) {
+ $this->db->insert( 'cu_changes', $row + $commonData );
+ }
+
+ $this->tablesUsed[] = 'cu_changes';
+ }
+}
diff --git a/CheckUser/tests/phpunit/CompareServiceTest.php b/CheckUser/tests/phpunit/CompareServiceTest.php
new file mode 100644
index 00000000..074d9274
--- /dev/null
+++ b/CheckUser/tests/phpunit/CompareServiceTest.php
@@ -0,0 +1,376 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use MediaWiki\CheckUser\CompareService;
+use MediaWiki\CheckUser\UserManager;
+use MediaWiki\MediaWikiServices;
+use MediaWikiIntegrationTestCase;
+use Wikimedia\IPUtils;
+use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+/**
+ * @group CheckUser
+ * @group Database
+ * @covers \MediaWiki\CheckUser\CompareService
+ */
+class CompareServiceTest extends MediaWikiIntegrationTestCase {
+
+ /** @var CompareService */
+ private $service;
+
+ /**
+ * Lazy load CompareService
+ *
+ * @return CompareService
+ */
+ private function getCompareService(): CompareService {
+ if ( !$this->service ) {
+ $this->service = MediaWikiServices::getInstance()->get( 'CheckUserCompareService' );
+ }
+
+ return $this->service;
+ }
+
+ /**
+ * Sanity check for the subqueries built by getQueryInfo. Checks for the presence
+ * of valid targets and the presence of the expected per-target limit. Whitespace
+ * is not always predictable so look for the bare minimum in the SQL string.
+ *
+ * Invalid targets are tested in ComparePagerTest::testDoQuery.
+ *
+ * @dataProvider provideGetQueryInfo
+ */
+ public function testGetQueryInfo( $options, $expected ) {
+ $db = $this->getMockBuilder( Database::class )
+ ->setMethods( [
+ 'dbSchema',
+ 'tablePrefix',
+ ] )
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $db->method( 'strencode' )
+ ->will( $this->returnArgument( 0 ) );
+ $db->method( 'dbSchema' )
+ ->willReturn( '' );
+ $db->method( 'tablePrefix' )
+ ->willReturn( '' );
+
+ $loadBalancer = $this->createMock( ILoadBalancer::class );
+ $loadBalancer->method( 'getConnectionRef' )
+ ->willReturn( $db );
+
+ $userManager = $this->createMock( UserManager::class );
+ $userManager->method( 'idFromName' )
+ ->will( $this->returnValueMap( [
+ [ 'User1', 11111, ],
+ [ 'User2', 22222, ],
+ ] ) );
+
+ $compareService = new CompareService(
+ $loadBalancer,
+ $userManager
+ );
+
+ $queryInfo = $compareService->getQueryInfo(
+ $options['targets'],
+ $options['excludeTargets'],
+ $options['start']
+ );
+
+ foreach ( $expected['targets'] as $target ) {
+ $this->assertStringContainsString( $target, $queryInfo['tables']['a'] );
+ }
+
+ foreach ( $expected['excludeTargets'] as $excludeTarget ) {
+ $this->assertStringContainsString( $excludeTarget, $queryInfo['tables']['a'] );
+ }
+
+ $this->assertStringContainsString( 'LIMIT ' . $expected['limit'], $queryInfo['tables']['a'] );
+
+ [ 'start' => $start ] = $expected;
+ if ( $start === '' ) {
+ $this->assertStringNotContainsString( 'cuc_timestamp >=', $queryInfo['tables']['a'] );
+ } else {
+ $this->assertStringContainsString( "cuc_timestamp >= '$start'", $queryInfo['tables']['a'] );
+ }
+ }
+
+ public function provideGetQueryInfo() {
+ return [
+ 'Valid username, excluded IP' => [
+ [
+ 'targets' => [ 'User1' ],
+ 'excludeTargets' => [ '0:0:0:0:0:0:0:1' ],
+ 'start' => ''
+ ],
+ [
+ 'targets' => [ '11111' ],
+ 'excludeTargets' => [ 'v6-00000000000000000000000000000001' ],
+ 'limit' => '100000',
+ 'start' => ''
+ ],
+ ],
+ 'Valid username, excluded IP, with start' => [
+ [
+ 'targets' => [ 'User1' ],
+ 'excludeTargets' => [ '0:0:0:0:0:0:0:1' ],
+ 'start' => '111'
+ ],
+ [
+ 'targets' => [ '11111' ],
+ 'excludeTargets' => [ 'v6-00000000000000000000000000000001' ],
+ 'limit' => '100000',
+ 'start' => '111'
+ ],
+ ],
+ 'Single valid IP, excluded username' => [
+ [
+ 'targets' => [ '0:0:0:0:0:0:0:1' ],
+ 'excludeTargets' => [ 'User1' ],
+ 'start' => ''
+ ],
+ [
+ 'targets' => [ 'v6-00000000000000000000000000000001' ],
+ 'excludeTargets' => [ '11111' ],
+ 'limit' => '100000',
+ 'start' => ''
+ ],
+ ],
+ 'Valid username and IP, excluded username and IP' => [
+ [
+ 'targets' => [ 'User1', '1.2.3.4' ],
+ 'excludeTargets' => [ 'User2', '1.2.3.5' ],
+ 'start' => ''
+ ],
+ [
+ 'targets' => [ '11111', '01020304' ],
+ 'excludeTargets' => [ '22222', '01020305' ],
+ 'limit' => '50000',
+ 'start' => ''
+ ],
+ ],
+ 'Two valid IPs' => [
+ [
+ 'targets' => [ '0:0:0:0:0:0:0:1', '1.2.3.4' ],
+ 'excludeTargets' => [],
+ 'start' => ''
+ ],
+ [
+ 'targets' => [
+ 'v6-00000000000000000000000000000001',
+ '01020304'
+ ],
+ 'excludeTargets' => [],
+ 'limit' => '50000',
+ 'start' => ''
+ ],
+ ],
+ 'Valid IP addresses and IP range' => [
+ [
+ 'targets' => [
+ '0:0:0:0:0:0:0:1',
+ '1.2.3.4',
+ '1.2.3.4/16',
+ ],
+ 'excludeTargets' => [],
+ 'start' => ''
+ ],
+ [
+ 'targets' => [
+ 'v6-00000000000000000000000000000001',
+ '01020304',
+ '01020000',
+ '0102FFFF',
+ ],
+ 'excludeTargets' => [],
+ 'limit' => '33333',
+ 'start' => ''
+ ],
+ ],
+ ];
+ }
+
+ public function testGetQueryInfoNoTargets() {
+ $this->expectException( \LogicException::class );
+
+ $compareService = new CompareService(
+ $this->createMock( ILoadBalancer::class ),
+ $this->createMock( UserManager::class )
+ );
+
+ $compareService->getQueryInfo( [], [], '' );
+ }
+
+ /**
+ * @dataProvider provideGetQueryInfoForSingleTarget
+ */
+ public function testGetQueryInfoForSingleTarget( $options, $expected ) {
+ $db = $this->getMockBuilder( Database::class )
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $db->method( 'strencode' )
+ ->will( $this->returnArgument( 0 ) );
+
+ $loadBalancer = $this->createMock( ILoadBalancer::class );
+ $loadBalancer->method( 'getConnectionRef' )
+ ->willReturn( $db );
+
+ $compareServcice = new CompareService(
+ $loadBalancer,
+ $this->createMock( UserManager::class )
+ );
+
+ $info = $compareServcice->getQueryInfoForSingleTarget(
+ '1.2.3.4',
+ [],
+ '',
+ $options['limitPerTarget'],
+ $options['limitCheck']
+ );
+
+ $this->assertSame( $expected['orderBy'], $info['options']['ORDER BY'] );
+ $this->assertSame( $expected['limit'], $info['options']['LIMIT'] );
+ $this->assertSame( $expected['offset'], $info['options']['OFFSET'] );
+ }
+
+ public function provideGetQueryInfoForSingleTarget() {
+ $limitPerTarget = 100;
+ return [
+ 'Main investigation' => [
+ [
+ 'limitPerTarget' => $limitPerTarget,
+ 'limitCheck' => false,
+ ],
+ [
+ 'orderBy' => 'cuc_timestamp DESC',
+ 'offset' => null,
+ 'limit' => $limitPerTarget
+ ]
+ ],
+ 'Limit check' => [
+ [
+ 'limitPerTarget' => $limitPerTarget,
+ 'limitCheck' => true,
+ ],
+ [
+ 'orderBy' => null,
+ 'offset' => $limitPerTarget,
+ 'limit' => 1
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideTotalEditsFromIp()
+ */
+ public function testGetTotalEditsFromIp( $data, $expected ) {
+ $result = $this->getCompareService()->getTotalEditsFromIp(
+ $data['ip'], $data['excludeUser'] ?? null
+ );
+
+ $this->assertEquals( $expected, $result );
+ }
+
+ public function provideTotalEditsFromIp() {
+ return [
+ 'IP address with multiple users' => [
+ [
+ 'ip' => IPUtils::toHex( '1.2.3.5' )
+ ],
+ 3,
+ ],
+ 'IP address with multiple users, excluding a user' => [
+ [
+ 'ip' => IPUtils::toHex( '1.2.3.4' ),
+ 'excludeUser' => 'User1'
+ ],
+ 4,
+ ],
+ ];
+ }
+
+ public function addDBData() {
+ $testData = [
+ [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.4',
+ 'cuc_type' => RC_NEW,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.4',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.4',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'bar user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.5',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.5',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.5' ),
+ 'cuc_agent' => 'bar user agent',
+ ], [
+ 'cuc_user' => 0,
+ 'cuc_user_text' => '1.2.3.5',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.5',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.5' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 11111,
+ 'cuc_user_text' => 'User1',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 22222,
+ 'cuc_user_text' => 'User2',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.4',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.4' ),
+ 'cuc_agent' => 'foo user agent',
+ ], [
+ 'cuc_user' => 11111,
+ 'cuc_user_text' => 'User1',
+ 'cuc_type' => RC_EDIT,
+ 'cuc_ip' => '1.2.3.5',
+ 'cuc_ip_hex' => IPUtils::toHex( '1.2.3.5' ),
+ 'cuc_agent' => 'foo user agent',
+ ],
+ ];
+
+ $commonData = [
+ 'cuc_namespace' => NS_MAIN,
+ 'cuc_title' => 'Foo_Page',
+ 'cuc_minor' => 0,
+ 'cuc_page_id' => 1,
+ 'cuc_timestamp' => '',
+ 'cuc_xff' => 0,
+ 'cuc_xff_hex' => null,
+ 'cuc_actiontext' => '',
+ 'cuc_comment' => '',
+ 'cuc_this_oldid' => 0,
+ 'cuc_last_oldid' => 0,
+ ];
+
+ foreach ( $testData as $row ) {
+ $this->db->insert( 'cu_changes', $row + $commonData );
+ }
+
+ $this->tablesUsed[] = 'cu_changes';
+ }
+}
diff --git a/CheckUser/tests/phpunit/DurationManagerTest.php b/CheckUser/tests/phpunit/DurationManagerTest.php
new file mode 100644
index 00000000..501c1a06
--- /dev/null
+++ b/CheckUser/tests/phpunit/DurationManagerTest.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use FauxRequest;
+use MediaWiki\CheckUser\DurationManager;
+use MediaWikiIntegrationTestCase;
+
+/**
+ * @group CheckUser
+ * @covers \MediaWiki\CheckUser\DurationManager
+ */
+class DurationManagerTest extends MediaWikiIntegrationTestCase {
+
+ public function setUp() : void {
+ parent::setUp();
+ \MWTimestamp::setFakeTime( 0 );
+ }
+
+ /**
+ * @dataProvider provideDuration
+ */
+ public function testGetFromRequest( string $duration, string $timestamp ) : void {
+ $valid = ( $timestamp !== '' );
+ $durationManager = new DurationManager();
+
+ $request = new FauxRequest( [
+ 'duration' => $duration,
+ ] );
+
+ $this->assertSame( $valid ? $duration : '', $durationManager->getFromRequest( $request ) );
+ }
+
+ /**
+ * @dataProvider provideDuration
+ */
+ public function testIsValid( string $duration, string $timestamp ) : void {
+ $valid = ( $timestamp !== '' );
+ $durationManager = new DurationManager();
+
+ $this->assertSame( $valid, $durationManager->isValid( $duration ) );
+ }
+
+ /**
+ * @dataProvider provideDuration
+ */
+ public function testGetTimestampFromRequest( string $duration, string $timestamp ) : void {
+ $durationManager = new DurationManager();
+
+ $request = new FauxRequest( [
+ 'duration' => $duration,
+ ] );
+
+ $this->assertSame( $timestamp, $durationManager->getTimestampFromRequest( $request ) );
+ }
+
+ /**
+ * Provides durations.
+ */
+ public function provideDuration() : array {
+ return [
+ 'Valid duration' => [
+ 'P1W',
+ '19691225000000',
+ ],
+ 'Invalid duration' => [
+ 'fail!',
+ '',
+ ],
+ ];
+ }
+}
diff --git a/CheckUser/tests/phpunit/PreliminaryCheckPagerTest.php b/CheckUser/tests/phpunit/PreliminaryCheckPagerTest.php
new file mode 100644
index 00000000..51af6ac4
--- /dev/null
+++ b/CheckUser/tests/phpunit/PreliminaryCheckPagerTest.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use ExtensionRegistry;
+use MediaWiki\CheckUser\PreliminaryCheckPager;
+use MediaWiki\CheckUser\PreliminaryCheckService;
+use MediaWiki\CheckUser\TokenQueryManager;
+use MediaWiki\MediaWikiServices;
+use MediaWiki\User\UserGroupManagerFactory;
+use MediaWikiIntegrationTestCase;
+use RequestContext;
+use Wikimedia\Rdbms\ILBFactory;
+
+/**
+ * @group CheckUser
+ * @covers \MediaWiki\CheckUser\PreliminaryCheckPager
+ */
+class PreliminaryCheckPagerTest extends MediaWikiIntegrationTestCase {
+
+ /**
+ * @return MockObject|ExtensionRegistry
+ */
+ private function getMockExtensionRegistry() {
+ return $this->getMockBuilder( ExtensionRegistry::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return MockObject|TokenQueryManager
+ */
+ private function getMockTokenQueryManager() {
+ return $this->getMockBuilder( TokenQueryManager::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return MockObject|PreliminaryCheckService
+ */
+ private function getMockPreliminaryCheckService() {
+ return $this->getMockBuilder( PreliminaryCheckService::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ public function testGetQueryInfoFiltersIPsFromTargets() {
+ $registry = $this->getMockExtensionRegistry();
+ $registry->method( 'isLoaded' )->willReturn( true );
+
+ $tokenQueryManager = $this->getMockTokenQueryManager();
+ $tokenQueryManager->method( 'getDataFromRequest' )->willReturn( [
+ 'targets' => [ 'UserA', 'UserB', '1.2.3.4' ]
+ ] );
+
+ $lbf = $this->getMockBuilder( ILBFactory::class )
+ ->disableOriginalConstructor()->getMock();
+
+ $preliminaryCheckService = new PreliminaryCheckService(
+ $lbf,
+ $registry,
+ $this->createNoOpMock( UserGroupManagerFactory::class ),
+ 'testwiki'
+ );
+
+ $services = MediaWikiServices::getInstance();
+ $pager = new PreliminaryCheckPager( RequestContext::getMain(),
+ $services->getLinkRenderer(),
+ $services->getNamespaceInfo(),
+ $tokenQueryManager,
+ $registry,
+ $preliminaryCheckService
+ );
+
+ $result = $pager->getQueryInfo();
+
+ $expected = [
+ 'tables' => 'localuser',
+ 'fields' => [
+ 'lu_name',
+ 'lu_wiki',
+ ],
+ 'conds' => [ 'lu_name' => [ 'UserA', 'UserB' ] ]
+ ];
+ $this->assertSame( $expected, $result );
+ }
+
+ public function testGetIndexFieldLocal() {
+ $services = MediaWikiServices::getInstance();
+ $pager = new PreliminaryCheckPager(
+ RequestContext::getMain(),
+ $services->getLinkRenderer(),
+ $services->getNamespaceInfo(),
+ $services->get( 'CheckUserTokenQueryManager' ),
+ $this->getMockExtensionRegistry(),
+ $this->getMockPreliminaryCheckService()
+ );
+ $this->assertEquals( 'user_name', $pager->getIndexfield() );
+ }
+
+ public function testGetIndexFieldGlobal() {
+ $services = MediaWikiServices::getInstance();
+ $registry = $this->getMockExtensionRegistry();
+ $preliminaryCheckService = $this->getMockPreliminaryCheckService();
+ $pager = $this->getMockBuilder( PreliminaryCheckPager::class )
+ ->setConstructorArgs( [ RequestContext::getMain(),
+ $services->getLinkRenderer(),
+ $services->getNamespaceInfo(),
+ $services->get( 'CheckUserTokenQueryManager' ),
+ $registry,
+ $preliminaryCheckService
+ ] )
+ ->setMethods( [ 'isGlobalCheck' ] )
+ ->getMock();
+
+ $pager->method( 'isGlobalCheck' )->willReturn( true );
+ $this->assertEquals( [ [ 'lu_name', 'lu_wiki' ] ], $pager->getIndexfield() );
+ }
+}
diff --git a/CheckUser/tests/phpunit/PreliminaryCheckServiceTest.php b/CheckUser/tests/phpunit/PreliminaryCheckServiceTest.php
new file mode 100644
index 00000000..a88521a8
--- /dev/null
+++ b/CheckUser/tests/phpunit/PreliminaryCheckServiceTest.php
@@ -0,0 +1,228 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use ExtensionRegistry;
+use MediaWiki\CheckUser\PreliminaryCheckService;
+use MediaWiki\User\UserGroupManager;
+use MediaWiki\User\UserGroupManagerFactory;
+use MediaWikiIntegrationTestCase;
+use Wikimedia\Rdbms\FakeResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\ILBFactory;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+/**
+ * Test class for PreliminaryCheckService class
+ *
+ * @group CheckUser
+ * @covers \MediaWiki\CheckUser\PreliminaryCheckService
+ */
+class PreliminaryCheckServiceTest extends MediaWikiIntegrationTestCase {
+ /**
+ * @return MockObject|ILoadBalancer
+ */
+ private function getMockLoadBalancer() {
+ return $this->getMockBuilder( ILoadBalancer::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return MockObject|IDatabase
+ */
+ private function getMockDb() {
+ return $this->getMockBuilder( IDatabase::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return MockObject|ILBFactory
+ */
+ private function getMockLoadBalancerFactory() {
+ return $this->getMockBuilder( ILBFactory::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @return MockObject|ExtensionRegistry
+ */
+ private function getMockExtensionRegistry() {
+ return $this->getMockBuilder( ExtensionRegistry::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ /**
+ * @dataProvider preprocessResultsProvider()
+ */
+ public function testPreprocessResults( $user, $options, $expected ) {
+ $dbRef = $this->getMockDb();
+ $dbRef->method( 'selectRow' )
+ ->willReturn(
+ (object)[
+ 'user_id' => $user['id'],
+ 'user_name' => $user['name'],
+ 'user_registration' => $user['registration'],
+ 'user_editcount' => $user['editcount'],
+ ]
+ );
+
+ $lb = $this->getMockLoadBalancer();
+ $lb->method( 'getConnectionRef' )->willReturn( $dbRef );
+ $lbFactory = $this->getMockLoadBalancerFactory();
+ $lbFactory->method( 'getMainLB' )->willReturn( $lb );
+
+ $registry = $this->getMockExtensionRegistry();
+ $registry->method( 'isLoaded' )->willReturn( $options['isCentralAuthAvailable'] );
+
+ $ugm = $this->createNoOpMock( UserGroupManager::class, [ 'getUserGroups' ] );
+ $ugm->method( 'getUserGroups' )->willReturn( $user['groups'] );
+ $ugmf = $this->createNoOpMock( UserGroupManagerFactory::class, [ 'getUserGroupManager' ] );
+ $ugmf->method( 'getUserGroupManager' )->willReturn( $ugm );
+
+ $service = $this->getMockBuilder( PreliminaryCheckService::class )
+ ->setConstructorArgs( [
+ $lbFactory,
+ $registry,
+ $ugmf,
+ $options['localWikiId']
+ ] )
+ ->setMethods( [ 'getCentralAuthDB', 'isUserBlocked', 'getUserGroups' ] )
+ ->getMock();
+
+ $service->method( 'isUserBlocked' )
+ ->willReturn( $user['blocked'] );
+ $service->method( 'getUserGroups' )
+ ->willReturn( $user['groups'] );
+ $service->method( 'getCentralAuthDB' )
+ ->willReturn( $dbRef );
+
+ if ( $options['isCentralAuthAvailable'] ) {
+ $rows = new FakeResultWrapper( array_map(
+ function ( $wiki ) use ( $user ) {
+ return (object)[
+ 'lu_name' => $user['name'],
+ 'lu_wiki' => $wiki,
+ ];
+ },
+ $options['attachedWikis']
+ ) );
+ } else {
+ $rows = new FakeResultWrapper( [
+ [
+ 'user_id' => $user['id'],
+ 'user_name' => $user['name'],
+ 'user_registration' => $user['registration'],
+ 'user_editcount' => $user['editcount'],
+ 'wiki' => $options['localWikiId'],
+ ]
+ ] );
+ }
+
+ $data = $service->preprocessResults( $rows );
+ $this->assertEquals( $expected, $data );
+ }
+
+ public function preprocessResultsProvider() {
+ $userData = [
+ 'id' => 1,
+ 'name' => 'Test User',
+ 'registration' => '20190101010101',
+ 'editcount' => 20,
+ 'blocked' => true,
+ 'groups' => [ 'sysop', 'autoconfirmed' ],
+ ];
+
+ return [
+ 'User attached to 3 wikis' => [
+ $userData,
+ [
+ 'attachedWikis' => [ 'enwiki', 'frwiki', 'testwiki' ],
+ 'isCentralAuthAvailable' => true,
+ 'localWikiId' => 'testwiki',
+ ],
+ [
+ $userData + [ 'wiki' => 'enwiki' ],
+ $userData + [ 'wiki' => 'frwiki' ],
+ $userData + [ 'wiki' => 'testwiki' ],
+ ],
+ ],
+ 'User with only 1 wiki' => [
+ $userData,
+ [
+ 'attachedWikis' => [ 'testwiki' ],
+ 'isCentralAuthAvailable' => true,
+ 'localWikiId' => 'testwiki',
+ ],
+ [
+ $userData + [ 'wiki' => 'testwiki' ],
+ ],
+ ],
+ 'CentralAuth not available' => [
+ $userData,
+ [
+ 'isCentralAuthAvailable' => false,
+ 'localWikiId' => 'somewiki',
+ ],
+ [
+ $userData + [ 'wiki' => 'somewiki' ],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider getQueryInfoProvider()
+ */
+ public function testGetQueryInfo( $users, $options, $expected ) {
+ $lbFactory = $this->getMockLoadBalancerFactory();
+ $registry = $this->getMockExtensionRegistry();
+
+ $registry->method( 'isLoaded' )->willReturn( $options['isCentralAuthAvailable'] );
+
+ $service = new PreliminaryCheckService(
+ $lbFactory,
+ $registry,
+ $this->createNoOpMock( UserGroupManagerFactory::class ),
+ 'devwiki'
+ );
+ $result = $service->getQueryInfo( $users );
+
+ $this->assertSame(
+ array_replace_recursive( $result, $expected ),
+ $result
+ );
+ }
+
+ public function getQueryInfoProvider() {
+ return [
+ 'local users as string' => [
+ [ 'UserA', 'UserB' ],
+ [ 'isCentralAuthAvailable' => false ],
+ [
+ 'tables' => 'user',
+ 'conds' => [
+ 'user_name' => [ 'UserA', 'UserB' ],
+ ],
+ ],
+ ],
+ 'empty users' => [
+ [],
+ [ 'isCentralAuthAvailable' => false ],
+ [
+ 'tables' => 'user',
+ 'conds' => [ 0 ],
+ ],
+ ],
+ 'global users as string' => [
+ [ 'UserA', 'UserB' ],
+ [ 'isCentralAuthAvailable' => true ],
+ [
+ 'tables' => 'localuser',
+ 'conds' => [
+ 'lu_name' => [ 'UserA', 'UserB' ],
+ ],
+ ],
+ ],
+ ];
+ }
+}
diff --git a/CheckUser/tests/phpunit/SpecialCheckUserTest.php b/CheckUser/tests/phpunit/SpecialCheckUserTest.php
index 8f456014..2f012efa 100644
--- a/CheckUser/tests/phpunit/SpecialCheckUserTest.php
+++ b/CheckUser/tests/phpunit/SpecialCheckUserTest.php
@@ -1,5 +1,11 @@
<?php
+namespace MediaWiki\CheckUser\Tests;
+
+use MediaWikiIntegrationTestCase;
+use ReflectionClass;
+use SpecialCheckUser;
+
/**
* Test class for SpecialCheckUser class
*
@@ -8,9 +14,19 @@
*
* @covers SpecialCheckUser
*/
-class SpecialCheckUserTest extends MediaWikiTestCase {
+class SpecialCheckUserTest extends MediaWikiIntegrationTestCase {
+
+ /**
+ * @var int
+ */
+ private $lowerThanLimitIPv4;
- function __construct( $name = null, array $data = [], $dataName = '' ) {
+ /**
+ * @var int
+ */
+ private $lowerThanLimitIPv6;
+
+ public function __construct( $name = null, array $data = [], $dataName = '' ) {
parent::__construct( $name, $data, $dataName );
$this->tablesUsed = array_merge(
@@ -29,7 +45,7 @@ class SpecialCheckUserTest extends MediaWikiTestCase {
);
}
- protected function setUp() {
+ protected function setUp() : void {
parent::setUp();
$this->setMwGlobals( [
@@ -38,6 +54,10 @@ class SpecialCheckUserTest extends MediaWikiTestCase {
'IPv6' => 19,
]
] );
+
+ $CIDRLimit = \RequestContext::getMain()->getConfig()->get( 'CheckUserCIDRLimit' );
+ $this->lowerThanLimitIPv4 = $CIDRLimit['IPv4'] - 1;
+ $this->lowerThanLimitIPv6 = $CIDRLimit['IPv6'] - 1;
}
/**
@@ -76,8 +96,66 @@ class SpecialCheckUserTest extends MediaWikiTestCase {
[ 0 => 'cuc_ip_hex BETWEEN \'v6-00000000000000000000000E00000000\'' .
' AND \'v6-00000000000000000000000EFFFFFFFF\'' ],
],
- [ '0.17.184.5/15', false ],
- [ '2000::/16', false ],
+ [ "0.17.184.5/{$this->lowerThanLimitIPv4}", false ],
+ [ "2000::/{$this->lowerThanLimitIPv6}", false ],
+ ];
+ }
+
+ /**
+ * @covers SpecialCheckUser::isValidRange
+ * @dataProvider provideIsValidRange
+ */
+ public function testIsValidRange( $target, $expected ) {
+ $this->assertEquals(
+ $expected,
+ SpecialCheckUser::isValidRange( $target )
+ );
+ }
+
+ /**
+ * Test cases for SpecialCheckUser::isValid
+ * @return array
+ */
+ public function provideIsValidRange() {
+ return [
+ [ '212.35.31.121', true ],
+ [ '212.35.31.121/32', true ],
+ [ '::e:f:2001', true ],
+ [ '::e:f:2001/96', true ],
+ [ "0.17.184.5/{$this->lowerThanLimitIPv4}", false ],
+ [ "2000::/{$this->lowerThanLimitIPv6}", false ]
+ ];
+ }
+
+ /**
+ * @covers SpecialCheckUser::checkReason
+ * @dataProvider provideCheckReason
+ */
+ public function testCheckReason( $config, $reason, $expected ) {
+ $this->setMwGlobals( 'wgCheckUserForceSummary', $config );
+ $class = new ReflectionClass( SpecialCheckUser::class );
+ $method = $class->getMethod( 'checkReason' );
+ $method->setAccessible( true );
+ $instance = $class->newInstanceWithoutConstructor();
+ $property = $class->getProperty( 'reason' );
+ $property->setAccessible( true );
+ $property->setValue( $instance, $reason );
+ $this->assertEquals(
+ $expected,
+ $method->invoke( $instance )
+ );
+ }
+
+ /**
+ * Test cases for SpecialCheckUser::checkReason
+ * @return array
+ */
+ public function provideCheckReason() {
+ return [
+ [ false, '', true ],
+ [ false, 'Test Reason', true ],
+ [ true, '', false ],
+ [ true, 'Test Reason', true ]
];
}
}
diff --git a/CheckUser/tests/phpunit/TimelineServiceTest.php b/CheckUser/tests/phpunit/TimelineServiceTest.php
new file mode 100644
index 00000000..e2ea68fa
--- /dev/null
+++ b/CheckUser/tests/phpunit/TimelineServiceTest.php
@@ -0,0 +1,119 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use MediaWiki\CheckUser\TimelineService;
+use MediaWiki\CheckUser\UserManager;
+use MediaWikiIntegrationTestCase;
+use Wikimedia\IPUtils;
+use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\ILoadBalancer;
+
+/**
+ * @group CheckUser
+ * @covers \MediaWiki\CheckUser\TimelineService
+ */
+class TimelineServiceTest extends MediaWikiIntegrationTestCase {
+
+ /**
+ * @dataProvider provideGetQueryInfo
+ */
+ public function testGetQueryInfo( $targets, $start, $expected ) {
+ $db = $this->getMockBuilder( Database::class )
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $db->method( 'strencode' )
+ ->will( $this->returnArgument( 0 ) );
+
+ $loadBalancer = $this->createMock( ILoadBalancer::class );
+ $loadBalancer->method( 'getConnectionRef' )
+ ->willReturn( $db );
+
+ $userManager = $this->createMock( UserManager::class );
+ $userManager->method( 'idFromName' )
+ ->will( $this->returnValueMap( [
+ [ 'User1', 11111, ],
+ ] ) );
+
+ $timelineService = new TimelineService( $loadBalancer, $userManager );
+
+ $q = $timelineService->getQueryInfo( $targets, [], $start );
+
+ foreach ( $expected['targets'] as $target ) {
+ $this->assertStringContainsString( $target, $q['conds'][0] );
+ }
+
+ foreach ( $expected['conds'] as $cond ) {
+ $this->assertStringContainsString( $cond, $q['conds'][0] );
+ }
+
+ if ( $start === '' ) {
+ $this->assertCount( 1, $q['conds'] );
+ } else {
+ $this->assertCount( 2, $q['conds'] );
+ $this->assertStringContainsString( 'cuc_timestamp >=', $q['conds'][1] );
+ }
+ }
+
+ public function provideGetQueryInfo() {
+ $range = IPUtils::parseRange( '127.0.0.1/24' );
+ return [
+ 'Valid username' => [
+ [ 'User1' ],
+ '',
+ [
+ 'targets' => [ '11111' ],
+ 'conds' => [ 'cuc_user' ],
+ ],
+ ],
+ 'Valid username, with start' => [
+ [ 'User1' ],
+ '111',
+ [
+ 'targets' => [ '11111' ],
+ 'conds' => [ 'cuc_user' ],
+ ],
+ ],
+ 'Valid IP' => [
+ [ '1.2.3.4' ],
+ '',
+ [
+ 'targets' => [ IPUtils::toHex( '1.2.3.4' ) ],
+ 'conds' => [ 'cuc_ip_hex' ],
+ ],
+ ],
+ 'Multiple valid targets' => [
+ [ '1.2.3.4', 'User1' ],
+ '',
+ [
+ 'targets' => [ '11111', IPUtils::toHex( '1.2.3.4' ) ],
+ 'conds' => [ 'cuc_ip_hex', 'cuc_user' ],
+ ],
+ ],
+ 'Valid IP range' => [
+ [ '127.0.0.1/24', 'User1' ],
+ '',
+ [
+ 'targets' => [ '11111' ] + $range,
+ 'conds' => [ 'cuc_ip_hex >=', 'cuc_ip_hex <=', 'cuc_user' ],
+ ],
+ ],
+ 'Some valid targets' => [
+ [ 'User1', 'InvalidUser', '1.1..23', '::1' ],
+ '',
+ [
+ 'targets' => [ '11111', IPUtils::toHex( '::1' ) ],
+ 'conds' => [ 'cuc_user', 'cuc_ip_hex' ],
+ ],
+ ],
+ 'Invalid targets' => [
+ [ 'InvalidUser' ],
+ '',
+ [
+ 'targets' => [],
+ 'conds' => [ '0' ],
+ ],
+ ]
+ ];
+ }
+}
diff --git a/CheckUser/tests/phpunit/TokenManagerTest.php b/CheckUser/tests/phpunit/TokenManagerTest.php
new file mode 100644
index 00000000..a8ba2a55
--- /dev/null
+++ b/CheckUser/tests/phpunit/TokenManagerTest.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use Firebase\JWT\JWT;
+use MediaWiki\CheckUser\TokenManager;
+use MediaWiki\Session\SessionManager;
+use MediaWikiIntegrationTestCase;
+
+/**
+ * Test class for TokenManager class
+ *
+ * @group CheckUser
+ *
+ * @covers \MediaWiki\CheckUser\TokenManager
+ */
+class TokenManagerTest extends MediaWikiIntegrationTestCase {
+
+ public function setUp() : void {
+ parent::setUp();
+ \MWTimestamp::setFakeTime( 0 );
+ JWT::$timestamp = 60;
+ }
+
+ public function tearDown() : void {
+ parent::tearDown();
+ \MWTimestamp::setFakeTime( null );
+ JWT::$timestamp = null;
+ }
+
+ public function testEncodeDecode() {
+ $tokenManager = new TokenManager( 'abcdef' );
+ $targets = [ 'Example', '10.0.0.0/8' ];
+ $request = new \FauxRequest( [], false, [
+ 'CheckUserTokenKey' => base64_encode( 'test' ),
+ ] );
+
+ $encoded = $tokenManager->encode( $request->getSession(), [
+ 'targets' => $targets
+ ] );
+
+ $decoded = $tokenManager->decode( $request->getSession(), $encoded );
+ $this->assertIsArray( $decoded );
+ $this->assertCount( 1, $decoded );
+ $this->arrayHasKey( 'targets', $decoded );
+ $this->assertSame( $targets, $decoded['targets'] );
+ }
+
+ public function testDecodeSecretFailure() {
+ $this->expectExceptionMessage( 'Signature verification failed' );
+
+ $tokenManager = new TokenManager( 'abcdef' );
+ $session = SessionManager::singleton()->getEmptySession();
+ $encoded = $tokenManager->encode( $session, [] );
+
+ $tokenManager = new TokenManager( 'abcdef2' );
+ $decoded = $tokenManager->decode( $session, $encoded );
+ }
+
+ public function testDecodeSessionFailure() {
+ $this->expectExceptionMessage( 'Signature verification failed' );
+
+ $tokenManager = new TokenManager( 'abcdef' );
+ $encoded = $tokenManager->encode( SessionManager::singleton()->getEmptySession(), [] );
+ $decoded = $tokenManager->decode( SessionManager::singleton()->getEmptySession(), $encoded );
+ }
+}
diff --git a/CheckUser/tests/phpunit/TokenQueryManagerTest.php b/CheckUser/tests/phpunit/TokenQueryManagerTest.php
new file mode 100644
index 00000000..762daed0
--- /dev/null
+++ b/CheckUser/tests/phpunit/TokenQueryManagerTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace MediaWiki\CheckUser\Tests;
+
+use FauxRequest;
+use MediaWiki\CheckUser\TokenManager;
+use MediaWiki\CheckUser\TokenQueryManager;
+use MediaWikiIntegrationTestCase;
+
+/**
+ * Test class for TokenQueryManager class
+ *
+ * @group CheckUser
+ *
+ * @covers \MediaWiki\CheckUser\TokenQueryManager
+ */
+class TokenQueryManagerTest extends MediaWikiIntegrationTestCase {
+
+ /**
+ * @return MockObject|TokenManager
+ */
+ private function getMockTokenManager() {
+ return $this->getMockBuilder( TokenManager::class )
+ ->disableOriginalConstructor()->getMock();
+ }
+
+ public function testUpdateToken() {
+ $tokenManager = $this->getMockTokenManager();
+ $tokenQueryManager = $this->getMockBuilder( TokenQueryManager::class )
+ ->setConstructorArgs( [ $tokenManager ] )
+ ->setMethods( [ 'getDataFromRequest' ] )
+ ->getMock();
+
+ $tokenData = [ 'foo' => true, 'bar' => false, 'baz' => 'test' ];
+
+ $tokenQueryManager->method( 'getDataFromRequest' )->willReturn( $tokenData );
+ $tokenManager->expects( $this->once() )
+ ->method( 'encode' )
+ ->with( $this->anything(), [ 'bar' => true, 'baz' => 'test' ] );
+
+ $tokenQueryManager->updateToken( new FauxRequest(), [ 'foo' => null, 'bar' => true ] );
+ }
+
+ public function testGetDataFromRequest() {
+ $request = new FauxRequest( [ 'token' => 'token' ] );
+
+ $tokenManager = $this->getMockTokenManager();
+ $tokenManager->expects( $this->once() )->method( 'decode' )->with( $this->anything(), 'token' );
+
+ $tokenQueryManager = new TokenQueryManager( $tokenManager );
+ $tokenQueryManager->getDataFromRequest( $request );
+ }
+
+ public function testGetDataFromRequestWithNoToken() {
+ $request = new FauxRequest();
+
+ $tokenManager = $this->getMockTokenManager();
+ $tokenQueryManager = new TokenQueryManager( $tokenManager );
+ $data = $tokenQueryManager->getDataFromRequest( $request );
+
+ $this->assertSame( [], $data );
+ }
+
+ public function testGetDataFromRequestHandlesDecodeException() {
+ $tokenManager = $this->getMockTokenManager();
+ $tokenManager->method( 'decode' )->willThrowException( new \Exception() );
+
+ $tokenQueryManager = new TokenQueryManager( $tokenManager );
+ $request = new FauxRequest( [ 'token' => 'token' ] );
+ $data = $tokenQueryManager->getDataFromRequest( $request );
+
+ $this->assertSame( [], $data );
+ }
+}
diff --git a/CheckUser/version b/CheckUser/version
deleted file mode 100644
index ab46523d..00000000
--- a/CheckUser/version
+++ /dev/null
@@ -1,4 +0,0 @@
-CheckUser: REL1_32
-2018-10-17T02:10:33
-
-27be3bc